[CIFS] fix build error
[linux-2.6/verdex.git] / fs / cifs / cifssmb.c
blob4c344fe7a152da6a42333045c7403c134976ab8f
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2008
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * Contains the routines for constructing the SMB PDUs themselves
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsacl.h"
38 #include "cifsproto.h"
39 #include "cifs_unicode.h"
40 #include "cifs_debug.h"
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44 int index;
45 char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49 {LANMAN2_PROT, "\2LANMAN2.1"},
50 #endif /* weak password hashing for legacy clients */
51 {CIFS_PROT, "\2NT LM 0.12"},
52 {POSIX_PROT, "\2POSIX 2"},
53 {BAD_PROT, "\2"}
55 #else
56 static struct {
57 int index;
58 char *name;
59 } protocols[] = {
60 #ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
62 {LANMAN2_PROT, "\2LANMAN2.1"},
63 #endif /* weak password hashing for legacy clients */
64 {CIFS_PROT, "\2NT LM 0.12"},
65 {BAD_PROT, "\2"}
67 #endif
69 /* define the number of elements in the cifs dialect array */
70 #ifdef CONFIG_CIFS_POSIX
71 #ifdef CONFIG_CIFS_WEAK_PW_HASH
72 #define CIFS_NUM_PROT 4
73 #else
74 #define CIFS_NUM_PROT 2
75 #endif /* CIFS_WEAK_PW_HASH */
76 #else /* not posix */
77 #ifdef CONFIG_CIFS_WEAK_PW_HASH
78 #define CIFS_NUM_PROT 3
79 #else
80 #define CIFS_NUM_PROT 1
81 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
82 #endif /* CIFS_POSIX */
84 /* Allocates buffer into dst and copies smb string from src to it.
85 * caller is responsible for freeing dst if function returned 0.
86 * returns:
87 * on success - 0
88 * on failure - errno
90 static int
91 cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
92 const bool is_unicode, const struct nls_table *nls_codepage)
94 int plen;
96 if (is_unicode) {
97 plen = UniStrnlen((wchar_t *)src, maxlen);
98 *dst = kmalloc(plen + 2, GFP_KERNEL);
99 if (!*dst)
100 goto cifs_strncpy_to_host_ErrExit;
101 cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
102 } else {
103 plen = strnlen(src, maxlen);
104 *dst = kmalloc(plen + 2, GFP_KERNEL);
105 if (!*dst)
106 goto cifs_strncpy_to_host_ErrExit;
107 strncpy(*dst, src, plen);
109 (*dst)[plen] = 0;
110 (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
111 return 0;
113 cifs_strncpy_to_host_ErrExit:
114 cERROR(1, ("Failed to allocate buffer for string\n"));
115 return -ENOMEM;
119 /* Mark as invalid, all open files on tree connections since they
120 were closed when session to server was lost */
121 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
123 struct cifsFileInfo *open_file = NULL;
124 struct list_head *tmp;
125 struct list_head *tmp1;
127 /* list all files open on tree connection and mark them invalid */
128 write_lock(&GlobalSMBSeslock);
129 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
130 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
131 open_file->invalidHandle = true;
133 write_unlock(&GlobalSMBSeslock);
134 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
135 to this tcon */
138 /* Allocate and return pointer to an SMB request buffer, and set basic
139 SMB information in the SMB header. If the return code is zero, this
140 function must have filled in request_buf pointer */
141 static int
142 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
143 void **request_buf)
145 int rc = 0;
147 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
148 check for tcp and smb session status done differently
149 for those three - in the calling routine */
150 if (tcon) {
151 if (tcon->tidStatus == CifsExiting) {
152 /* only tree disconnect, open, and write,
153 (and ulogoff which does not have tcon)
154 are allowed as we start force umount */
155 if ((smb_command != SMB_COM_WRITE_ANDX) &&
156 (smb_command != SMB_COM_OPEN_ANDX) &&
157 (smb_command != SMB_COM_TREE_DISCONNECT)) {
158 cFYI(1, ("can not send cmd %d while umounting",
159 smb_command));
160 return -ENODEV;
163 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
164 (tcon->ses->server)) {
165 struct nls_table *nls_codepage;
166 /* Give Demultiplex thread up to 10 seconds to
167 reconnect, should be greater than cifs socket
168 timeout which is 7 seconds */
169 while (tcon->ses->server->tcpStatus ==
170 CifsNeedReconnect) {
171 wait_event_interruptible_timeout(tcon->ses->server->response_q,
172 (tcon->ses->server->tcpStatus ==
173 CifsGood), 10 * HZ);
174 if (tcon->ses->server->tcpStatus ==
175 CifsNeedReconnect) {
176 /* on "soft" mounts we wait once */
177 if (!tcon->retry ||
178 (tcon->ses->status == CifsExiting)) {
179 cFYI(1, ("gave up waiting on "
180 "reconnect in smb_init"));
181 return -EHOSTDOWN;
182 } /* else "hard" mount - keep retrying
183 until process is killed or server
184 comes back on-line */
185 } else /* TCP session is reestablished now */
186 break;
189 nls_codepage = load_nls_default();
190 /* need to prevent multiple threads trying to
191 simultaneously reconnect the same SMB session */
192 down(&tcon->ses->sesSem);
193 if (tcon->ses->need_reconnect)
194 rc = cifs_setup_session(0, tcon->ses,
195 nls_codepage);
196 if (!rc && (tcon->need_reconnect)) {
197 mark_open_files_invalid(tcon);
198 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
199 tcon, nls_codepage);
200 up(&tcon->ses->sesSem);
201 /* BB FIXME add code to check if wsize needs
202 update due to negotiated smb buffer size
203 shrinking */
204 if (rc == 0) {
205 atomic_inc(&tconInfoReconnectCount);
206 /* tell server Unix caps we support */
207 if (tcon->ses->capabilities & CAP_UNIX)
208 reset_cifs_unix_caps(
209 0 /* no xid */,
210 tcon,
211 NULL /* we do not know sb */,
212 NULL /* no vol info */);
215 cFYI(1, ("reconnect tcon rc = %d", rc));
216 /* Removed call to reopen open files here.
217 It is safer (and faster) to reopen files
218 one at a time as needed in read and write */
220 /* Check if handle based operation so we
221 know whether we can continue or not without
222 returning to caller to reset file handle */
223 switch (smb_command) {
224 case SMB_COM_READ_ANDX:
225 case SMB_COM_WRITE_ANDX:
226 case SMB_COM_CLOSE:
227 case SMB_COM_FIND_CLOSE2:
228 case SMB_COM_LOCKING_ANDX: {
229 unload_nls(nls_codepage);
230 return -EAGAIN;
233 } else {
234 up(&tcon->ses->sesSem);
236 unload_nls(nls_codepage);
238 } else {
239 return -EIO;
242 if (rc)
243 return rc;
245 *request_buf = cifs_small_buf_get();
246 if (*request_buf == NULL) {
247 /* BB should we add a retry in here if not a writepage? */
248 return -ENOMEM;
251 header_assemble((struct smb_hdr *) *request_buf, smb_command,
252 tcon, wct);
254 if (tcon != NULL)
255 cifs_stats_inc(&tcon->num_smbs_sent);
257 return rc;
261 small_smb_init_no_tc(const int smb_command, const int wct,
262 struct cifsSesInfo *ses, void **request_buf)
264 int rc;
265 struct smb_hdr *buffer;
267 rc = small_smb_init(smb_command, wct, NULL, request_buf);
268 if (rc)
269 return rc;
271 buffer = (struct smb_hdr *)*request_buf;
272 buffer->Mid = GetNextMid(ses->server);
273 if (ses->capabilities & CAP_UNICODE)
274 buffer->Flags2 |= SMBFLG2_UNICODE;
275 if (ses->capabilities & CAP_STATUS32)
276 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
278 /* uid, tid can stay at zero as set in header assemble */
280 /* BB add support for turning on the signing when
281 this function is used after 1st of session setup requests */
283 return rc;
286 /* If the return code is zero, this function must fill in request_buf pointer */
287 static int
288 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
289 void **request_buf /* returned */ ,
290 void **response_buf /* returned */ )
292 int rc = 0;
294 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
295 check for tcp and smb session status done differently
296 for those three - in the calling routine */
297 if (tcon) {
298 if (tcon->tidStatus == CifsExiting) {
299 /* only tree disconnect, open, and write,
300 (and ulogoff which does not have tcon)
301 are allowed as we start force umount */
302 if ((smb_command != SMB_COM_WRITE_ANDX) &&
303 (smb_command != SMB_COM_OPEN_ANDX) &&
304 (smb_command != SMB_COM_TREE_DISCONNECT)) {
305 cFYI(1, ("can not send cmd %d while umounting",
306 smb_command));
307 return -ENODEV;
311 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
312 (tcon->ses->server)) {
313 struct nls_table *nls_codepage;
314 /* Give Demultiplex thread up to 10 seconds to
315 reconnect, should be greater than cifs socket
316 timeout which is 7 seconds */
317 while (tcon->ses->server->tcpStatus ==
318 CifsNeedReconnect) {
319 wait_event_interruptible_timeout(tcon->ses->server->response_q,
320 (tcon->ses->server->tcpStatus ==
321 CifsGood), 10 * HZ);
322 if (tcon->ses->server->tcpStatus ==
323 CifsNeedReconnect) {
324 /* on "soft" mounts we wait once */
325 if (!tcon->retry ||
326 (tcon->ses->status == CifsExiting)) {
327 cFYI(1, ("gave up waiting on "
328 "reconnect in smb_init"));
329 return -EHOSTDOWN;
330 } /* else "hard" mount - keep retrying
331 until process is killed or server
332 comes on-line */
333 } else /* TCP session is reestablished now */
334 break;
336 nls_codepage = load_nls_default();
337 /* need to prevent multiple threads trying to
338 simultaneously reconnect the same SMB session */
339 down(&tcon->ses->sesSem);
340 if (tcon->ses->need_reconnect)
341 rc = cifs_setup_session(0, tcon->ses,
342 nls_codepage);
343 if (!rc && (tcon->need_reconnect)) {
344 mark_open_files_invalid(tcon);
345 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
346 tcon, nls_codepage);
347 up(&tcon->ses->sesSem);
348 /* BB FIXME add code to check if wsize needs
349 update due to negotiated smb buffer size
350 shrinking */
351 if (rc == 0) {
352 atomic_inc(&tconInfoReconnectCount);
353 /* tell server Unix caps we support */
354 if (tcon->ses->capabilities & CAP_UNIX)
355 reset_cifs_unix_caps(
356 0 /* no xid */,
357 tcon,
358 NULL /* do not know sb */,
359 NULL /* no vol info */);
362 cFYI(1, ("reconnect tcon rc = %d", rc));
363 /* Removed call to reopen open files here.
364 It is safer (and faster) to reopen files
365 one at a time as needed in read and write */
367 /* Check if handle based operation so we
368 know whether we can continue or not without
369 returning to caller to reset file handle */
370 switch (smb_command) {
371 case SMB_COM_READ_ANDX:
372 case SMB_COM_WRITE_ANDX:
373 case SMB_COM_CLOSE:
374 case SMB_COM_FIND_CLOSE2:
375 case SMB_COM_LOCKING_ANDX: {
376 unload_nls(nls_codepage);
377 return -EAGAIN;
380 } else {
381 up(&tcon->ses->sesSem);
383 unload_nls(nls_codepage);
385 } else {
386 return -EIO;
389 if (rc)
390 return rc;
392 *request_buf = cifs_buf_get();
393 if (*request_buf == NULL) {
394 /* BB should we add a retry in here if not a writepage? */
395 return -ENOMEM;
397 /* Although the original thought was we needed the response buf for */
398 /* potential retries of smb operations it turns out we can determine */
399 /* from the mid flags when the request buffer can be resent without */
400 /* having to use a second distinct buffer for the response */
401 if (response_buf)
402 *response_buf = *request_buf;
404 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
405 wct);
407 if (tcon != NULL)
408 cifs_stats_inc(&tcon->num_smbs_sent);
410 return rc;
413 static int validate_t2(struct smb_t2_rsp *pSMB)
415 int rc = -EINVAL;
416 int total_size;
417 char *pBCC;
419 /* check for plausible wct, bcc and t2 data and parm sizes */
420 /* check for parm and data offset going beyond end of smb */
421 if (pSMB->hdr.WordCount >= 10) {
422 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
423 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
424 /* check that bcc is at least as big as parms + data */
425 /* check that bcc is less than negotiated smb buffer */
426 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
427 if (total_size < 512) {
428 total_size +=
429 le16_to_cpu(pSMB->t2_rsp.DataCount);
430 /* BCC le converted in SendReceive */
431 pBCC = (pSMB->hdr.WordCount * 2) +
432 sizeof(struct smb_hdr) +
433 (char *)pSMB;
434 if ((total_size <= (*(u16 *)pBCC)) &&
435 (total_size <
436 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
437 return 0;
442 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
443 sizeof(struct smb_t2_rsp) + 16);
444 return rc;
447 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
449 NEGOTIATE_REQ *pSMB;
450 NEGOTIATE_RSP *pSMBr;
451 int rc = 0;
452 int bytes_returned;
453 int i;
454 struct TCP_Server_Info *server;
455 u16 count;
456 unsigned int secFlags;
457 u16 dialect;
459 if (ses->server)
460 server = ses->server;
461 else {
462 rc = -EIO;
463 return rc;
465 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
466 (void **) &pSMB, (void **) &pSMBr);
467 if (rc)
468 return rc;
470 /* if any of auth flags (ie not sign or seal) are overriden use them */
471 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
472 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
473 else /* if override flags set only sign/seal OR them with global auth */
474 secFlags = extended_security | ses->overrideSecFlg;
476 cFYI(1, ("secFlags 0x%x", secFlags));
478 pSMB->hdr.Mid = GetNextMid(server);
479 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
481 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
482 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
483 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
484 cFYI(1, ("Kerberos only mechanism, enable extended security"));
485 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
488 count = 0;
489 for (i = 0; i < CIFS_NUM_PROT; i++) {
490 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
491 count += strlen(protocols[i].name) + 1;
492 /* null at end of source and target buffers anyway */
494 pSMB->hdr.smb_buf_length += count;
495 pSMB->ByteCount = cpu_to_le16(count);
497 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
499 if (rc != 0)
500 goto neg_err_exit;
502 dialect = le16_to_cpu(pSMBr->DialectIndex);
503 cFYI(1, ("Dialect: %d", dialect));
504 /* Check wct = 1 error case */
505 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
506 /* core returns wct = 1, but we do not ask for core - otherwise
507 small wct just comes when dialect index is -1 indicating we
508 could not negotiate a common dialect */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
511 #ifdef CONFIG_CIFS_WEAK_PW_HASH
512 } else if ((pSMBr->hdr.WordCount == 13)
513 && ((dialect == LANMAN_PROT)
514 || (dialect == LANMAN2_PROT))) {
515 __s16 tmp;
516 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
518 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
519 (secFlags & CIFSSEC_MAY_PLNTXT))
520 server->secType = LANMAN;
521 else {
522 cERROR(1, ("mount failed weak security disabled"
523 " in /proc/fs/cifs/SecurityFlags"));
524 rc = -EOPNOTSUPP;
525 goto neg_err_exit;
527 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
528 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
529 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
530 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
531 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
532 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
533 /* even though we do not use raw we might as well set this
534 accurately, in case we ever find a need for it */
535 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
536 server->max_rw = 0xFF00;
537 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
538 } else {
539 server->max_rw = 0;/* do not need to use raw anyway */
540 server->capabilities = CAP_MPX_MODE;
542 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
543 if (tmp == -1) {
544 /* OS/2 often does not set timezone therefore
545 * we must use server time to calc time zone.
546 * Could deviate slightly from the right zone.
547 * Smallest defined timezone difference is 15 minutes
548 * (i.e. Nepal). Rounding up/down is done to match
549 * this requirement.
551 int val, seconds, remain, result;
552 struct timespec ts, utc;
553 utc = CURRENT_TIME;
554 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
555 le16_to_cpu(rsp->SrvTime.Time));
556 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
557 (int)ts.tv_sec, (int)utc.tv_sec,
558 (int)(utc.tv_sec - ts.tv_sec)));
559 val = (int)(utc.tv_sec - ts.tv_sec);
560 seconds = abs(val);
561 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
562 remain = seconds % MIN_TZ_ADJ;
563 if (remain >= (MIN_TZ_ADJ / 2))
564 result += MIN_TZ_ADJ;
565 if (val < 0)
566 result = -result;
567 server->timeAdj = result;
568 } else {
569 server->timeAdj = (int)tmp;
570 server->timeAdj *= 60; /* also in seconds */
572 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
575 /* BB get server time for time conversions and add
576 code to use it and timezone since this is not UTC */
578 if (rsp->EncryptionKeyLength ==
579 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
580 memcpy(server->cryptKey, rsp->EncryptionKey,
581 CIFS_CRYPTO_KEY_SIZE);
582 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
583 rc = -EIO; /* need cryptkey unless plain text */
584 goto neg_err_exit;
587 cFYI(1, ("LANMAN negotiated"));
588 /* we will not end up setting signing flags - as no signing
589 was in LANMAN and server did not return the flags on */
590 goto signing_check;
591 #else /* weak security disabled */
592 } else if (pSMBr->hdr.WordCount == 13) {
593 cERROR(1, ("mount failed, cifs module not built "
594 "with CIFS_WEAK_PW_HASH support"));
595 rc = -EOPNOTSUPP;
596 #endif /* WEAK_PW_HASH */
597 goto neg_err_exit;
598 } else if (pSMBr->hdr.WordCount != 17) {
599 /* unknown wct */
600 rc = -EOPNOTSUPP;
601 goto neg_err_exit;
603 /* else wct == 17 NTLM */
604 server->secMode = pSMBr->SecurityMode;
605 if ((server->secMode & SECMODE_USER) == 0)
606 cFYI(1, ("share mode security"));
608 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
609 #ifdef CONFIG_CIFS_WEAK_PW_HASH
610 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
611 #endif /* CIFS_WEAK_PW_HASH */
612 cERROR(1, ("Server requests plain text password"
613 " but client support disabled"));
615 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
616 server->secType = NTLMv2;
617 else if (secFlags & CIFSSEC_MAY_NTLM)
618 server->secType = NTLM;
619 else if (secFlags & CIFSSEC_MAY_NTLMV2)
620 server->secType = NTLMv2;
621 else if (secFlags & CIFSSEC_MAY_KRB5)
622 server->secType = Kerberos;
623 else if (secFlags & CIFSSEC_MAY_LANMAN)
624 server->secType = LANMAN;
625 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
626 else if (secFlags & CIFSSEC_MAY_PLNTXT)
627 server->secType = ??
628 #endif */
629 else {
630 rc = -EOPNOTSUPP;
631 cERROR(1, ("Invalid security type"));
632 goto neg_err_exit;
634 /* else ... any others ...? */
636 /* one byte, so no need to convert this or EncryptionKeyLen from
637 little endian */
638 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
639 /* probably no need to store and check maxvcs */
640 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
641 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
642 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
643 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
644 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
645 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
646 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
647 server->timeAdj *= 60;
648 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
649 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
650 CIFS_CRYPTO_KEY_SIZE);
651 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
652 && (pSMBr->EncryptionKeyLength == 0)) {
653 /* decode security blob */
654 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
655 rc = -EIO; /* no crypt key only if plain text pwd */
656 goto neg_err_exit;
659 /* BB might be helpful to save off the domain of server here */
661 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
662 (server->capabilities & CAP_EXTENDED_SECURITY)) {
663 count = pSMBr->ByteCount;
664 if (count < 16) {
665 rc = -EIO;
666 goto neg_err_exit;
668 read_lock(&cifs_tcp_ses_lock);
669 if (server->srv_count > 1) {
670 read_unlock(&cifs_tcp_ses_lock);
671 if (memcmp(server->server_GUID,
672 pSMBr->u.extended_response.
673 GUID, 16) != 0) {
674 cFYI(1, ("server UID changed"));
675 memcpy(server->server_GUID,
676 pSMBr->u.extended_response.GUID,
677 16);
679 } else {
680 read_unlock(&cifs_tcp_ses_lock);
681 memcpy(server->server_GUID,
682 pSMBr->u.extended_response.GUID, 16);
685 if (count == 16) {
686 server->secType = RawNTLMSSP;
687 } else {
688 rc = decode_negTokenInit(pSMBr->u.extended_response.
689 SecurityBlob,
690 count - 16,
691 &server->secType);
692 if (rc == 1)
693 rc = 0;
694 else
695 rc = -EINVAL;
697 } else
698 server->capabilities &= ~CAP_EXTENDED_SECURITY;
700 #ifdef CONFIG_CIFS_WEAK_PW_HASH
701 signing_check:
702 #endif
703 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
704 /* MUST_SIGN already includes the MAY_SIGN FLAG
705 so if this is zero it means that signing is disabled */
706 cFYI(1, ("Signing disabled"));
707 if (server->secMode & SECMODE_SIGN_REQUIRED) {
708 cERROR(1, ("Server requires "
709 "packet signing to be enabled in "
710 "/proc/fs/cifs/SecurityFlags."));
711 rc = -EOPNOTSUPP;
713 server->secMode &=
714 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
715 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
716 /* signing required */
717 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
718 if ((server->secMode &
719 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
720 cERROR(1,
721 ("signing required but server lacks support"));
722 rc = -EOPNOTSUPP;
723 } else
724 server->secMode |= SECMODE_SIGN_REQUIRED;
725 } else {
726 /* signing optional ie CIFSSEC_MAY_SIGN */
727 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
728 server->secMode &=
729 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
732 neg_err_exit:
733 cifs_buf_release(pSMB);
735 cFYI(1, ("negprot rc %d", rc));
736 return rc;
740 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
742 struct smb_hdr *smb_buffer;
743 int rc = 0;
745 cFYI(1, ("In tree disconnect"));
747 /* BB: do we need to check this? These should never be NULL. */
748 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
749 return -EIO;
752 * No need to return error on this operation if tid invalidated and
753 * closed on server already e.g. due to tcp session crashing. Also,
754 * the tcon is no longer on the list, so no need to take lock before
755 * checking this.
757 if (tcon->need_reconnect)
758 return 0;
760 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
761 (void **)&smb_buffer);
762 if (rc)
763 return rc;
765 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
766 if (rc)
767 cFYI(1, ("Tree disconnect failed %d", rc));
769 /* No need to return error on this operation if tid invalidated and
770 closed on server already e.g. due to tcp session crashing */
771 if (rc == -EAGAIN)
772 rc = 0;
774 return rc;
778 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
780 LOGOFF_ANDX_REQ *pSMB;
781 int rc = 0;
783 cFYI(1, ("In SMBLogoff for session disconnect"));
786 * BB: do we need to check validity of ses and server? They should
787 * always be valid since we have an active reference. If not, that
788 * should probably be a BUG()
790 if (!ses || !ses->server)
791 return -EIO;
793 down(&ses->sesSem);
794 if (ses->need_reconnect)
795 goto session_already_dead; /* no need to send SMBlogoff if uid
796 already closed due to reconnect */
797 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
798 if (rc) {
799 up(&ses->sesSem);
800 return rc;
803 pSMB->hdr.Mid = GetNextMid(ses->server);
805 if (ses->server->secMode &
806 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
807 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
809 pSMB->hdr.Uid = ses->Suid;
811 pSMB->AndXCommand = 0xFF;
812 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
813 session_already_dead:
814 up(&ses->sesSem);
816 /* if session dead then we do not need to do ulogoff,
817 since server closed smb session, no sense reporting
818 error */
819 if (rc == -EAGAIN)
820 rc = 0;
821 return rc;
825 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
826 __u16 type, const struct nls_table *nls_codepage, int remap)
828 TRANSACTION2_SPI_REQ *pSMB = NULL;
829 TRANSACTION2_SPI_RSP *pSMBr = NULL;
830 struct unlink_psx_rq *pRqD;
831 int name_len;
832 int rc = 0;
833 int bytes_returned = 0;
834 __u16 params, param_offset, offset, byte_count;
836 cFYI(1, ("In POSIX delete"));
837 PsxDelete:
838 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
839 (void **) &pSMBr);
840 if (rc)
841 return rc;
843 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
844 name_len =
845 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
846 PATH_MAX, nls_codepage, remap);
847 name_len++; /* trailing null */
848 name_len *= 2;
849 } else { /* BB add path length overrun check */
850 name_len = strnlen(fileName, PATH_MAX);
851 name_len++; /* trailing null */
852 strncpy(pSMB->FileName, fileName, name_len);
855 params = 6 + name_len;
856 pSMB->MaxParameterCount = cpu_to_le16(2);
857 pSMB->MaxDataCount = 0; /* BB double check this with jra */
858 pSMB->MaxSetupCount = 0;
859 pSMB->Reserved = 0;
860 pSMB->Flags = 0;
861 pSMB->Timeout = 0;
862 pSMB->Reserved2 = 0;
863 param_offset = offsetof(struct smb_com_transaction2_spi_req,
864 InformationLevel) - 4;
865 offset = param_offset + params;
867 /* Setup pointer to Request Data (inode type) */
868 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
869 pRqD->type = cpu_to_le16(type);
870 pSMB->ParameterOffset = cpu_to_le16(param_offset);
871 pSMB->DataOffset = cpu_to_le16(offset);
872 pSMB->SetupCount = 1;
873 pSMB->Reserved3 = 0;
874 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
875 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
877 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
878 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
879 pSMB->ParameterCount = cpu_to_le16(params);
880 pSMB->TotalParameterCount = pSMB->ParameterCount;
881 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
882 pSMB->Reserved4 = 0;
883 pSMB->hdr.smb_buf_length += byte_count;
884 pSMB->ByteCount = cpu_to_le16(byte_count);
885 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
886 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
887 if (rc)
888 cFYI(1, ("Posix delete returned %d", rc));
889 cifs_buf_release(pSMB);
891 cifs_stats_inc(&tcon->num_deletes);
893 if (rc == -EAGAIN)
894 goto PsxDelete;
896 return rc;
900 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
901 const struct nls_table *nls_codepage, int remap)
903 DELETE_FILE_REQ *pSMB = NULL;
904 DELETE_FILE_RSP *pSMBr = NULL;
905 int rc = 0;
906 int bytes_returned;
907 int name_len;
909 DelFileRetry:
910 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
911 (void **) &pSMBr);
912 if (rc)
913 return rc;
915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
916 name_len =
917 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
918 PATH_MAX, nls_codepage, remap);
919 name_len++; /* trailing null */
920 name_len *= 2;
921 } else { /* BB improve check for buffer overruns BB */
922 name_len = strnlen(fileName, PATH_MAX);
923 name_len++; /* trailing null */
924 strncpy(pSMB->fileName, fileName, name_len);
926 pSMB->SearchAttributes =
927 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
928 pSMB->BufferFormat = 0x04;
929 pSMB->hdr.smb_buf_length += name_len + 1;
930 pSMB->ByteCount = cpu_to_le16(name_len + 1);
931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
933 cifs_stats_inc(&tcon->num_deletes);
934 if (rc)
935 cFYI(1, ("Error in RMFile = %d", rc));
937 cifs_buf_release(pSMB);
938 if (rc == -EAGAIN)
939 goto DelFileRetry;
941 return rc;
945 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
946 const struct nls_table *nls_codepage, int remap)
948 DELETE_DIRECTORY_REQ *pSMB = NULL;
949 DELETE_DIRECTORY_RSP *pSMBr = NULL;
950 int rc = 0;
951 int bytes_returned;
952 int name_len;
954 cFYI(1, ("In CIFSSMBRmDir"));
955 RmDirRetry:
956 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
957 (void **) &pSMBr);
958 if (rc)
959 return rc;
961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
962 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
963 PATH_MAX, nls_codepage, remap);
964 name_len++; /* trailing null */
965 name_len *= 2;
966 } else { /* BB improve check for buffer overruns BB */
967 name_len = strnlen(dirName, PATH_MAX);
968 name_len++; /* trailing null */
969 strncpy(pSMB->DirName, dirName, name_len);
972 pSMB->BufferFormat = 0x04;
973 pSMB->hdr.smb_buf_length += name_len + 1;
974 pSMB->ByteCount = cpu_to_le16(name_len + 1);
975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
977 cifs_stats_inc(&tcon->num_rmdirs);
978 if (rc)
979 cFYI(1, ("Error in RMDir = %d", rc));
981 cifs_buf_release(pSMB);
982 if (rc == -EAGAIN)
983 goto RmDirRetry;
984 return rc;
988 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
989 const char *name, const struct nls_table *nls_codepage, int remap)
991 int rc = 0;
992 CREATE_DIRECTORY_REQ *pSMB = NULL;
993 CREATE_DIRECTORY_RSP *pSMBr = NULL;
994 int bytes_returned;
995 int name_len;
997 cFYI(1, ("In CIFSSMBMkDir"));
998 MkDirRetry:
999 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1000 (void **) &pSMBr);
1001 if (rc)
1002 return rc;
1004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1005 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
1006 PATH_MAX, nls_codepage, remap);
1007 name_len++; /* trailing null */
1008 name_len *= 2;
1009 } else { /* BB improve check for buffer overruns BB */
1010 name_len = strnlen(name, PATH_MAX);
1011 name_len++; /* trailing null */
1012 strncpy(pSMB->DirName, name, name_len);
1015 pSMB->BufferFormat = 0x04;
1016 pSMB->hdr.smb_buf_length += name_len + 1;
1017 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1020 cifs_stats_inc(&tcon->num_mkdirs);
1021 if (rc)
1022 cFYI(1, ("Error in Mkdir = %d", rc));
1024 cifs_buf_release(pSMB);
1025 if (rc == -EAGAIN)
1026 goto MkDirRetry;
1027 return rc;
1031 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1032 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1033 __u32 *pOplock, const char *name,
1034 const struct nls_table *nls_codepage, int remap)
1036 TRANSACTION2_SPI_REQ *pSMB = NULL;
1037 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1038 int name_len;
1039 int rc = 0;
1040 int bytes_returned = 0;
1041 __u16 params, param_offset, offset, byte_count, count;
1042 OPEN_PSX_REQ *pdata;
1043 OPEN_PSX_RSP *psx_rsp;
1045 cFYI(1, ("In POSIX Create"));
1046 PsxCreat:
1047 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1048 (void **) &pSMBr);
1049 if (rc)
1050 return rc;
1052 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1053 name_len =
1054 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1055 PATH_MAX, nls_codepage, remap);
1056 name_len++; /* trailing null */
1057 name_len *= 2;
1058 } else { /* BB improve the check for buffer overruns BB */
1059 name_len = strnlen(name, PATH_MAX);
1060 name_len++; /* trailing null */
1061 strncpy(pSMB->FileName, name, name_len);
1064 params = 6 + name_len;
1065 count = sizeof(OPEN_PSX_REQ);
1066 pSMB->MaxParameterCount = cpu_to_le16(2);
1067 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1068 pSMB->MaxSetupCount = 0;
1069 pSMB->Reserved = 0;
1070 pSMB->Flags = 0;
1071 pSMB->Timeout = 0;
1072 pSMB->Reserved2 = 0;
1073 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1074 InformationLevel) - 4;
1075 offset = param_offset + params;
1076 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1077 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1078 pdata->Permissions = cpu_to_le64(mode);
1079 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1080 pdata->OpenFlags = cpu_to_le32(*pOplock);
1081 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1082 pSMB->DataOffset = cpu_to_le16(offset);
1083 pSMB->SetupCount = 1;
1084 pSMB->Reserved3 = 0;
1085 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1086 byte_count = 3 /* pad */ + params + count;
1088 pSMB->DataCount = cpu_to_le16(count);
1089 pSMB->ParameterCount = cpu_to_le16(params);
1090 pSMB->TotalDataCount = pSMB->DataCount;
1091 pSMB->TotalParameterCount = pSMB->ParameterCount;
1092 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1093 pSMB->Reserved4 = 0;
1094 pSMB->hdr.smb_buf_length += byte_count;
1095 pSMB->ByteCount = cpu_to_le16(byte_count);
1096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1098 if (rc) {
1099 cFYI(1, ("Posix create returned %d", rc));
1100 goto psx_create_err;
1103 cFYI(1, ("copying inode info"));
1104 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1106 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1107 rc = -EIO; /* bad smb */
1108 goto psx_create_err;
1111 /* copy return information to pRetData */
1112 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1113 + le16_to_cpu(pSMBr->t2.DataOffset));
1115 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1116 if (netfid)
1117 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1118 /* Let caller know file was created so we can set the mode. */
1119 /* Do we care about the CreateAction in any other cases? */
1120 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1121 *pOplock |= CIFS_CREATE_ACTION;
1122 /* check to make sure response data is there */
1123 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1124 pRetData->Type = cpu_to_le32(-1); /* unknown */
1125 cFYI(DBG2, ("unknown type"));
1126 } else {
1127 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1128 + sizeof(FILE_UNIX_BASIC_INFO)) {
1129 cERROR(1, ("Open response data too small"));
1130 pRetData->Type = cpu_to_le32(-1);
1131 goto psx_create_err;
1133 memcpy((char *) pRetData,
1134 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1135 sizeof(FILE_UNIX_BASIC_INFO));
1138 psx_create_err:
1139 cifs_buf_release(pSMB);
1141 cifs_stats_inc(&tcon->num_mkdirs);
1143 if (rc == -EAGAIN)
1144 goto PsxCreat;
1146 return rc;
1149 static __u16 convert_disposition(int disposition)
1151 __u16 ofun = 0;
1153 switch (disposition) {
1154 case FILE_SUPERSEDE:
1155 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1156 break;
1157 case FILE_OPEN:
1158 ofun = SMBOPEN_OAPPEND;
1159 break;
1160 case FILE_CREATE:
1161 ofun = SMBOPEN_OCREATE;
1162 break;
1163 case FILE_OPEN_IF:
1164 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1165 break;
1166 case FILE_OVERWRITE:
1167 ofun = SMBOPEN_OTRUNC;
1168 break;
1169 case FILE_OVERWRITE_IF:
1170 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1171 break;
1172 default:
1173 cFYI(1, ("unknown disposition %d", disposition));
1174 ofun = SMBOPEN_OAPPEND; /* regular open */
1176 return ofun;
1179 static int
1180 access_flags_to_smbopen_mode(const int access_flags)
1182 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1184 if (masked_flags == GENERIC_READ)
1185 return SMBOPEN_READ;
1186 else if (masked_flags == GENERIC_WRITE)
1187 return SMBOPEN_WRITE;
1189 /* just go for read/write */
1190 return SMBOPEN_READWRITE;
1194 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1195 const char *fileName, const int openDisposition,
1196 const int access_flags, const int create_options, __u16 *netfid,
1197 int *pOplock, FILE_ALL_INFO *pfile_info,
1198 const struct nls_table *nls_codepage, int remap)
1200 int rc = -EACCES;
1201 OPENX_REQ *pSMB = NULL;
1202 OPENX_RSP *pSMBr = NULL;
1203 int bytes_returned;
1204 int name_len;
1205 __u16 count;
1207 OldOpenRetry:
1208 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1209 (void **) &pSMBr);
1210 if (rc)
1211 return rc;
1213 pSMB->AndXCommand = 0xFF; /* none */
1215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1216 count = 1; /* account for one byte pad to word boundary */
1217 name_len =
1218 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1219 fileName, PATH_MAX, nls_codepage, remap);
1220 name_len++; /* trailing null */
1221 name_len *= 2;
1222 } else { /* BB improve check for buffer overruns BB */
1223 count = 0; /* no pad */
1224 name_len = strnlen(fileName, PATH_MAX);
1225 name_len++; /* trailing null */
1226 strncpy(pSMB->fileName, fileName, name_len);
1228 if (*pOplock & REQ_OPLOCK)
1229 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1230 else if (*pOplock & REQ_BATCHOPLOCK)
1231 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1233 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1234 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1235 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1236 /* set file as system file if special file such
1237 as fifo and server expecting SFU style and
1238 no Unix extensions */
1240 if (create_options & CREATE_OPTION_SPECIAL)
1241 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1242 else /* BB FIXME BB */
1243 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1245 if (create_options & CREATE_OPTION_READONLY)
1246 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1248 /* BB FIXME BB */
1249 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1250 CREATE_OPTIONS_MASK); */
1251 /* BB FIXME END BB */
1253 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1254 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1255 count += name_len;
1256 pSMB->hdr.smb_buf_length += count;
1258 pSMB->ByteCount = cpu_to_le16(count);
1259 /* long_op set to 1 to allow for oplock break timeouts */
1260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1261 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1262 cifs_stats_inc(&tcon->num_opens);
1263 if (rc) {
1264 cFYI(1, ("Error in Open = %d", rc));
1265 } else {
1266 /* BB verify if wct == 15 */
1268 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1270 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1271 /* Let caller know file was created so we can set the mode. */
1272 /* Do we care about the CreateAction in any other cases? */
1273 /* BB FIXME BB */
1274 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1275 *pOplock |= CIFS_CREATE_ACTION; */
1276 /* BB FIXME END */
1278 if (pfile_info) {
1279 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1280 pfile_info->LastAccessTime = 0; /* BB fixme */
1281 pfile_info->LastWriteTime = 0; /* BB fixme */
1282 pfile_info->ChangeTime = 0; /* BB fixme */
1283 pfile_info->Attributes =
1284 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1285 /* the file_info buf is endian converted by caller */
1286 pfile_info->AllocationSize =
1287 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1288 pfile_info->EndOfFile = pfile_info->AllocationSize;
1289 pfile_info->NumberOfLinks = cpu_to_le32(1);
1290 pfile_info->DeletePending = 0;
1294 cifs_buf_release(pSMB);
1295 if (rc == -EAGAIN)
1296 goto OldOpenRetry;
1297 return rc;
1301 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1302 const char *fileName, const int openDisposition,
1303 const int access_flags, const int create_options, __u16 *netfid,
1304 int *pOplock, FILE_ALL_INFO *pfile_info,
1305 const struct nls_table *nls_codepage, int remap)
1307 int rc = -EACCES;
1308 OPEN_REQ *pSMB = NULL;
1309 OPEN_RSP *pSMBr = NULL;
1310 int bytes_returned;
1311 int name_len;
1312 __u16 count;
1314 openRetry:
1315 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1316 (void **) &pSMBr);
1317 if (rc)
1318 return rc;
1320 pSMB->AndXCommand = 0xFF; /* none */
1322 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1323 count = 1; /* account for one byte pad to word boundary */
1324 name_len =
1325 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1326 fileName, PATH_MAX, nls_codepage, remap);
1327 name_len++; /* trailing null */
1328 name_len *= 2;
1329 pSMB->NameLength = cpu_to_le16(name_len);
1330 } else { /* BB improve check for buffer overruns BB */
1331 count = 0; /* no pad */
1332 name_len = strnlen(fileName, PATH_MAX);
1333 name_len++; /* trailing null */
1334 pSMB->NameLength = cpu_to_le16(name_len);
1335 strncpy(pSMB->fileName, fileName, name_len);
1337 if (*pOplock & REQ_OPLOCK)
1338 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1339 else if (*pOplock & REQ_BATCHOPLOCK)
1340 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1341 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1342 pSMB->AllocationSize = 0;
1343 /* set file as system file if special file such
1344 as fifo and server expecting SFU style and
1345 no Unix extensions */
1346 if (create_options & CREATE_OPTION_SPECIAL)
1347 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1348 else
1349 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1351 /* XP does not handle ATTR_POSIX_SEMANTICS */
1352 /* but it helps speed up case sensitive checks for other
1353 servers such as Samba */
1354 if (tcon->ses->capabilities & CAP_UNIX)
1355 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1357 if (create_options & CREATE_OPTION_READONLY)
1358 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1360 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1361 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1362 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1363 /* BB Expirement with various impersonation levels and verify */
1364 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1365 pSMB->SecurityFlags =
1366 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1368 count += name_len;
1369 pSMB->hdr.smb_buf_length += count;
1371 pSMB->ByteCount = cpu_to_le16(count);
1372 /* long_op set to 1 to allow for oplock break timeouts */
1373 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1374 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1375 cifs_stats_inc(&tcon->num_opens);
1376 if (rc) {
1377 cFYI(1, ("Error in Open = %d", rc));
1378 } else {
1379 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1380 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1381 /* Let caller know file was created so we can set the mode. */
1382 /* Do we care about the CreateAction in any other cases? */
1383 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1384 *pOplock |= CIFS_CREATE_ACTION;
1385 if (pfile_info) {
1386 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1387 36 /* CreationTime to Attributes */);
1388 /* the file_info buf is endian converted by caller */
1389 pfile_info->AllocationSize = pSMBr->AllocationSize;
1390 pfile_info->EndOfFile = pSMBr->EndOfFile;
1391 pfile_info->NumberOfLinks = cpu_to_le32(1);
1392 pfile_info->DeletePending = 0;
1396 cifs_buf_release(pSMB);
1397 if (rc == -EAGAIN)
1398 goto openRetry;
1399 return rc;
1403 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1404 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1405 char **buf, int *pbuf_type)
1407 int rc = -EACCES;
1408 READ_REQ *pSMB = NULL;
1409 READ_RSP *pSMBr = NULL;
1410 char *pReadData = NULL;
1411 int wct;
1412 int resp_buf_type = 0;
1413 struct kvec iov[1];
1415 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1416 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1417 wct = 12;
1418 else {
1419 wct = 10; /* old style read */
1420 if ((lseek >> 32) > 0) {
1421 /* can not handle this big offset for old */
1422 return -EIO;
1426 *nbytes = 0;
1427 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1428 if (rc)
1429 return rc;
1431 /* tcon and ses pointer are checked in smb_init */
1432 if (tcon->ses->server == NULL)
1433 return -ECONNABORTED;
1435 pSMB->AndXCommand = 0xFF; /* none */
1436 pSMB->Fid = netfid;
1437 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1438 if (wct == 12)
1439 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1441 pSMB->Remaining = 0;
1442 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1443 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1444 if (wct == 12)
1445 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1446 else {
1447 /* old style read */
1448 struct smb_com_readx_req *pSMBW =
1449 (struct smb_com_readx_req *)pSMB;
1450 pSMBW->ByteCount = 0;
1453 iov[0].iov_base = (char *)pSMB;
1454 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1455 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1456 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1457 cifs_stats_inc(&tcon->num_reads);
1458 pSMBr = (READ_RSP *)iov[0].iov_base;
1459 if (rc) {
1460 cERROR(1, ("Send error in read = %d", rc));
1461 } else {
1462 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1463 data_length = data_length << 16;
1464 data_length += le16_to_cpu(pSMBr->DataLength);
1465 *nbytes = data_length;
1467 /*check that DataLength would not go beyond end of SMB */
1468 if ((data_length > CIFSMaxBufSize)
1469 || (data_length > count)) {
1470 cFYI(1, ("bad length %d for count %d",
1471 data_length, count));
1472 rc = -EIO;
1473 *nbytes = 0;
1474 } else {
1475 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1476 le16_to_cpu(pSMBr->DataOffset);
1477 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1478 cERROR(1,("Faulting on read rc = %d",rc));
1479 rc = -EFAULT;
1480 }*/ /* can not use copy_to_user when using page cache*/
1481 if (*buf)
1482 memcpy(*buf, pReadData, data_length);
1486 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1487 if (*buf) {
1488 if (resp_buf_type == CIFS_SMALL_BUFFER)
1489 cifs_small_buf_release(iov[0].iov_base);
1490 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1491 cifs_buf_release(iov[0].iov_base);
1492 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1493 /* return buffer to caller to free */
1494 *buf = iov[0].iov_base;
1495 if (resp_buf_type == CIFS_SMALL_BUFFER)
1496 *pbuf_type = CIFS_SMALL_BUFFER;
1497 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1498 *pbuf_type = CIFS_LARGE_BUFFER;
1499 } /* else no valid buffer on return - leave as null */
1501 /* Note: On -EAGAIN error only caller can retry on handle based calls
1502 since file handle passed in no longer valid */
1503 return rc;
1508 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1509 const int netfid, const unsigned int count,
1510 const __u64 offset, unsigned int *nbytes, const char *buf,
1511 const char __user *ubuf, const int long_op)
1513 int rc = -EACCES;
1514 WRITE_REQ *pSMB = NULL;
1515 WRITE_RSP *pSMBr = NULL;
1516 int bytes_returned, wct;
1517 __u32 bytes_sent;
1518 __u16 byte_count;
1520 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1521 if (tcon->ses == NULL)
1522 return -ECONNABORTED;
1524 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1525 wct = 14;
1526 else {
1527 wct = 12;
1528 if ((offset >> 32) > 0) {
1529 /* can not handle big offset for old srv */
1530 return -EIO;
1534 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1535 (void **) &pSMBr);
1536 if (rc)
1537 return rc;
1538 /* tcon and ses pointer are checked in smb_init */
1539 if (tcon->ses->server == NULL)
1540 return -ECONNABORTED;
1542 pSMB->AndXCommand = 0xFF; /* none */
1543 pSMB->Fid = netfid;
1544 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1545 if (wct == 14)
1546 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1548 pSMB->Reserved = 0xFFFFFFFF;
1549 pSMB->WriteMode = 0;
1550 pSMB->Remaining = 0;
1552 /* Can increase buffer size if buffer is big enough in some cases ie we
1553 can send more if LARGE_WRITE_X capability returned by the server and if
1554 our buffer is big enough or if we convert to iovecs on socket writes
1555 and eliminate the copy to the CIFS buffer */
1556 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1557 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1558 } else {
1559 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1560 & ~0xFF;
1563 if (bytes_sent > count)
1564 bytes_sent = count;
1565 pSMB->DataOffset =
1566 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1567 if (buf)
1568 memcpy(pSMB->Data, buf, bytes_sent);
1569 else if (ubuf) {
1570 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1571 cifs_buf_release(pSMB);
1572 return -EFAULT;
1574 } else if (count != 0) {
1575 /* No buffer */
1576 cifs_buf_release(pSMB);
1577 return -EINVAL;
1578 } /* else setting file size with write of zero bytes */
1579 if (wct == 14)
1580 byte_count = bytes_sent + 1; /* pad */
1581 else /* wct == 12 */
1582 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1584 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1585 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1586 pSMB->hdr.smb_buf_length += byte_count;
1588 if (wct == 14)
1589 pSMB->ByteCount = cpu_to_le16(byte_count);
1590 else { /* old style write has byte count 4 bytes earlier
1591 so 4 bytes pad */
1592 struct smb_com_writex_req *pSMBW =
1593 (struct smb_com_writex_req *)pSMB;
1594 pSMBW->ByteCount = cpu_to_le16(byte_count);
1597 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1598 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1599 cifs_stats_inc(&tcon->num_writes);
1600 if (rc) {
1601 cFYI(1, ("Send error in write = %d", rc));
1602 *nbytes = 0;
1603 } else {
1604 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1605 *nbytes = (*nbytes) << 16;
1606 *nbytes += le16_to_cpu(pSMBr->Count);
1609 cifs_buf_release(pSMB);
1611 /* Note: On -EAGAIN error only caller can retry on handle based calls
1612 since file handle passed in no longer valid */
1614 return rc;
1618 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1619 const int netfid, const unsigned int count,
1620 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1621 int n_vec, const int long_op)
1623 int rc = -EACCES;
1624 WRITE_REQ *pSMB = NULL;
1625 int wct;
1626 int smb_hdr_len;
1627 int resp_buf_type = 0;
1629 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1631 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1632 wct = 14;
1633 } else {
1634 wct = 12;
1635 if ((offset >> 32) > 0) {
1636 /* can not handle big offset for old srv */
1637 return -EIO;
1640 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1641 if (rc)
1642 return rc;
1643 /* tcon and ses pointer are checked in smb_init */
1644 if (tcon->ses->server == NULL)
1645 return -ECONNABORTED;
1647 pSMB->AndXCommand = 0xFF; /* none */
1648 pSMB->Fid = netfid;
1649 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1650 if (wct == 14)
1651 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1652 pSMB->Reserved = 0xFFFFFFFF;
1653 pSMB->WriteMode = 0;
1654 pSMB->Remaining = 0;
1656 pSMB->DataOffset =
1657 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1659 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1660 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1661 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1662 if (wct == 14)
1663 pSMB->hdr.smb_buf_length += count+1;
1664 else /* wct == 12 */
1665 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1666 if (wct == 14)
1667 pSMB->ByteCount = cpu_to_le16(count + 1);
1668 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1669 struct smb_com_writex_req *pSMBW =
1670 (struct smb_com_writex_req *)pSMB;
1671 pSMBW->ByteCount = cpu_to_le16(count + 5);
1673 iov[0].iov_base = pSMB;
1674 if (wct == 14)
1675 iov[0].iov_len = smb_hdr_len + 4;
1676 else /* wct == 12 pad bigger by four bytes */
1677 iov[0].iov_len = smb_hdr_len + 8;
1680 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1681 long_op);
1682 cifs_stats_inc(&tcon->num_writes);
1683 if (rc) {
1684 cFYI(1, ("Send error Write2 = %d", rc));
1685 *nbytes = 0;
1686 } else if (resp_buf_type == 0) {
1687 /* presumably this can not happen, but best to be safe */
1688 rc = -EIO;
1689 *nbytes = 0;
1690 } else {
1691 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1692 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1693 *nbytes = (*nbytes) << 16;
1694 *nbytes += le16_to_cpu(pSMBr->Count);
1697 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1698 if (resp_buf_type == CIFS_SMALL_BUFFER)
1699 cifs_small_buf_release(iov[0].iov_base);
1700 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1701 cifs_buf_release(iov[0].iov_base);
1703 /* Note: On -EAGAIN error only caller can retry on handle based calls
1704 since file handle passed in no longer valid */
1706 return rc;
1711 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1712 const __u16 smb_file_id, const __u64 len,
1713 const __u64 offset, const __u32 numUnlock,
1714 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1716 int rc = 0;
1717 LOCK_REQ *pSMB = NULL;
1718 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1719 int bytes_returned;
1720 int timeout = 0;
1721 __u16 count;
1723 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1724 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1726 if (rc)
1727 return rc;
1729 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1730 timeout = CIFS_ASYNC_OP; /* no response expected */
1731 pSMB->Timeout = 0;
1732 } else if (waitFlag) {
1733 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1734 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1735 } else {
1736 pSMB->Timeout = 0;
1739 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1740 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1741 pSMB->LockType = lockType;
1742 pSMB->AndXCommand = 0xFF; /* none */
1743 pSMB->Fid = smb_file_id; /* netfid stays le */
1745 if ((numLock != 0) || (numUnlock != 0)) {
1746 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1747 /* BB where to store pid high? */
1748 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1749 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1750 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1751 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1752 count = sizeof(LOCKING_ANDX_RANGE);
1753 } else {
1754 /* oplock break */
1755 count = 0;
1757 pSMB->hdr.smb_buf_length += count;
1758 pSMB->ByteCount = cpu_to_le16(count);
1760 if (waitFlag) {
1761 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1762 (struct smb_hdr *) pSMB, &bytes_returned);
1763 cifs_small_buf_release(pSMB);
1764 } else {
1765 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1766 timeout);
1767 /* SMB buffer freed by function above */
1769 cifs_stats_inc(&tcon->num_locks);
1770 if (rc)
1771 cFYI(1, ("Send error in Lock = %d", rc));
1773 /* Note: On -EAGAIN error only caller can retry on handle based calls
1774 since file handle passed in no longer valid */
1775 return rc;
1779 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1780 const __u16 smb_file_id, const int get_flag, const __u64 len,
1781 struct file_lock *pLockData, const __u16 lock_type,
1782 const bool waitFlag)
1784 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1785 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1786 struct cifs_posix_lock *parm_data;
1787 int rc = 0;
1788 int timeout = 0;
1789 int bytes_returned = 0;
1790 int resp_buf_type = 0;
1791 __u16 params, param_offset, offset, byte_count, count;
1792 struct kvec iov[1];
1794 cFYI(1, ("Posix Lock"));
1796 if (pLockData == NULL)
1797 return -EINVAL;
1799 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1801 if (rc)
1802 return rc;
1804 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1806 params = 6;
1807 pSMB->MaxSetupCount = 0;
1808 pSMB->Reserved = 0;
1809 pSMB->Flags = 0;
1810 pSMB->Reserved2 = 0;
1811 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1812 offset = param_offset + params;
1814 count = sizeof(struct cifs_posix_lock);
1815 pSMB->MaxParameterCount = cpu_to_le16(2);
1816 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1817 pSMB->SetupCount = 1;
1818 pSMB->Reserved3 = 0;
1819 if (get_flag)
1820 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1821 else
1822 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1823 byte_count = 3 /* pad */ + params + count;
1824 pSMB->DataCount = cpu_to_le16(count);
1825 pSMB->ParameterCount = cpu_to_le16(params);
1826 pSMB->TotalDataCount = pSMB->DataCount;
1827 pSMB->TotalParameterCount = pSMB->ParameterCount;
1828 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1829 parm_data = (struct cifs_posix_lock *)
1830 (((char *) &pSMB->hdr.Protocol) + offset);
1832 parm_data->lock_type = cpu_to_le16(lock_type);
1833 if (waitFlag) {
1834 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1835 parm_data->lock_flags = cpu_to_le16(1);
1836 pSMB->Timeout = cpu_to_le32(-1);
1837 } else
1838 pSMB->Timeout = 0;
1840 parm_data->pid = cpu_to_le32(current->tgid);
1841 parm_data->start = cpu_to_le64(pLockData->fl_start);
1842 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1844 pSMB->DataOffset = cpu_to_le16(offset);
1845 pSMB->Fid = smb_file_id;
1846 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1847 pSMB->Reserved4 = 0;
1848 pSMB->hdr.smb_buf_length += byte_count;
1849 pSMB->ByteCount = cpu_to_le16(byte_count);
1850 if (waitFlag) {
1851 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1852 (struct smb_hdr *) pSMBr, &bytes_returned);
1853 } else {
1854 iov[0].iov_base = (char *)pSMB;
1855 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1856 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1857 &resp_buf_type, timeout);
1858 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1859 not try to free it twice below on exit */
1860 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1863 if (rc) {
1864 cFYI(1, ("Send error in Posix Lock = %d", rc));
1865 } else if (get_flag) {
1866 /* lock structure can be returned on get */
1867 __u16 data_offset;
1868 __u16 data_count;
1869 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1871 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1872 rc = -EIO; /* bad smb */
1873 goto plk_err_exit;
1875 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1876 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1877 if (data_count < sizeof(struct cifs_posix_lock)) {
1878 rc = -EIO;
1879 goto plk_err_exit;
1881 parm_data = (struct cifs_posix_lock *)
1882 ((char *)&pSMBr->hdr.Protocol + data_offset);
1883 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1884 pLockData->fl_type = F_UNLCK;
1887 plk_err_exit:
1888 if (pSMB)
1889 cifs_small_buf_release(pSMB);
1891 if (resp_buf_type == CIFS_SMALL_BUFFER)
1892 cifs_small_buf_release(iov[0].iov_base);
1893 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1894 cifs_buf_release(iov[0].iov_base);
1896 /* Note: On -EAGAIN error only caller can retry on handle based calls
1897 since file handle passed in no longer valid */
1899 return rc;
1904 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1906 int rc = 0;
1907 CLOSE_REQ *pSMB = NULL;
1908 cFYI(1, ("In CIFSSMBClose"));
1910 /* do not retry on dead session on close */
1911 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1912 if (rc == -EAGAIN)
1913 return 0;
1914 if (rc)
1915 return rc;
1917 pSMB->FileID = (__u16) smb_file_id;
1918 pSMB->LastWriteTime = 0xFFFFFFFF;
1919 pSMB->ByteCount = 0;
1920 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1921 cifs_stats_inc(&tcon->num_closes);
1922 if (rc) {
1923 if (rc != -EINTR) {
1924 /* EINTR is expected when user ctl-c to kill app */
1925 cERROR(1, ("Send error in Close = %d", rc));
1929 /* Since session is dead, file will be closed on server already */
1930 if (rc == -EAGAIN)
1931 rc = 0;
1933 return rc;
1937 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1939 int rc = 0;
1940 FLUSH_REQ *pSMB = NULL;
1941 cFYI(1, ("In CIFSSMBFlush"));
1943 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1944 if (rc)
1945 return rc;
1947 pSMB->FileID = (__u16) smb_file_id;
1948 pSMB->ByteCount = 0;
1949 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1950 cifs_stats_inc(&tcon->num_flushes);
1951 if (rc)
1952 cERROR(1, ("Send error in Flush = %d", rc));
1954 return rc;
1958 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1959 const char *fromName, const char *toName,
1960 const struct nls_table *nls_codepage, int remap)
1962 int rc = 0;
1963 RENAME_REQ *pSMB = NULL;
1964 RENAME_RSP *pSMBr = NULL;
1965 int bytes_returned;
1966 int name_len, name_len2;
1967 __u16 count;
1969 cFYI(1, ("In CIFSSMBRename"));
1970 renameRetry:
1971 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1972 (void **) &pSMBr);
1973 if (rc)
1974 return rc;
1976 pSMB->BufferFormat = 0x04;
1977 pSMB->SearchAttributes =
1978 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1979 ATTR_DIRECTORY);
1981 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1982 name_len =
1983 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1984 PATH_MAX, nls_codepage, remap);
1985 name_len++; /* trailing null */
1986 name_len *= 2;
1987 pSMB->OldFileName[name_len] = 0x04; /* pad */
1988 /* protocol requires ASCII signature byte on Unicode string */
1989 pSMB->OldFileName[name_len + 1] = 0x00;
1990 name_len2 =
1991 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1992 toName, PATH_MAX, nls_codepage, remap);
1993 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1994 name_len2 *= 2; /* convert to bytes */
1995 } else { /* BB improve the check for buffer overruns BB */
1996 name_len = strnlen(fromName, PATH_MAX);
1997 name_len++; /* trailing null */
1998 strncpy(pSMB->OldFileName, fromName, name_len);
1999 name_len2 = strnlen(toName, PATH_MAX);
2000 name_len2++; /* trailing null */
2001 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2002 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2003 name_len2++; /* trailing null */
2004 name_len2++; /* signature byte */
2007 count = 1 /* 1st signature byte */ + name_len + name_len2;
2008 pSMB->hdr.smb_buf_length += count;
2009 pSMB->ByteCount = cpu_to_le16(count);
2011 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2012 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2013 cifs_stats_inc(&tcon->num_renames);
2014 if (rc)
2015 cFYI(1, ("Send error in rename = %d", rc));
2017 cifs_buf_release(pSMB);
2019 if (rc == -EAGAIN)
2020 goto renameRetry;
2022 return rc;
2025 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2026 int netfid, const char *target_name,
2027 const struct nls_table *nls_codepage, int remap)
2029 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2030 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2031 struct set_file_rename *rename_info;
2032 char *data_offset;
2033 char dummy_string[30];
2034 int rc = 0;
2035 int bytes_returned = 0;
2036 int len_of_str;
2037 __u16 params, param_offset, offset, count, byte_count;
2039 cFYI(1, ("Rename to File by handle"));
2040 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2041 (void **) &pSMBr);
2042 if (rc)
2043 return rc;
2045 params = 6;
2046 pSMB->MaxSetupCount = 0;
2047 pSMB->Reserved = 0;
2048 pSMB->Flags = 0;
2049 pSMB->Timeout = 0;
2050 pSMB->Reserved2 = 0;
2051 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2052 offset = param_offset + params;
2054 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2055 rename_info = (struct set_file_rename *) data_offset;
2056 pSMB->MaxParameterCount = cpu_to_le16(2);
2057 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2058 pSMB->SetupCount = 1;
2059 pSMB->Reserved3 = 0;
2060 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2061 byte_count = 3 /* pad */ + params;
2062 pSMB->ParameterCount = cpu_to_le16(params);
2063 pSMB->TotalParameterCount = pSMB->ParameterCount;
2064 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2065 pSMB->DataOffset = cpu_to_le16(offset);
2066 /* construct random name ".cifs_tmp<inodenum><mid>" */
2067 rename_info->overwrite = cpu_to_le32(1);
2068 rename_info->root_fid = 0;
2069 /* unicode only call */
2070 if (target_name == NULL) {
2071 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2072 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2073 dummy_string, 24, nls_codepage, remap);
2074 } else {
2075 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2076 target_name, PATH_MAX, nls_codepage,
2077 remap);
2079 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2080 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2081 byte_count += count;
2082 pSMB->DataCount = cpu_to_le16(count);
2083 pSMB->TotalDataCount = pSMB->DataCount;
2084 pSMB->Fid = netfid;
2085 pSMB->InformationLevel =
2086 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2087 pSMB->Reserved4 = 0;
2088 pSMB->hdr.smb_buf_length += byte_count;
2089 pSMB->ByteCount = cpu_to_le16(byte_count);
2090 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2092 cifs_stats_inc(&pTcon->num_t2renames);
2093 if (rc)
2094 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2096 cifs_buf_release(pSMB);
2098 /* Note: On -EAGAIN error only caller can retry on handle based calls
2099 since file handle passed in no longer valid */
2101 return rc;
2105 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2106 const __u16 target_tid, const char *toName, const int flags,
2107 const struct nls_table *nls_codepage, int remap)
2109 int rc = 0;
2110 COPY_REQ *pSMB = NULL;
2111 COPY_RSP *pSMBr = NULL;
2112 int bytes_returned;
2113 int name_len, name_len2;
2114 __u16 count;
2116 cFYI(1, ("In CIFSSMBCopy"));
2117 copyRetry:
2118 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2119 (void **) &pSMBr);
2120 if (rc)
2121 return rc;
2123 pSMB->BufferFormat = 0x04;
2124 pSMB->Tid2 = target_tid;
2126 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2128 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2129 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2130 fromName, PATH_MAX, nls_codepage,
2131 remap);
2132 name_len++; /* trailing null */
2133 name_len *= 2;
2134 pSMB->OldFileName[name_len] = 0x04; /* pad */
2135 /* protocol requires ASCII signature byte on Unicode string */
2136 pSMB->OldFileName[name_len + 1] = 0x00;
2137 name_len2 =
2138 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2139 toName, PATH_MAX, nls_codepage, remap);
2140 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2141 name_len2 *= 2; /* convert to bytes */
2142 } else { /* BB improve the check for buffer overruns BB */
2143 name_len = strnlen(fromName, PATH_MAX);
2144 name_len++; /* trailing null */
2145 strncpy(pSMB->OldFileName, fromName, name_len);
2146 name_len2 = strnlen(toName, PATH_MAX);
2147 name_len2++; /* trailing null */
2148 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2149 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2150 name_len2++; /* trailing null */
2151 name_len2++; /* signature byte */
2154 count = 1 /* 1st signature byte */ + name_len + name_len2;
2155 pSMB->hdr.smb_buf_length += count;
2156 pSMB->ByteCount = cpu_to_le16(count);
2158 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2159 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2160 if (rc) {
2161 cFYI(1, ("Send error in copy = %d with %d files copied",
2162 rc, le16_to_cpu(pSMBr->CopyCount)));
2164 cifs_buf_release(pSMB);
2166 if (rc == -EAGAIN)
2167 goto copyRetry;
2169 return rc;
2173 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2174 const char *fromName, const char *toName,
2175 const struct nls_table *nls_codepage)
2177 TRANSACTION2_SPI_REQ *pSMB = NULL;
2178 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2179 char *data_offset;
2180 int name_len;
2181 int name_len_target;
2182 int rc = 0;
2183 int bytes_returned = 0;
2184 __u16 params, param_offset, offset, byte_count;
2186 cFYI(1, ("In Symlink Unix style"));
2187 createSymLinkRetry:
2188 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2189 (void **) &pSMBr);
2190 if (rc)
2191 return rc;
2193 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2194 name_len =
2195 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2196 /* find define for this maxpathcomponent */
2197 , nls_codepage);
2198 name_len++; /* trailing null */
2199 name_len *= 2;
2201 } else { /* BB improve the check for buffer overruns BB */
2202 name_len = strnlen(fromName, PATH_MAX);
2203 name_len++; /* trailing null */
2204 strncpy(pSMB->FileName, fromName, name_len);
2206 params = 6 + name_len;
2207 pSMB->MaxSetupCount = 0;
2208 pSMB->Reserved = 0;
2209 pSMB->Flags = 0;
2210 pSMB->Timeout = 0;
2211 pSMB->Reserved2 = 0;
2212 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2213 InformationLevel) - 4;
2214 offset = param_offset + params;
2216 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2217 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2218 name_len_target =
2219 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2220 /* find define for this maxpathcomponent */
2221 , nls_codepage);
2222 name_len_target++; /* trailing null */
2223 name_len_target *= 2;
2224 } else { /* BB improve the check for buffer overruns BB */
2225 name_len_target = strnlen(toName, PATH_MAX);
2226 name_len_target++; /* trailing null */
2227 strncpy(data_offset, toName, name_len_target);
2230 pSMB->MaxParameterCount = cpu_to_le16(2);
2231 /* BB find exact max on data count below from sess */
2232 pSMB->MaxDataCount = cpu_to_le16(1000);
2233 pSMB->SetupCount = 1;
2234 pSMB->Reserved3 = 0;
2235 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2236 byte_count = 3 /* pad */ + params + name_len_target;
2237 pSMB->DataCount = cpu_to_le16(name_len_target);
2238 pSMB->ParameterCount = cpu_to_le16(params);
2239 pSMB->TotalDataCount = pSMB->DataCount;
2240 pSMB->TotalParameterCount = pSMB->ParameterCount;
2241 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2242 pSMB->DataOffset = cpu_to_le16(offset);
2243 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2244 pSMB->Reserved4 = 0;
2245 pSMB->hdr.smb_buf_length += byte_count;
2246 pSMB->ByteCount = cpu_to_le16(byte_count);
2247 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2248 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2249 cifs_stats_inc(&tcon->num_symlinks);
2250 if (rc)
2251 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2253 cifs_buf_release(pSMB);
2255 if (rc == -EAGAIN)
2256 goto createSymLinkRetry;
2258 return rc;
2262 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2263 const char *fromName, const char *toName,
2264 const struct nls_table *nls_codepage, int remap)
2266 TRANSACTION2_SPI_REQ *pSMB = NULL;
2267 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2268 char *data_offset;
2269 int name_len;
2270 int name_len_target;
2271 int rc = 0;
2272 int bytes_returned = 0;
2273 __u16 params, param_offset, offset, byte_count;
2275 cFYI(1, ("In Create Hard link Unix style"));
2276 createHardLinkRetry:
2277 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2278 (void **) &pSMBr);
2279 if (rc)
2280 return rc;
2282 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2283 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2284 PATH_MAX, nls_codepage, remap);
2285 name_len++; /* trailing null */
2286 name_len *= 2;
2288 } else { /* BB improve the check for buffer overruns BB */
2289 name_len = strnlen(toName, PATH_MAX);
2290 name_len++; /* trailing null */
2291 strncpy(pSMB->FileName, toName, name_len);
2293 params = 6 + name_len;
2294 pSMB->MaxSetupCount = 0;
2295 pSMB->Reserved = 0;
2296 pSMB->Flags = 0;
2297 pSMB->Timeout = 0;
2298 pSMB->Reserved2 = 0;
2299 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2300 InformationLevel) - 4;
2301 offset = param_offset + params;
2303 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2305 name_len_target =
2306 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2307 nls_codepage, remap);
2308 name_len_target++; /* trailing null */
2309 name_len_target *= 2;
2310 } else { /* BB improve the check for buffer overruns BB */
2311 name_len_target = strnlen(fromName, PATH_MAX);
2312 name_len_target++; /* trailing null */
2313 strncpy(data_offset, fromName, name_len_target);
2316 pSMB->MaxParameterCount = cpu_to_le16(2);
2317 /* BB find exact max on data count below from sess*/
2318 pSMB->MaxDataCount = cpu_to_le16(1000);
2319 pSMB->SetupCount = 1;
2320 pSMB->Reserved3 = 0;
2321 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2322 byte_count = 3 /* pad */ + params + name_len_target;
2323 pSMB->ParameterCount = cpu_to_le16(params);
2324 pSMB->TotalParameterCount = pSMB->ParameterCount;
2325 pSMB->DataCount = cpu_to_le16(name_len_target);
2326 pSMB->TotalDataCount = pSMB->DataCount;
2327 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2328 pSMB->DataOffset = cpu_to_le16(offset);
2329 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2330 pSMB->Reserved4 = 0;
2331 pSMB->hdr.smb_buf_length += byte_count;
2332 pSMB->ByteCount = cpu_to_le16(byte_count);
2333 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2334 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2335 cifs_stats_inc(&tcon->num_hardlinks);
2336 if (rc)
2337 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2339 cifs_buf_release(pSMB);
2340 if (rc == -EAGAIN)
2341 goto createHardLinkRetry;
2343 return rc;
2347 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2348 const char *fromName, const char *toName,
2349 const struct nls_table *nls_codepage, int remap)
2351 int rc = 0;
2352 NT_RENAME_REQ *pSMB = NULL;
2353 RENAME_RSP *pSMBr = NULL;
2354 int bytes_returned;
2355 int name_len, name_len2;
2356 __u16 count;
2358 cFYI(1, ("In CIFSCreateHardLink"));
2359 winCreateHardLinkRetry:
2361 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2362 (void **) &pSMBr);
2363 if (rc)
2364 return rc;
2366 pSMB->SearchAttributes =
2367 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2368 ATTR_DIRECTORY);
2369 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2370 pSMB->ClusterCount = 0;
2372 pSMB->BufferFormat = 0x04;
2374 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2375 name_len =
2376 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2377 PATH_MAX, nls_codepage, remap);
2378 name_len++; /* trailing null */
2379 name_len *= 2;
2380 pSMB->OldFileName[name_len] = 0; /* pad */
2381 pSMB->OldFileName[name_len + 1] = 0x04;
2382 name_len2 =
2383 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2384 toName, PATH_MAX, nls_codepage, remap);
2385 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2386 name_len2 *= 2; /* convert to bytes */
2387 } else { /* BB improve the check for buffer overruns BB */
2388 name_len = strnlen(fromName, PATH_MAX);
2389 name_len++; /* trailing null */
2390 strncpy(pSMB->OldFileName, fromName, name_len);
2391 name_len2 = strnlen(toName, PATH_MAX);
2392 name_len2++; /* trailing null */
2393 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2394 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2395 name_len2++; /* trailing null */
2396 name_len2++; /* signature byte */
2399 count = 1 /* string type byte */ + name_len + name_len2;
2400 pSMB->hdr.smb_buf_length += count;
2401 pSMB->ByteCount = cpu_to_le16(count);
2403 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2404 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2405 cifs_stats_inc(&tcon->num_hardlinks);
2406 if (rc)
2407 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2409 cifs_buf_release(pSMB);
2410 if (rc == -EAGAIN)
2411 goto winCreateHardLinkRetry;
2413 return rc;
2417 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2418 const unsigned char *searchName,
2419 char *symlinkinfo, const int buflen,
2420 const struct nls_table *nls_codepage)
2422 /* SMB_QUERY_FILE_UNIX_LINK */
2423 TRANSACTION2_QPI_REQ *pSMB = NULL;
2424 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2425 int rc = 0;
2426 int bytes_returned;
2427 int name_len;
2428 __u16 params, byte_count;
2430 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2432 querySymLinkRetry:
2433 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2434 (void **) &pSMBr);
2435 if (rc)
2436 return rc;
2438 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2439 name_len =
2440 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2441 PATH_MAX, nls_codepage);
2442 name_len++; /* trailing null */
2443 name_len *= 2;
2444 } else { /* BB improve the check for buffer overruns BB */
2445 name_len = strnlen(searchName, PATH_MAX);
2446 name_len++; /* trailing null */
2447 strncpy(pSMB->FileName, searchName, name_len);
2450 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2451 pSMB->TotalDataCount = 0;
2452 pSMB->MaxParameterCount = cpu_to_le16(2);
2453 /* BB find exact max data count below from sess structure BB */
2454 pSMB->MaxDataCount = cpu_to_le16(4000);
2455 pSMB->MaxSetupCount = 0;
2456 pSMB->Reserved = 0;
2457 pSMB->Flags = 0;
2458 pSMB->Timeout = 0;
2459 pSMB->Reserved2 = 0;
2460 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2461 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2462 pSMB->DataCount = 0;
2463 pSMB->DataOffset = 0;
2464 pSMB->SetupCount = 1;
2465 pSMB->Reserved3 = 0;
2466 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2467 byte_count = params + 1 /* pad */ ;
2468 pSMB->TotalParameterCount = cpu_to_le16(params);
2469 pSMB->ParameterCount = pSMB->TotalParameterCount;
2470 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2471 pSMB->Reserved4 = 0;
2472 pSMB->hdr.smb_buf_length += byte_count;
2473 pSMB->ByteCount = cpu_to_le16(byte_count);
2475 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2476 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2477 if (rc) {
2478 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2479 } else {
2480 /* decode response */
2482 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2483 if (rc || (pSMBr->ByteCount < 2))
2484 /* BB also check enough total bytes returned */
2485 rc = -EIO; /* bad smb */
2486 else {
2487 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2488 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2490 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2491 name_len = UniStrnlen((wchar_t *) ((char *)
2492 &pSMBr->hdr.Protocol + data_offset),
2493 min_t(const int, buflen, count) / 2);
2494 /* BB FIXME investigate remapping reserved chars here */
2495 cifs_strfromUCS_le(symlinkinfo,
2496 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2497 + data_offset),
2498 name_len, nls_codepage);
2499 } else {
2500 strncpy(symlinkinfo,
2501 (char *) &pSMBr->hdr.Protocol +
2502 data_offset,
2503 min_t(const int, buflen, count));
2505 symlinkinfo[buflen] = 0;
2506 /* just in case so calling code does not go off the end of buffer */
2509 cifs_buf_release(pSMB);
2510 if (rc == -EAGAIN)
2511 goto querySymLinkRetry;
2512 return rc;
2515 #ifdef CONFIG_CIFS_EXPERIMENTAL
2516 /* Initialize NT TRANSACT SMB into small smb request buffer.
2517 This assumes that all NT TRANSACTS that we init here have
2518 total parm and data under about 400 bytes (to fit in small cifs
2519 buffer size), which is the case so far, it easily fits. NB:
2520 Setup words themselves and ByteCount
2521 MaxSetupCount (size of returned setup area) and
2522 MaxParameterCount (returned parms size) must be set by caller */
2523 static int
2524 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2525 const int parm_len, struct cifsTconInfo *tcon,
2526 void **ret_buf)
2528 int rc;
2529 __u32 temp_offset;
2530 struct smb_com_ntransact_req *pSMB;
2532 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2533 (void **)&pSMB);
2534 if (rc)
2535 return rc;
2536 *ret_buf = (void *)pSMB;
2537 pSMB->Reserved = 0;
2538 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2539 pSMB->TotalDataCount = 0;
2540 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2541 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2542 pSMB->ParameterCount = pSMB->TotalParameterCount;
2543 pSMB->DataCount = pSMB->TotalDataCount;
2544 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2545 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2546 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2547 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2548 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2549 pSMB->SubCommand = cpu_to_le16(sub_command);
2550 return 0;
2553 static int
2554 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2555 __u32 *pparmlen, __u32 *pdatalen)
2557 char *end_of_smb;
2558 __u32 data_count, data_offset, parm_count, parm_offset;
2559 struct smb_com_ntransact_rsp *pSMBr;
2561 *pdatalen = 0;
2562 *pparmlen = 0;
2564 if (buf == NULL)
2565 return -EINVAL;
2567 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2569 /* ByteCount was converted from little endian in SendReceive */
2570 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2571 (char *)&pSMBr->ByteCount;
2573 data_offset = le32_to_cpu(pSMBr->DataOffset);
2574 data_count = le32_to_cpu(pSMBr->DataCount);
2575 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2576 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2578 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2579 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2581 /* should we also check that parm and data areas do not overlap? */
2582 if (*ppparm > end_of_smb) {
2583 cFYI(1, ("parms start after end of smb"));
2584 return -EINVAL;
2585 } else if (parm_count + *ppparm > end_of_smb) {
2586 cFYI(1, ("parm end after end of smb"));
2587 return -EINVAL;
2588 } else if (*ppdata > end_of_smb) {
2589 cFYI(1, ("data starts after end of smb"));
2590 return -EINVAL;
2591 } else if (data_count + *ppdata > end_of_smb) {
2592 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2593 *ppdata, data_count, (data_count + *ppdata),
2594 end_of_smb, pSMBr));
2595 return -EINVAL;
2596 } else if (parm_count + data_count > pSMBr->ByteCount) {
2597 cFYI(1, ("parm count and data count larger than SMB"));
2598 return -EINVAL;
2600 *pdatalen = data_count;
2601 *pparmlen = parm_count;
2602 return 0;
2604 #endif /* CIFS_EXPERIMENTAL */
2607 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2608 const unsigned char *searchName,
2609 char *symlinkinfo, const int buflen, __u16 fid,
2610 const struct nls_table *nls_codepage)
2612 int rc = 0;
2613 int bytes_returned;
2614 int name_len;
2615 struct smb_com_transaction_ioctl_req *pSMB;
2616 struct smb_com_transaction_ioctl_rsp *pSMBr;
2618 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2619 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2620 (void **) &pSMBr);
2621 if (rc)
2622 return rc;
2624 pSMB->TotalParameterCount = 0 ;
2625 pSMB->TotalDataCount = 0;
2626 pSMB->MaxParameterCount = cpu_to_le32(2);
2627 /* BB find exact data count max from sess structure BB */
2628 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2629 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2630 pSMB->MaxSetupCount = 4;
2631 pSMB->Reserved = 0;
2632 pSMB->ParameterOffset = 0;
2633 pSMB->DataCount = 0;
2634 pSMB->DataOffset = 0;
2635 pSMB->SetupCount = 4;
2636 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2637 pSMB->ParameterCount = pSMB->TotalParameterCount;
2638 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2639 pSMB->IsFsctl = 1; /* FSCTL */
2640 pSMB->IsRootFlag = 0;
2641 pSMB->Fid = fid; /* file handle always le */
2642 pSMB->ByteCount = 0;
2644 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2645 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2646 if (rc) {
2647 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2648 } else { /* decode response */
2649 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2650 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2651 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2652 /* BB also check enough total bytes returned */
2653 rc = -EIO; /* bad smb */
2654 else {
2655 if (data_count && (data_count < 2048)) {
2656 char *end_of_smb = 2 /* sizeof byte count */ +
2657 pSMBr->ByteCount +
2658 (char *)&pSMBr->ByteCount;
2660 struct reparse_data *reparse_buf =
2661 (struct reparse_data *)
2662 ((char *)&pSMBr->hdr.Protocol
2663 + data_offset);
2664 if ((char *)reparse_buf >= end_of_smb) {
2665 rc = -EIO;
2666 goto qreparse_out;
2668 if ((reparse_buf->LinkNamesBuf +
2669 reparse_buf->TargetNameOffset +
2670 reparse_buf->TargetNameLen) >
2671 end_of_smb) {
2672 cFYI(1, ("reparse buf beyond SMB"));
2673 rc = -EIO;
2674 goto qreparse_out;
2677 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2678 name_len = UniStrnlen((wchar_t *)
2679 (reparse_buf->LinkNamesBuf +
2680 reparse_buf->TargetNameOffset),
2681 min(buflen/2,
2682 reparse_buf->TargetNameLen / 2));
2683 cifs_strfromUCS_le(symlinkinfo,
2684 (__le16 *) (reparse_buf->LinkNamesBuf +
2685 reparse_buf->TargetNameOffset),
2686 name_len, nls_codepage);
2687 } else { /* ASCII names */
2688 strncpy(symlinkinfo,
2689 reparse_buf->LinkNamesBuf +
2690 reparse_buf->TargetNameOffset,
2691 min_t(const int, buflen,
2692 reparse_buf->TargetNameLen));
2694 } else {
2695 rc = -EIO;
2696 cFYI(1, ("Invalid return data count on "
2697 "get reparse info ioctl"));
2699 symlinkinfo[buflen] = 0; /* just in case so the caller
2700 does not go off the end of the buffer */
2701 cFYI(1, ("readlink result - %s", symlinkinfo));
2704 qreparse_out:
2705 cifs_buf_release(pSMB);
2707 /* Note: On -EAGAIN error only caller can retry on handle based calls
2708 since file handle passed in no longer valid */
2710 return rc;
2713 #ifdef CONFIG_CIFS_POSIX
2715 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2716 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2717 struct cifs_posix_ace *cifs_ace)
2719 /* u8 cifs fields do not need le conversion */
2720 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2721 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2722 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2723 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2725 return;
2728 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2729 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2730 const int acl_type, const int size_of_data_area)
2732 int size = 0;
2733 int i;
2734 __u16 count;
2735 struct cifs_posix_ace *pACE;
2736 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2737 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2739 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2740 return -EOPNOTSUPP;
2742 if (acl_type & ACL_TYPE_ACCESS) {
2743 count = le16_to_cpu(cifs_acl->access_entry_count);
2744 pACE = &cifs_acl->ace_array[0];
2745 size = sizeof(struct cifs_posix_acl);
2746 size += sizeof(struct cifs_posix_ace) * count;
2747 /* check if we would go beyond end of SMB */
2748 if (size_of_data_area < size) {
2749 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2750 size_of_data_area, size));
2751 return -EINVAL;
2753 } else if (acl_type & ACL_TYPE_DEFAULT) {
2754 count = le16_to_cpu(cifs_acl->access_entry_count);
2755 size = sizeof(struct cifs_posix_acl);
2756 size += sizeof(struct cifs_posix_ace) * count;
2757 /* skip past access ACEs to get to default ACEs */
2758 pACE = &cifs_acl->ace_array[count];
2759 count = le16_to_cpu(cifs_acl->default_entry_count);
2760 size += sizeof(struct cifs_posix_ace) * count;
2761 /* check if we would go beyond end of SMB */
2762 if (size_of_data_area < size)
2763 return -EINVAL;
2764 } else {
2765 /* illegal type */
2766 return -EINVAL;
2769 size = posix_acl_xattr_size(count);
2770 if ((buflen == 0) || (local_acl == NULL)) {
2771 /* used to query ACL EA size */
2772 } else if (size > buflen) {
2773 return -ERANGE;
2774 } else /* buffer big enough */ {
2775 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2776 for (i = 0; i < count ; i++) {
2777 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2778 pACE++;
2781 return size;
2784 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2785 const posix_acl_xattr_entry *local_ace)
2787 __u16 rc = 0; /* 0 = ACL converted ok */
2789 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2790 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2791 /* BB is there a better way to handle the large uid? */
2792 if (local_ace->e_id == cpu_to_le32(-1)) {
2793 /* Probably no need to le convert -1 on any arch but can not hurt */
2794 cifs_ace->cifs_uid = cpu_to_le64(-1);
2795 } else
2796 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2797 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2798 return rc;
2801 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2802 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2803 const int buflen, const int acl_type)
2805 __u16 rc = 0;
2806 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2807 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2808 int count;
2809 int i;
2811 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2812 return 0;
2814 count = posix_acl_xattr_count((size_t)buflen);
2815 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2816 "version of %d",
2817 count, buflen, le32_to_cpu(local_acl->a_version)));
2818 if (le32_to_cpu(local_acl->a_version) != 2) {
2819 cFYI(1, ("unknown POSIX ACL version %d",
2820 le32_to_cpu(local_acl->a_version)));
2821 return 0;
2823 cifs_acl->version = cpu_to_le16(1);
2824 if (acl_type == ACL_TYPE_ACCESS)
2825 cifs_acl->access_entry_count = cpu_to_le16(count);
2826 else if (acl_type == ACL_TYPE_DEFAULT)
2827 cifs_acl->default_entry_count = cpu_to_le16(count);
2828 else {
2829 cFYI(1, ("unknown ACL type %d", acl_type));
2830 return 0;
2832 for (i = 0; i < count; i++) {
2833 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2834 &local_acl->a_entries[i]);
2835 if (rc != 0) {
2836 /* ACE not converted */
2837 break;
2840 if (rc == 0) {
2841 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2842 rc += sizeof(struct cifs_posix_acl);
2843 /* BB add check to make sure ACL does not overflow SMB */
2845 return rc;
2849 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2850 const unsigned char *searchName,
2851 char *acl_inf, const int buflen, const int acl_type,
2852 const struct nls_table *nls_codepage, int remap)
2854 /* SMB_QUERY_POSIX_ACL */
2855 TRANSACTION2_QPI_REQ *pSMB = NULL;
2856 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2857 int rc = 0;
2858 int bytes_returned;
2859 int name_len;
2860 __u16 params, byte_count;
2862 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2864 queryAclRetry:
2865 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2866 (void **) &pSMBr);
2867 if (rc)
2868 return rc;
2870 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2871 name_len =
2872 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2873 PATH_MAX, nls_codepage, remap);
2874 name_len++; /* trailing null */
2875 name_len *= 2;
2876 pSMB->FileName[name_len] = 0;
2877 pSMB->FileName[name_len+1] = 0;
2878 } else { /* BB improve the check for buffer overruns BB */
2879 name_len = strnlen(searchName, PATH_MAX);
2880 name_len++; /* trailing null */
2881 strncpy(pSMB->FileName, searchName, name_len);
2884 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2885 pSMB->TotalDataCount = 0;
2886 pSMB->MaxParameterCount = cpu_to_le16(2);
2887 /* BB find exact max data count below from sess structure BB */
2888 pSMB->MaxDataCount = cpu_to_le16(4000);
2889 pSMB->MaxSetupCount = 0;
2890 pSMB->Reserved = 0;
2891 pSMB->Flags = 0;
2892 pSMB->Timeout = 0;
2893 pSMB->Reserved2 = 0;
2894 pSMB->ParameterOffset = cpu_to_le16(
2895 offsetof(struct smb_com_transaction2_qpi_req,
2896 InformationLevel) - 4);
2897 pSMB->DataCount = 0;
2898 pSMB->DataOffset = 0;
2899 pSMB->SetupCount = 1;
2900 pSMB->Reserved3 = 0;
2901 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2902 byte_count = params + 1 /* pad */ ;
2903 pSMB->TotalParameterCount = cpu_to_le16(params);
2904 pSMB->ParameterCount = pSMB->TotalParameterCount;
2905 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2906 pSMB->Reserved4 = 0;
2907 pSMB->hdr.smb_buf_length += byte_count;
2908 pSMB->ByteCount = cpu_to_le16(byte_count);
2910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2912 cifs_stats_inc(&tcon->num_acl_get);
2913 if (rc) {
2914 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2915 } else {
2916 /* decode response */
2918 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2919 if (rc || (pSMBr->ByteCount < 2))
2920 /* BB also check enough total bytes returned */
2921 rc = -EIO; /* bad smb */
2922 else {
2923 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2924 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2925 rc = cifs_copy_posix_acl(acl_inf,
2926 (char *)&pSMBr->hdr.Protocol+data_offset,
2927 buflen, acl_type, count);
2930 cifs_buf_release(pSMB);
2931 if (rc == -EAGAIN)
2932 goto queryAclRetry;
2933 return rc;
2937 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2938 const unsigned char *fileName,
2939 const char *local_acl, const int buflen,
2940 const int acl_type,
2941 const struct nls_table *nls_codepage, int remap)
2943 struct smb_com_transaction2_spi_req *pSMB = NULL;
2944 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2945 char *parm_data;
2946 int name_len;
2947 int rc = 0;
2948 int bytes_returned = 0;
2949 __u16 params, byte_count, data_count, param_offset, offset;
2951 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2952 setAclRetry:
2953 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2954 (void **) &pSMBr);
2955 if (rc)
2956 return rc;
2957 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2958 name_len =
2959 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2960 PATH_MAX, nls_codepage, remap);
2961 name_len++; /* trailing null */
2962 name_len *= 2;
2963 } else { /* BB improve the check for buffer overruns BB */
2964 name_len = strnlen(fileName, PATH_MAX);
2965 name_len++; /* trailing null */
2966 strncpy(pSMB->FileName, fileName, name_len);
2968 params = 6 + name_len;
2969 pSMB->MaxParameterCount = cpu_to_le16(2);
2970 /* BB find max SMB size from sess */
2971 pSMB->MaxDataCount = cpu_to_le16(1000);
2972 pSMB->MaxSetupCount = 0;
2973 pSMB->Reserved = 0;
2974 pSMB->Flags = 0;
2975 pSMB->Timeout = 0;
2976 pSMB->Reserved2 = 0;
2977 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2978 InformationLevel) - 4;
2979 offset = param_offset + params;
2980 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2981 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2983 /* convert to on the wire format for POSIX ACL */
2984 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2986 if (data_count == 0) {
2987 rc = -EOPNOTSUPP;
2988 goto setACLerrorExit;
2990 pSMB->DataOffset = cpu_to_le16(offset);
2991 pSMB->SetupCount = 1;
2992 pSMB->Reserved3 = 0;
2993 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2994 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2995 byte_count = 3 /* pad */ + params + data_count;
2996 pSMB->DataCount = cpu_to_le16(data_count);
2997 pSMB->TotalDataCount = pSMB->DataCount;
2998 pSMB->ParameterCount = cpu_to_le16(params);
2999 pSMB->TotalParameterCount = pSMB->ParameterCount;
3000 pSMB->Reserved4 = 0;
3001 pSMB->hdr.smb_buf_length += byte_count;
3002 pSMB->ByteCount = cpu_to_le16(byte_count);
3003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3005 if (rc)
3006 cFYI(1, ("Set POSIX ACL returned %d", rc));
3008 setACLerrorExit:
3009 cifs_buf_release(pSMB);
3010 if (rc == -EAGAIN)
3011 goto setAclRetry;
3012 return rc;
3015 /* BB fix tabs in this function FIXME BB */
3017 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
3018 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3020 int rc = 0;
3021 struct smb_t2_qfi_req *pSMB = NULL;
3022 struct smb_t2_qfi_rsp *pSMBr = NULL;
3023 int bytes_returned;
3024 __u16 params, byte_count;
3026 cFYI(1, ("In GetExtAttr"));
3027 if (tcon == NULL)
3028 return -ENODEV;
3030 GetExtAttrRetry:
3031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3032 (void **) &pSMBr);
3033 if (rc)
3034 return rc;
3036 params = 2 /* level */ + 2 /* fid */;
3037 pSMB->t2.TotalDataCount = 0;
3038 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3039 /* BB find exact max data count below from sess structure BB */
3040 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3041 pSMB->t2.MaxSetupCount = 0;
3042 pSMB->t2.Reserved = 0;
3043 pSMB->t2.Flags = 0;
3044 pSMB->t2.Timeout = 0;
3045 pSMB->t2.Reserved2 = 0;
3046 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3047 Fid) - 4);
3048 pSMB->t2.DataCount = 0;
3049 pSMB->t2.DataOffset = 0;
3050 pSMB->t2.SetupCount = 1;
3051 pSMB->t2.Reserved3 = 0;
3052 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3053 byte_count = params + 1 /* pad */ ;
3054 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3055 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3056 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3057 pSMB->Pad = 0;
3058 pSMB->Fid = netfid;
3059 pSMB->hdr.smb_buf_length += byte_count;
3060 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3062 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3063 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3064 if (rc) {
3065 cFYI(1, ("error %d in GetExtAttr", rc));
3066 } else {
3067 /* decode response */
3068 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3069 if (rc || (pSMBr->ByteCount < 2))
3070 /* BB also check enough total bytes returned */
3071 /* If rc should we check for EOPNOSUPP and
3072 disable the srvino flag? or in caller? */
3073 rc = -EIO; /* bad smb */
3074 else {
3075 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3076 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3077 struct file_chattr_info *pfinfo;
3078 /* BB Do we need a cast or hash here ? */
3079 if (count != 16) {
3080 cFYI(1, ("Illegal size ret in GetExtAttr"));
3081 rc = -EIO;
3082 goto GetExtAttrOut;
3084 pfinfo = (struct file_chattr_info *)
3085 (data_offset + (char *) &pSMBr->hdr.Protocol);
3086 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3087 *pMask = le64_to_cpu(pfinfo->mask);
3090 GetExtAttrOut:
3091 cifs_buf_release(pSMB);
3092 if (rc == -EAGAIN)
3093 goto GetExtAttrRetry;
3094 return rc;
3097 #endif /* CONFIG_POSIX */
3099 #ifdef CONFIG_CIFS_EXPERIMENTAL
3100 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3102 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3103 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3105 int rc = 0;
3106 int buf_type = 0;
3107 QUERY_SEC_DESC_REQ *pSMB;
3108 struct kvec iov[1];
3110 cFYI(1, ("GetCifsACL"));
3112 *pbuflen = 0;
3113 *acl_inf = NULL;
3115 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3116 8 /* parm len */, tcon, (void **) &pSMB);
3117 if (rc)
3118 return rc;
3120 pSMB->MaxParameterCount = cpu_to_le32(4);
3121 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3122 pSMB->MaxSetupCount = 0;
3123 pSMB->Fid = fid; /* file handle always le */
3124 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3125 CIFS_ACL_DACL);
3126 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3127 pSMB->hdr.smb_buf_length += 11;
3128 iov[0].iov_base = (char *)pSMB;
3129 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3131 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3132 CIFS_STD_OP);
3133 cifs_stats_inc(&tcon->num_acl_get);
3134 if (rc) {
3135 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3136 } else { /* decode response */
3137 __le32 *parm;
3138 __u32 parm_len;
3139 __u32 acl_len;
3140 struct smb_com_ntransact_rsp *pSMBr;
3141 char *pdata;
3143 /* validate_nttransact */
3144 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3145 &pdata, &parm_len, pbuflen);
3146 if (rc)
3147 goto qsec_out;
3148 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3150 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3152 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3153 rc = -EIO; /* bad smb */
3154 *pbuflen = 0;
3155 goto qsec_out;
3158 /* BB check that data area is minimum length and as big as acl_len */
3160 acl_len = le32_to_cpu(*parm);
3161 if (acl_len != *pbuflen) {
3162 cERROR(1, ("acl length %d does not match %d",
3163 acl_len, *pbuflen));
3164 if (*pbuflen > acl_len)
3165 *pbuflen = acl_len;
3168 /* check if buffer is big enough for the acl
3169 header followed by the smallest SID */
3170 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3171 (*pbuflen >= 64 * 1024)) {
3172 cERROR(1, ("bad acl length %d", *pbuflen));
3173 rc = -EINVAL;
3174 *pbuflen = 0;
3175 } else {
3176 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3177 if (*acl_inf == NULL) {
3178 *pbuflen = 0;
3179 rc = -ENOMEM;
3181 memcpy(*acl_inf, pdata, *pbuflen);
3184 qsec_out:
3185 if (buf_type == CIFS_SMALL_BUFFER)
3186 cifs_small_buf_release(iov[0].iov_base);
3187 else if (buf_type == CIFS_LARGE_BUFFER)
3188 cifs_buf_release(iov[0].iov_base);
3189 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3190 return rc;
3194 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3195 struct cifs_ntsd *pntsd, __u32 acllen)
3197 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3198 int rc = 0;
3199 int bytes_returned = 0;
3200 SET_SEC_DESC_REQ *pSMB = NULL;
3201 NTRANSACT_RSP *pSMBr = NULL;
3203 setCifsAclRetry:
3204 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3205 (void **) &pSMBr);
3206 if (rc)
3207 return (rc);
3209 pSMB->MaxSetupCount = 0;
3210 pSMB->Reserved = 0;
3212 param_count = 8;
3213 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3214 data_count = acllen;
3215 data_offset = param_offset + param_count;
3216 byte_count = 3 /* pad */ + param_count;
3218 pSMB->DataCount = cpu_to_le32(data_count);
3219 pSMB->TotalDataCount = pSMB->DataCount;
3220 pSMB->MaxParameterCount = cpu_to_le32(4);
3221 pSMB->MaxDataCount = cpu_to_le32(16384);
3222 pSMB->ParameterCount = cpu_to_le32(param_count);
3223 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3224 pSMB->TotalParameterCount = pSMB->ParameterCount;
3225 pSMB->DataOffset = cpu_to_le32(data_offset);
3226 pSMB->SetupCount = 0;
3227 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3228 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3230 pSMB->Fid = fid; /* file handle always le */
3231 pSMB->Reserved2 = 0;
3232 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3234 if (pntsd && acllen) {
3235 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3236 (char *) pntsd,
3237 acllen);
3238 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3240 } else
3241 pSMB->hdr.smb_buf_length += byte_count;
3243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3246 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3247 if (rc)
3248 cFYI(1, ("Set CIFS ACL returned %d", rc));
3249 cifs_buf_release(pSMB);
3251 if (rc == -EAGAIN)
3252 goto setCifsAclRetry;
3254 return (rc);
3257 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3259 /* Legacy Query Path Information call for lookup to old servers such
3260 as Win9x/WinME */
3261 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3262 const unsigned char *searchName,
3263 FILE_ALL_INFO *pFinfo,
3264 const struct nls_table *nls_codepage, int remap)
3266 QUERY_INFORMATION_REQ *pSMB;
3267 QUERY_INFORMATION_RSP *pSMBr;
3268 int rc = 0;
3269 int bytes_returned;
3270 int name_len;
3272 cFYI(1, ("In SMBQPath path %s", searchName));
3273 QInfRetry:
3274 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3275 (void **) &pSMBr);
3276 if (rc)
3277 return rc;
3279 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3280 name_len =
3281 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3282 PATH_MAX, nls_codepage, remap);
3283 name_len++; /* trailing null */
3284 name_len *= 2;
3285 } else {
3286 name_len = strnlen(searchName, PATH_MAX);
3287 name_len++; /* trailing null */
3288 strncpy(pSMB->FileName, searchName, name_len);
3290 pSMB->BufferFormat = 0x04;
3291 name_len++; /* account for buffer type byte */
3292 pSMB->hdr.smb_buf_length += (__u16) name_len;
3293 pSMB->ByteCount = cpu_to_le16(name_len);
3295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3297 if (rc) {
3298 cFYI(1, ("Send error in QueryInfo = %d", rc));
3299 } else if (pFinfo) {
3300 struct timespec ts;
3301 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3303 /* decode response */
3304 /* BB FIXME - add time zone adjustment BB */
3305 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3306 ts.tv_nsec = 0;
3307 ts.tv_sec = time;
3308 /* decode time fields */
3309 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3310 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3311 pFinfo->LastAccessTime = 0;
3312 pFinfo->AllocationSize =
3313 cpu_to_le64(le32_to_cpu(pSMBr->size));
3314 pFinfo->EndOfFile = pFinfo->AllocationSize;
3315 pFinfo->Attributes =
3316 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3317 } else
3318 rc = -EIO; /* bad buffer passed in */
3320 cifs_buf_release(pSMB);
3322 if (rc == -EAGAIN)
3323 goto QInfRetry;
3325 return rc;
3332 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3333 const unsigned char *searchName,
3334 FILE_ALL_INFO *pFindData,
3335 int legacy /* old style infolevel */,
3336 const struct nls_table *nls_codepage, int remap)
3338 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3339 TRANSACTION2_QPI_REQ *pSMB = NULL;
3340 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3341 int rc = 0;
3342 int bytes_returned;
3343 int name_len;
3344 __u16 params, byte_count;
3346 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3347 QPathInfoRetry:
3348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3349 (void **) &pSMBr);
3350 if (rc)
3351 return rc;
3353 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3354 name_len =
3355 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3356 PATH_MAX, nls_codepage, remap);
3357 name_len++; /* trailing null */
3358 name_len *= 2;
3359 } else { /* BB improve the check for buffer overruns BB */
3360 name_len = strnlen(searchName, PATH_MAX);
3361 name_len++; /* trailing null */
3362 strncpy(pSMB->FileName, searchName, name_len);
3365 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3366 pSMB->TotalDataCount = 0;
3367 pSMB->MaxParameterCount = cpu_to_le16(2);
3368 /* BB find exact max SMB PDU from sess structure BB */
3369 pSMB->MaxDataCount = cpu_to_le16(4000);
3370 pSMB->MaxSetupCount = 0;
3371 pSMB->Reserved = 0;
3372 pSMB->Flags = 0;
3373 pSMB->Timeout = 0;
3374 pSMB->Reserved2 = 0;
3375 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3376 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3377 pSMB->DataCount = 0;
3378 pSMB->DataOffset = 0;
3379 pSMB->SetupCount = 1;
3380 pSMB->Reserved3 = 0;
3381 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3382 byte_count = params + 1 /* pad */ ;
3383 pSMB->TotalParameterCount = cpu_to_le16(params);
3384 pSMB->ParameterCount = pSMB->TotalParameterCount;
3385 if (legacy)
3386 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3387 else
3388 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3389 pSMB->Reserved4 = 0;
3390 pSMB->hdr.smb_buf_length += byte_count;
3391 pSMB->ByteCount = cpu_to_le16(byte_count);
3393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3395 if (rc) {
3396 cFYI(1, ("Send error in QPathInfo = %d", rc));
3397 } else { /* decode response */
3398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3400 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3401 rc = -EIO;
3402 else if (!legacy && (pSMBr->ByteCount < 40))
3403 rc = -EIO; /* bad smb */
3404 else if (legacy && (pSMBr->ByteCount < 24))
3405 rc = -EIO; /* 24 or 26 expected but we do not read
3406 last field */
3407 else if (pFindData) {
3408 int size;
3409 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3411 /* On legacy responses we do not read the last field,
3412 EAsize, fortunately since it varies by subdialect and
3413 also note it differs on Set vs. Get, ie two bytes or 4
3414 bytes depending but we don't care here */
3415 if (legacy)
3416 size = sizeof(FILE_INFO_STANDARD);
3417 else
3418 size = sizeof(FILE_ALL_INFO);
3419 memcpy((char *) pFindData,
3420 (char *) &pSMBr->hdr.Protocol +
3421 data_offset, size);
3422 } else
3423 rc = -ENOMEM;
3425 cifs_buf_release(pSMB);
3426 if (rc == -EAGAIN)
3427 goto QPathInfoRetry;
3429 return rc;
3433 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3434 const unsigned char *searchName,
3435 FILE_UNIX_BASIC_INFO *pFindData,
3436 const struct nls_table *nls_codepage, int remap)
3438 /* SMB_QUERY_FILE_UNIX_BASIC */
3439 TRANSACTION2_QPI_REQ *pSMB = NULL;
3440 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3441 int rc = 0;
3442 int bytes_returned = 0;
3443 int name_len;
3444 __u16 params, byte_count;
3446 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3447 UnixQPathInfoRetry:
3448 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3449 (void **) &pSMBr);
3450 if (rc)
3451 return rc;
3453 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3454 name_len =
3455 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3456 PATH_MAX, nls_codepage, remap);
3457 name_len++; /* trailing null */
3458 name_len *= 2;
3459 } else { /* BB improve the check for buffer overruns BB */
3460 name_len = strnlen(searchName, PATH_MAX);
3461 name_len++; /* trailing null */
3462 strncpy(pSMB->FileName, searchName, name_len);
3465 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3466 pSMB->TotalDataCount = 0;
3467 pSMB->MaxParameterCount = cpu_to_le16(2);
3468 /* BB find exact max SMB PDU from sess structure BB */
3469 pSMB->MaxDataCount = cpu_to_le16(4000);
3470 pSMB->MaxSetupCount = 0;
3471 pSMB->Reserved = 0;
3472 pSMB->Flags = 0;
3473 pSMB->Timeout = 0;
3474 pSMB->Reserved2 = 0;
3475 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3476 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3477 pSMB->DataCount = 0;
3478 pSMB->DataOffset = 0;
3479 pSMB->SetupCount = 1;
3480 pSMB->Reserved3 = 0;
3481 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3482 byte_count = params + 1 /* pad */ ;
3483 pSMB->TotalParameterCount = cpu_to_le16(params);
3484 pSMB->ParameterCount = pSMB->TotalParameterCount;
3485 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3486 pSMB->Reserved4 = 0;
3487 pSMB->hdr.smb_buf_length += byte_count;
3488 pSMB->ByteCount = cpu_to_le16(byte_count);
3490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3492 if (rc) {
3493 cFYI(1, ("Send error in QPathInfo = %d", rc));
3494 } else { /* decode response */
3495 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3497 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3498 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3499 "Unix Extensions can be disabled on mount "
3500 "by specifying the nosfu mount option."));
3501 rc = -EIO; /* bad smb */
3502 } else {
3503 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3504 memcpy((char *) pFindData,
3505 (char *) &pSMBr->hdr.Protocol +
3506 data_offset,
3507 sizeof(FILE_UNIX_BASIC_INFO));
3510 cifs_buf_release(pSMB);
3511 if (rc == -EAGAIN)
3512 goto UnixQPathInfoRetry;
3514 return rc;
3517 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3519 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3520 const char *searchName,
3521 const struct nls_table *nls_codepage,
3522 __u16 *pnetfid,
3523 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3525 /* level 257 SMB_ */
3526 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3527 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3528 T2_FFIRST_RSP_PARMS *parms;
3529 int rc = 0;
3530 int bytes_returned = 0;
3531 int name_len;
3532 __u16 params, byte_count;
3534 cFYI(1, ("In FindFirst for %s", searchName));
3536 findFirstRetry:
3537 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3538 (void **) &pSMBr);
3539 if (rc)
3540 return rc;
3542 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3543 name_len =
3544 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3545 PATH_MAX, nls_codepage, remap);
3546 /* We can not add the asterik earlier in case
3547 it got remapped to 0xF03A as if it were part of the
3548 directory name instead of a wildcard */
3549 name_len *= 2;
3550 pSMB->FileName[name_len] = dirsep;
3551 pSMB->FileName[name_len+1] = 0;
3552 pSMB->FileName[name_len+2] = '*';
3553 pSMB->FileName[name_len+3] = 0;
3554 name_len += 4; /* now the trailing null */
3555 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3556 pSMB->FileName[name_len+1] = 0;
3557 name_len += 2;
3558 } else { /* BB add check for overrun of SMB buf BB */
3559 name_len = strnlen(searchName, PATH_MAX);
3560 /* BB fix here and in unicode clause above ie
3561 if (name_len > buffersize-header)
3562 free buffer exit; BB */
3563 strncpy(pSMB->FileName, searchName, name_len);
3564 pSMB->FileName[name_len] = dirsep;
3565 pSMB->FileName[name_len+1] = '*';
3566 pSMB->FileName[name_len+2] = 0;
3567 name_len += 3;
3570 params = 12 + name_len /* includes null */ ;
3571 pSMB->TotalDataCount = 0; /* no EAs */
3572 pSMB->MaxParameterCount = cpu_to_le16(10);
3573 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3574 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3575 pSMB->MaxSetupCount = 0;
3576 pSMB->Reserved = 0;
3577 pSMB->Flags = 0;
3578 pSMB->Timeout = 0;
3579 pSMB->Reserved2 = 0;
3580 byte_count = params + 1 /* pad */ ;
3581 pSMB->TotalParameterCount = cpu_to_le16(params);
3582 pSMB->ParameterCount = pSMB->TotalParameterCount;
3583 pSMB->ParameterOffset = cpu_to_le16(
3584 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3585 - 4);
3586 pSMB->DataCount = 0;
3587 pSMB->DataOffset = 0;
3588 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3589 pSMB->Reserved3 = 0;
3590 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3591 pSMB->SearchAttributes =
3592 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3593 ATTR_DIRECTORY);
3594 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3595 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3596 CIFS_SEARCH_RETURN_RESUME);
3597 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3599 /* BB what should we set StorageType to? Does it matter? BB */
3600 pSMB->SearchStorageType = 0;
3601 pSMB->hdr.smb_buf_length += byte_count;
3602 pSMB->ByteCount = cpu_to_le16(byte_count);
3604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3606 cifs_stats_inc(&tcon->num_ffirst);
3608 if (rc) {/* BB add logic to retry regular search if Unix search
3609 rejected unexpectedly by server */
3610 /* BB Add code to handle unsupported level rc */
3611 cFYI(1, ("Error in FindFirst = %d", rc));
3613 cifs_buf_release(pSMB);
3615 /* BB eventually could optimize out free and realloc of buf */
3616 /* for this case */
3617 if (rc == -EAGAIN)
3618 goto findFirstRetry;
3619 } else { /* decode response */
3620 /* BB remember to free buffer if error BB */
3621 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3622 if (rc == 0) {
3623 unsigned int lnoff;
3625 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3626 psrch_inf->unicode = true;
3627 else
3628 psrch_inf->unicode = false;
3630 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3631 psrch_inf->smallBuf = 0;
3632 psrch_inf->srch_entries_start =
3633 (char *) &pSMBr->hdr.Protocol +
3634 le16_to_cpu(pSMBr->t2.DataOffset);
3635 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3636 le16_to_cpu(pSMBr->t2.ParameterOffset));
3638 if (parms->EndofSearch)
3639 psrch_inf->endOfSearch = true;
3640 else
3641 psrch_inf->endOfSearch = false;
3643 psrch_inf->entries_in_buffer =
3644 le16_to_cpu(parms->SearchCount);
3645 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3646 psrch_inf->entries_in_buffer;
3647 lnoff = le16_to_cpu(parms->LastNameOffset);
3648 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3649 lnoff) {
3650 cERROR(1, ("ignoring corrupt resume name"));
3651 psrch_inf->last_entry = NULL;
3652 return rc;
3655 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3656 lnoff;
3658 *pnetfid = parms->SearchHandle;
3659 } else {
3660 cifs_buf_release(pSMB);
3664 return rc;
3667 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3668 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3670 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3671 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3672 T2_FNEXT_RSP_PARMS *parms;
3673 char *response_data;
3674 int rc = 0;
3675 int bytes_returned, name_len;
3676 __u16 params, byte_count;
3678 cFYI(1, ("In FindNext"));
3680 if (psrch_inf->endOfSearch)
3681 return -ENOENT;
3683 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3684 (void **) &pSMBr);
3685 if (rc)
3686 return rc;
3688 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3689 byte_count = 0;
3690 pSMB->TotalDataCount = 0; /* no EAs */
3691 pSMB->MaxParameterCount = cpu_to_le16(8);
3692 pSMB->MaxDataCount =
3693 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3694 0xFFFFFF00);
3695 pSMB->MaxSetupCount = 0;
3696 pSMB->Reserved = 0;
3697 pSMB->Flags = 0;
3698 pSMB->Timeout = 0;
3699 pSMB->Reserved2 = 0;
3700 pSMB->ParameterOffset = cpu_to_le16(
3701 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3702 pSMB->DataCount = 0;
3703 pSMB->DataOffset = 0;
3704 pSMB->SetupCount = 1;
3705 pSMB->Reserved3 = 0;
3706 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3707 pSMB->SearchHandle = searchHandle; /* always kept as le */
3708 pSMB->SearchCount =
3709 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3710 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3711 pSMB->ResumeKey = psrch_inf->resume_key;
3712 pSMB->SearchFlags =
3713 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3715 name_len = psrch_inf->resume_name_len;
3716 params += name_len;
3717 if (name_len < PATH_MAX) {
3718 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3719 byte_count += name_len;
3720 /* 14 byte parm len above enough for 2 byte null terminator */
3721 pSMB->ResumeFileName[name_len] = 0;
3722 pSMB->ResumeFileName[name_len+1] = 0;
3723 } else {
3724 rc = -EINVAL;
3725 goto FNext2_err_exit;
3727 byte_count = params + 1 /* pad */ ;
3728 pSMB->TotalParameterCount = cpu_to_le16(params);
3729 pSMB->ParameterCount = pSMB->TotalParameterCount;
3730 pSMB->hdr.smb_buf_length += byte_count;
3731 pSMB->ByteCount = cpu_to_le16(byte_count);
3733 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3734 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3735 cifs_stats_inc(&tcon->num_fnext);
3736 if (rc) {
3737 if (rc == -EBADF) {
3738 psrch_inf->endOfSearch = true;
3739 cifs_buf_release(pSMB);
3740 rc = 0; /* search probably was closed at end of search*/
3741 } else
3742 cFYI(1, ("FindNext returned = %d", rc));
3743 } else { /* decode response */
3744 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3746 if (rc == 0) {
3747 unsigned int lnoff;
3749 /* BB fixme add lock for file (srch_info) struct here */
3750 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3751 psrch_inf->unicode = true;
3752 else
3753 psrch_inf->unicode = false;
3754 response_data = (char *) &pSMBr->hdr.Protocol +
3755 le16_to_cpu(pSMBr->t2.ParameterOffset);
3756 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3757 response_data = (char *)&pSMBr->hdr.Protocol +
3758 le16_to_cpu(pSMBr->t2.DataOffset);
3759 if (psrch_inf->smallBuf)
3760 cifs_small_buf_release(
3761 psrch_inf->ntwrk_buf_start);
3762 else
3763 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3764 psrch_inf->srch_entries_start = response_data;
3765 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3766 psrch_inf->smallBuf = 0;
3767 if (parms->EndofSearch)
3768 psrch_inf->endOfSearch = true;
3769 else
3770 psrch_inf->endOfSearch = false;
3771 psrch_inf->entries_in_buffer =
3772 le16_to_cpu(parms->SearchCount);
3773 psrch_inf->index_of_last_entry +=
3774 psrch_inf->entries_in_buffer;
3775 lnoff = le16_to_cpu(parms->LastNameOffset);
3776 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3777 lnoff) {
3778 cERROR(1, ("ignoring corrupt resume name"));
3779 psrch_inf->last_entry = NULL;
3780 return rc;
3781 } else
3782 psrch_inf->last_entry =
3783 psrch_inf->srch_entries_start + lnoff;
3785 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3786 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3788 /* BB fixme add unlock here */
3793 /* BB On error, should we leave previous search buf (and count and
3794 last entry fields) intact or free the previous one? */
3796 /* Note: On -EAGAIN error only caller can retry on handle based calls
3797 since file handle passed in no longer valid */
3798 FNext2_err_exit:
3799 if (rc != 0)
3800 cifs_buf_release(pSMB);
3801 return rc;
3805 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3806 const __u16 searchHandle)
3808 int rc = 0;
3809 FINDCLOSE_REQ *pSMB = NULL;
3811 cFYI(1, ("In CIFSSMBFindClose"));
3812 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3814 /* no sense returning error if session restarted
3815 as file handle has been closed */
3816 if (rc == -EAGAIN)
3817 return 0;
3818 if (rc)
3819 return rc;
3821 pSMB->FileID = searchHandle;
3822 pSMB->ByteCount = 0;
3823 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3824 if (rc)
3825 cERROR(1, ("Send error in FindClose = %d", rc));
3827 cifs_stats_inc(&tcon->num_fclose);
3829 /* Since session is dead, search handle closed on server already */
3830 if (rc == -EAGAIN)
3831 rc = 0;
3833 return rc;
3837 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3838 const unsigned char *searchName,
3839 __u64 *inode_number,
3840 const struct nls_table *nls_codepage, int remap)
3842 int rc = 0;
3843 TRANSACTION2_QPI_REQ *pSMB = NULL;
3844 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3845 int name_len, bytes_returned;
3846 __u16 params, byte_count;
3848 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3849 if (tcon == NULL)
3850 return -ENODEV;
3852 GetInodeNumberRetry:
3853 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3854 (void **) &pSMBr);
3855 if (rc)
3856 return rc;
3858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3859 name_len =
3860 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3861 PATH_MAX, nls_codepage, remap);
3862 name_len++; /* trailing null */
3863 name_len *= 2;
3864 } else { /* BB improve the check for buffer overruns BB */
3865 name_len = strnlen(searchName, PATH_MAX);
3866 name_len++; /* trailing null */
3867 strncpy(pSMB->FileName, searchName, name_len);
3870 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3871 pSMB->TotalDataCount = 0;
3872 pSMB->MaxParameterCount = cpu_to_le16(2);
3873 /* BB find exact max data count below from sess structure BB */
3874 pSMB->MaxDataCount = cpu_to_le16(4000);
3875 pSMB->MaxSetupCount = 0;
3876 pSMB->Reserved = 0;
3877 pSMB->Flags = 0;
3878 pSMB->Timeout = 0;
3879 pSMB->Reserved2 = 0;
3880 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3881 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3882 pSMB->DataCount = 0;
3883 pSMB->DataOffset = 0;
3884 pSMB->SetupCount = 1;
3885 pSMB->Reserved3 = 0;
3886 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3887 byte_count = params + 1 /* pad */ ;
3888 pSMB->TotalParameterCount = cpu_to_le16(params);
3889 pSMB->ParameterCount = pSMB->TotalParameterCount;
3890 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3891 pSMB->Reserved4 = 0;
3892 pSMB->hdr.smb_buf_length += byte_count;
3893 pSMB->ByteCount = cpu_to_le16(byte_count);
3895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3897 if (rc) {
3898 cFYI(1, ("error %d in QueryInternalInfo", rc));
3899 } else {
3900 /* decode response */
3901 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3902 if (rc || (pSMBr->ByteCount < 2))
3903 /* BB also check enough total bytes returned */
3904 /* If rc should we check for EOPNOSUPP and
3905 disable the srvino flag? or in caller? */
3906 rc = -EIO; /* bad smb */
3907 else {
3908 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3909 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3910 struct file_internal_info *pfinfo;
3911 /* BB Do we need a cast or hash here ? */
3912 if (count < 8) {
3913 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3914 rc = -EIO;
3915 goto GetInodeNumOut;
3917 pfinfo = (struct file_internal_info *)
3918 (data_offset + (char *) &pSMBr->hdr.Protocol);
3919 *inode_number = pfinfo->UniqueId;
3922 GetInodeNumOut:
3923 cifs_buf_release(pSMB);
3924 if (rc == -EAGAIN)
3925 goto GetInodeNumberRetry;
3926 return rc;
3929 /* computes length of UCS string converted to host codepage
3930 * @src: UCS string
3931 * @maxlen: length of the input string in UCS characters
3932 * (not in bytes)
3934 * return: size of input string in host codepage
3936 static int hostlen_fromUCS(const __le16 *src, const int maxlen,
3937 const struct nls_table *nls_codepage) {
3938 int i;
3939 int hostlen = 0;
3940 char to[4];
3941 int charlen;
3942 for (i = 0; (i < maxlen) && src[i]; ++i) {
3943 charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
3944 to, NLS_MAX_CHARSET_SIZE);
3945 hostlen += charlen > 0 ? charlen : 1;
3947 return hostlen;
3950 /* parses DFS refferal V3 structure
3951 * caller is responsible for freeing target_nodes
3952 * returns:
3953 * on success - 0
3954 * on failure - errno
3956 static int
3957 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3958 unsigned int *num_of_nodes,
3959 struct dfs_info3_param **target_nodes,
3960 const struct nls_table *nls_codepage, int remap,
3961 const char *searchName)
3963 int i, rc = 0;
3964 char *data_end;
3965 bool is_unicode;
3966 struct dfs_referral_level_3 *ref;
3968 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3969 is_unicode = true;
3970 else
3971 is_unicode = false;
3972 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3974 if (*num_of_nodes < 1) {
3975 cERROR(1, ("num_referrals: must be at least > 0,"
3976 "but we get num_referrals = %d\n", *num_of_nodes));
3977 rc = -EINVAL;
3978 goto parse_DFS_referrals_exit;
3981 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3982 if (ref->VersionNumber != cpu_to_le16(3)) {
3983 cERROR(1, ("Referrals of V%d version are not supported,"
3984 "should be V3", le16_to_cpu(ref->VersionNumber)));
3985 rc = -EINVAL;
3986 goto parse_DFS_referrals_exit;
3989 /* get the upper boundary of the resp buffer */
3990 data_end = (char *)(&(pSMBr->PathConsumed)) +
3991 le16_to_cpu(pSMBr->t2.DataCount);
3993 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3994 *num_of_nodes,
3995 le16_to_cpu(pSMBr->DFSFlags)));
3997 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3998 *num_of_nodes, GFP_KERNEL);
3999 if (*target_nodes == NULL) {
4000 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
4001 rc = -ENOMEM;
4002 goto parse_DFS_referrals_exit;
4005 /* collect neccessary data from referrals */
4006 for (i = 0; i < *num_of_nodes; i++) {
4007 char *temp;
4008 int max_len;
4009 struct dfs_info3_param *node = (*target_nodes)+i;
4011 node->flags = le16_to_cpu(pSMBr->DFSFlags);
4012 if (is_unicode) {
4013 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4014 GFP_KERNEL);
4015 cifsConvertToUCS((__le16 *) tmp, searchName,
4016 PATH_MAX, nls_codepage, remap);
4017 node->path_consumed = hostlen_fromUCS(tmp,
4018 le16_to_cpu(pSMBr->PathConsumed)/2,
4019 nls_codepage);
4020 kfree(tmp);
4021 } else
4022 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4024 node->server_type = le16_to_cpu(ref->ServerType);
4025 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4027 /* copy DfsPath */
4028 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4029 max_len = data_end - temp;
4030 rc = cifs_strncpy_to_host(&(node->path_name), temp,
4031 max_len, is_unicode, nls_codepage);
4032 if (rc)
4033 goto parse_DFS_referrals_exit;
4035 /* copy link target UNC */
4036 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4037 max_len = data_end - temp;
4038 rc = cifs_strncpy_to_host(&(node->node_name), temp,
4039 max_len, is_unicode, nls_codepage);
4040 if (rc)
4041 goto parse_DFS_referrals_exit;
4043 ref += le16_to_cpu(ref->Size);
4046 parse_DFS_referrals_exit:
4047 if (rc) {
4048 free_dfs_info_array(*target_nodes, *num_of_nodes);
4049 *target_nodes = NULL;
4050 *num_of_nodes = 0;
4052 return rc;
4056 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4057 const unsigned char *searchName,
4058 struct dfs_info3_param **target_nodes,
4059 unsigned int *num_of_nodes,
4060 const struct nls_table *nls_codepage, int remap)
4062 /* TRANS2_GET_DFS_REFERRAL */
4063 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4064 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4065 int rc = 0;
4066 int bytes_returned;
4067 int name_len;
4068 __u16 params, byte_count;
4069 *num_of_nodes = 0;
4070 *target_nodes = NULL;
4072 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4073 if (ses == NULL)
4074 return -ENODEV;
4075 getDFSRetry:
4076 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4077 (void **) &pSMBr);
4078 if (rc)
4079 return rc;
4081 /* server pointer checked in called function,
4082 but should never be null here anyway */
4083 pSMB->hdr.Mid = GetNextMid(ses->server);
4084 pSMB->hdr.Tid = ses->ipc_tid;
4085 pSMB->hdr.Uid = ses->Suid;
4086 if (ses->capabilities & CAP_STATUS32)
4087 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4088 if (ses->capabilities & CAP_DFS)
4089 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4091 if (ses->capabilities & CAP_UNICODE) {
4092 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4093 name_len =
4094 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4095 searchName, PATH_MAX, nls_codepage, remap);
4096 name_len++; /* trailing null */
4097 name_len *= 2;
4098 } else { /* BB improve the check for buffer overruns BB */
4099 name_len = strnlen(searchName, PATH_MAX);
4100 name_len++; /* trailing null */
4101 strncpy(pSMB->RequestFileName, searchName, name_len);
4104 if (ses->server) {
4105 if (ses->server->secMode &
4106 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4107 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4110 pSMB->hdr.Uid = ses->Suid;
4112 params = 2 /* level */ + name_len /*includes null */ ;
4113 pSMB->TotalDataCount = 0;
4114 pSMB->DataCount = 0;
4115 pSMB->DataOffset = 0;
4116 pSMB->MaxParameterCount = 0;
4117 /* BB find exact max SMB PDU from sess structure BB */
4118 pSMB->MaxDataCount = cpu_to_le16(4000);
4119 pSMB->MaxSetupCount = 0;
4120 pSMB->Reserved = 0;
4121 pSMB->Flags = 0;
4122 pSMB->Timeout = 0;
4123 pSMB->Reserved2 = 0;
4124 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4125 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4126 pSMB->SetupCount = 1;
4127 pSMB->Reserved3 = 0;
4128 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4129 byte_count = params + 3 /* pad */ ;
4130 pSMB->ParameterCount = cpu_to_le16(params);
4131 pSMB->TotalParameterCount = pSMB->ParameterCount;
4132 pSMB->MaxReferralLevel = cpu_to_le16(3);
4133 pSMB->hdr.smb_buf_length += byte_count;
4134 pSMB->ByteCount = cpu_to_le16(byte_count);
4136 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4138 if (rc) {
4139 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4140 goto GetDFSRefExit;
4142 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4144 /* BB Also check if enough total bytes returned? */
4145 if (rc || (pSMBr->ByteCount < 17)) {
4146 rc = -EIO; /* bad smb */
4147 goto GetDFSRefExit;
4150 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4151 pSMBr->ByteCount,
4152 le16_to_cpu(pSMBr->t2.DataOffset)));
4154 /* parse returned result into more usable form */
4155 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4156 target_nodes, nls_codepage, remap,
4157 searchName);
4159 GetDFSRefExit:
4160 cifs_buf_release(pSMB);
4162 if (rc == -EAGAIN)
4163 goto getDFSRetry;
4165 return rc;
4168 /* Query File System Info such as free space to old servers such as Win 9x */
4170 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4172 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4173 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4174 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4175 FILE_SYSTEM_ALLOC_INFO *response_data;
4176 int rc = 0;
4177 int bytes_returned = 0;
4178 __u16 params, byte_count;
4180 cFYI(1, ("OldQFSInfo"));
4181 oldQFSInfoRetry:
4182 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4183 (void **) &pSMBr);
4184 if (rc)
4185 return rc;
4187 params = 2; /* level */
4188 pSMB->TotalDataCount = 0;
4189 pSMB->MaxParameterCount = cpu_to_le16(2);
4190 pSMB->MaxDataCount = cpu_to_le16(1000);
4191 pSMB->MaxSetupCount = 0;
4192 pSMB->Reserved = 0;
4193 pSMB->Flags = 0;
4194 pSMB->Timeout = 0;
4195 pSMB->Reserved2 = 0;
4196 byte_count = params + 1 /* pad */ ;
4197 pSMB->TotalParameterCount = cpu_to_le16(params);
4198 pSMB->ParameterCount = pSMB->TotalParameterCount;
4199 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4200 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4201 pSMB->DataCount = 0;
4202 pSMB->DataOffset = 0;
4203 pSMB->SetupCount = 1;
4204 pSMB->Reserved3 = 0;
4205 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4206 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4207 pSMB->hdr.smb_buf_length += byte_count;
4208 pSMB->ByteCount = cpu_to_le16(byte_count);
4210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4212 if (rc) {
4213 cFYI(1, ("Send error in QFSInfo = %d", rc));
4214 } else { /* decode response */
4215 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4217 if (rc || (pSMBr->ByteCount < 18))
4218 rc = -EIO; /* bad smb */
4219 else {
4220 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4221 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4222 pSMBr->ByteCount, data_offset));
4224 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4225 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4226 FSData->f_bsize =
4227 le16_to_cpu(response_data->BytesPerSector) *
4228 le32_to_cpu(response_data->
4229 SectorsPerAllocationUnit);
4230 FSData->f_blocks =
4231 le32_to_cpu(response_data->TotalAllocationUnits);
4232 FSData->f_bfree = FSData->f_bavail =
4233 le32_to_cpu(response_data->FreeAllocationUnits);
4234 cFYI(1,
4235 ("Blocks: %lld Free: %lld Block size %ld",
4236 (unsigned long long)FSData->f_blocks,
4237 (unsigned long long)FSData->f_bfree,
4238 FSData->f_bsize));
4241 cifs_buf_release(pSMB);
4243 if (rc == -EAGAIN)
4244 goto oldQFSInfoRetry;
4246 return rc;
4250 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4252 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4253 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4254 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4255 FILE_SYSTEM_INFO *response_data;
4256 int rc = 0;
4257 int bytes_returned = 0;
4258 __u16 params, byte_count;
4260 cFYI(1, ("In QFSInfo"));
4261 QFSInfoRetry:
4262 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4263 (void **) &pSMBr);
4264 if (rc)
4265 return rc;
4267 params = 2; /* level */
4268 pSMB->TotalDataCount = 0;
4269 pSMB->MaxParameterCount = cpu_to_le16(2);
4270 pSMB->MaxDataCount = cpu_to_le16(1000);
4271 pSMB->MaxSetupCount = 0;
4272 pSMB->Reserved = 0;
4273 pSMB->Flags = 0;
4274 pSMB->Timeout = 0;
4275 pSMB->Reserved2 = 0;
4276 byte_count = params + 1 /* pad */ ;
4277 pSMB->TotalParameterCount = cpu_to_le16(params);
4278 pSMB->ParameterCount = pSMB->TotalParameterCount;
4279 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4280 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4281 pSMB->DataCount = 0;
4282 pSMB->DataOffset = 0;
4283 pSMB->SetupCount = 1;
4284 pSMB->Reserved3 = 0;
4285 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4286 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4287 pSMB->hdr.smb_buf_length += byte_count;
4288 pSMB->ByteCount = cpu_to_le16(byte_count);
4290 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4291 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4292 if (rc) {
4293 cFYI(1, ("Send error in QFSInfo = %d", rc));
4294 } else { /* decode response */
4295 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4297 if (rc || (pSMBr->ByteCount < 24))
4298 rc = -EIO; /* bad smb */
4299 else {
4300 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4302 response_data =
4303 (FILE_SYSTEM_INFO
4304 *) (((char *) &pSMBr->hdr.Protocol) +
4305 data_offset);
4306 FSData->f_bsize =
4307 le32_to_cpu(response_data->BytesPerSector) *
4308 le32_to_cpu(response_data->
4309 SectorsPerAllocationUnit);
4310 FSData->f_blocks =
4311 le64_to_cpu(response_data->TotalAllocationUnits);
4312 FSData->f_bfree = FSData->f_bavail =
4313 le64_to_cpu(response_data->FreeAllocationUnits);
4314 cFYI(1,
4315 ("Blocks: %lld Free: %lld Block size %ld",
4316 (unsigned long long)FSData->f_blocks,
4317 (unsigned long long)FSData->f_bfree,
4318 FSData->f_bsize));
4321 cifs_buf_release(pSMB);
4323 if (rc == -EAGAIN)
4324 goto QFSInfoRetry;
4326 return rc;
4330 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4332 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4333 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4334 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4335 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4336 int rc = 0;
4337 int bytes_returned = 0;
4338 __u16 params, byte_count;
4340 cFYI(1, ("In QFSAttributeInfo"));
4341 QFSAttributeRetry:
4342 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4343 (void **) &pSMBr);
4344 if (rc)
4345 return rc;
4347 params = 2; /* level */
4348 pSMB->TotalDataCount = 0;
4349 pSMB->MaxParameterCount = cpu_to_le16(2);
4350 /* BB find exact max SMB PDU from sess structure BB */
4351 pSMB->MaxDataCount = cpu_to_le16(1000);
4352 pSMB->MaxSetupCount = 0;
4353 pSMB->Reserved = 0;
4354 pSMB->Flags = 0;
4355 pSMB->Timeout = 0;
4356 pSMB->Reserved2 = 0;
4357 byte_count = params + 1 /* pad */ ;
4358 pSMB->TotalParameterCount = cpu_to_le16(params);
4359 pSMB->ParameterCount = pSMB->TotalParameterCount;
4360 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4361 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4362 pSMB->DataCount = 0;
4363 pSMB->DataOffset = 0;
4364 pSMB->SetupCount = 1;
4365 pSMB->Reserved3 = 0;
4366 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4367 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4368 pSMB->hdr.smb_buf_length += byte_count;
4369 pSMB->ByteCount = cpu_to_le16(byte_count);
4371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4372 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4373 if (rc) {
4374 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4375 } else { /* decode response */
4376 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4378 if (rc || (pSMBr->ByteCount < 13)) {
4379 /* BB also check if enough bytes returned */
4380 rc = -EIO; /* bad smb */
4381 } else {
4382 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4383 response_data =
4384 (FILE_SYSTEM_ATTRIBUTE_INFO
4385 *) (((char *) &pSMBr->hdr.Protocol) +
4386 data_offset);
4387 memcpy(&tcon->fsAttrInfo, response_data,
4388 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4391 cifs_buf_release(pSMB);
4393 if (rc == -EAGAIN)
4394 goto QFSAttributeRetry;
4396 return rc;
4400 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4402 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4403 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4404 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4405 FILE_SYSTEM_DEVICE_INFO *response_data;
4406 int rc = 0;
4407 int bytes_returned = 0;
4408 __u16 params, byte_count;
4410 cFYI(1, ("In QFSDeviceInfo"));
4411 QFSDeviceRetry:
4412 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4413 (void **) &pSMBr);
4414 if (rc)
4415 return rc;
4417 params = 2; /* level */
4418 pSMB->TotalDataCount = 0;
4419 pSMB->MaxParameterCount = cpu_to_le16(2);
4420 /* BB find exact max SMB PDU from sess structure BB */
4421 pSMB->MaxDataCount = cpu_to_le16(1000);
4422 pSMB->MaxSetupCount = 0;
4423 pSMB->Reserved = 0;
4424 pSMB->Flags = 0;
4425 pSMB->Timeout = 0;
4426 pSMB->Reserved2 = 0;
4427 byte_count = params + 1 /* pad */ ;
4428 pSMB->TotalParameterCount = cpu_to_le16(params);
4429 pSMB->ParameterCount = pSMB->TotalParameterCount;
4430 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4431 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4433 pSMB->DataCount = 0;
4434 pSMB->DataOffset = 0;
4435 pSMB->SetupCount = 1;
4436 pSMB->Reserved3 = 0;
4437 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4438 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4439 pSMB->hdr.smb_buf_length += byte_count;
4440 pSMB->ByteCount = cpu_to_le16(byte_count);
4442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4444 if (rc) {
4445 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4446 } else { /* decode response */
4447 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4449 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4450 rc = -EIO; /* bad smb */
4451 else {
4452 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4453 response_data =
4454 (FILE_SYSTEM_DEVICE_INFO *)
4455 (((char *) &pSMBr->hdr.Protocol) +
4456 data_offset);
4457 memcpy(&tcon->fsDevInfo, response_data,
4458 sizeof(FILE_SYSTEM_DEVICE_INFO));
4461 cifs_buf_release(pSMB);
4463 if (rc == -EAGAIN)
4464 goto QFSDeviceRetry;
4466 return rc;
4470 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4472 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4473 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4474 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4475 FILE_SYSTEM_UNIX_INFO *response_data;
4476 int rc = 0;
4477 int bytes_returned = 0;
4478 __u16 params, byte_count;
4480 cFYI(1, ("In QFSUnixInfo"));
4481 QFSUnixRetry:
4482 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4483 (void **) &pSMBr);
4484 if (rc)
4485 return rc;
4487 params = 2; /* level */
4488 pSMB->TotalDataCount = 0;
4489 pSMB->DataCount = 0;
4490 pSMB->DataOffset = 0;
4491 pSMB->MaxParameterCount = cpu_to_le16(2);
4492 /* BB find exact max SMB PDU from sess structure BB */
4493 pSMB->MaxDataCount = cpu_to_le16(100);
4494 pSMB->MaxSetupCount = 0;
4495 pSMB->Reserved = 0;
4496 pSMB->Flags = 0;
4497 pSMB->Timeout = 0;
4498 pSMB->Reserved2 = 0;
4499 byte_count = params + 1 /* pad */ ;
4500 pSMB->ParameterCount = cpu_to_le16(params);
4501 pSMB->TotalParameterCount = pSMB->ParameterCount;
4502 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4503 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4504 pSMB->SetupCount = 1;
4505 pSMB->Reserved3 = 0;
4506 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4507 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4508 pSMB->hdr.smb_buf_length += byte_count;
4509 pSMB->ByteCount = cpu_to_le16(byte_count);
4511 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4512 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4513 if (rc) {
4514 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4515 } else { /* decode response */
4516 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4518 if (rc || (pSMBr->ByteCount < 13)) {
4519 rc = -EIO; /* bad smb */
4520 } else {
4521 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4522 response_data =
4523 (FILE_SYSTEM_UNIX_INFO
4524 *) (((char *) &pSMBr->hdr.Protocol) +
4525 data_offset);
4526 memcpy(&tcon->fsUnixInfo, response_data,
4527 sizeof(FILE_SYSTEM_UNIX_INFO));
4530 cifs_buf_release(pSMB);
4532 if (rc == -EAGAIN)
4533 goto QFSUnixRetry;
4536 return rc;
4540 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4542 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4543 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4544 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4545 int rc = 0;
4546 int bytes_returned = 0;
4547 __u16 params, param_offset, offset, byte_count;
4549 cFYI(1, ("In SETFSUnixInfo"));
4550 SETFSUnixRetry:
4551 /* BB switch to small buf init to save memory */
4552 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4553 (void **) &pSMBr);
4554 if (rc)
4555 return rc;
4557 params = 4; /* 2 bytes zero followed by info level. */
4558 pSMB->MaxSetupCount = 0;
4559 pSMB->Reserved = 0;
4560 pSMB->Flags = 0;
4561 pSMB->Timeout = 0;
4562 pSMB->Reserved2 = 0;
4563 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4564 - 4;
4565 offset = param_offset + params;
4567 pSMB->MaxParameterCount = cpu_to_le16(4);
4568 /* BB find exact max SMB PDU from sess structure BB */
4569 pSMB->MaxDataCount = cpu_to_le16(100);
4570 pSMB->SetupCount = 1;
4571 pSMB->Reserved3 = 0;
4572 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4573 byte_count = 1 /* pad */ + params + 12;
4575 pSMB->DataCount = cpu_to_le16(12);
4576 pSMB->ParameterCount = cpu_to_le16(params);
4577 pSMB->TotalDataCount = pSMB->DataCount;
4578 pSMB->TotalParameterCount = pSMB->ParameterCount;
4579 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4580 pSMB->DataOffset = cpu_to_le16(offset);
4582 /* Params. */
4583 pSMB->FileNum = 0;
4584 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4586 /* Data. */
4587 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4588 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4589 pSMB->ClientUnixCap = cpu_to_le64(cap);
4591 pSMB->hdr.smb_buf_length += byte_count;
4592 pSMB->ByteCount = cpu_to_le16(byte_count);
4594 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4595 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4596 if (rc) {
4597 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4598 } else { /* decode response */
4599 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4600 if (rc)
4601 rc = -EIO; /* bad smb */
4603 cifs_buf_release(pSMB);
4605 if (rc == -EAGAIN)
4606 goto SETFSUnixRetry;
4608 return rc;
4614 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4615 struct kstatfs *FSData)
4617 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4618 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4619 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4620 FILE_SYSTEM_POSIX_INFO *response_data;
4621 int rc = 0;
4622 int bytes_returned = 0;
4623 __u16 params, byte_count;
4625 cFYI(1, ("In QFSPosixInfo"));
4626 QFSPosixRetry:
4627 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4628 (void **) &pSMBr);
4629 if (rc)
4630 return rc;
4632 params = 2; /* level */
4633 pSMB->TotalDataCount = 0;
4634 pSMB->DataCount = 0;
4635 pSMB->DataOffset = 0;
4636 pSMB->MaxParameterCount = cpu_to_le16(2);
4637 /* BB find exact max SMB PDU from sess structure BB */
4638 pSMB->MaxDataCount = cpu_to_le16(100);
4639 pSMB->MaxSetupCount = 0;
4640 pSMB->Reserved = 0;
4641 pSMB->Flags = 0;
4642 pSMB->Timeout = 0;
4643 pSMB->Reserved2 = 0;
4644 byte_count = params + 1 /* pad */ ;
4645 pSMB->ParameterCount = cpu_to_le16(params);
4646 pSMB->TotalParameterCount = pSMB->ParameterCount;
4647 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4648 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4649 pSMB->SetupCount = 1;
4650 pSMB->Reserved3 = 0;
4651 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4652 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4653 pSMB->hdr.smb_buf_length += byte_count;
4654 pSMB->ByteCount = cpu_to_le16(byte_count);
4656 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4657 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4658 if (rc) {
4659 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4660 } else { /* decode response */
4661 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4663 if (rc || (pSMBr->ByteCount < 13)) {
4664 rc = -EIO; /* bad smb */
4665 } else {
4666 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4667 response_data =
4668 (FILE_SYSTEM_POSIX_INFO
4669 *) (((char *) &pSMBr->hdr.Protocol) +
4670 data_offset);
4671 FSData->f_bsize =
4672 le32_to_cpu(response_data->BlockSize);
4673 FSData->f_blocks =
4674 le64_to_cpu(response_data->TotalBlocks);
4675 FSData->f_bfree =
4676 le64_to_cpu(response_data->BlocksAvail);
4677 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4678 FSData->f_bavail = FSData->f_bfree;
4679 } else {
4680 FSData->f_bavail =
4681 le64_to_cpu(response_data->UserBlocksAvail);
4683 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4684 FSData->f_files =
4685 le64_to_cpu(response_data->TotalFileNodes);
4686 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4687 FSData->f_ffree =
4688 le64_to_cpu(response_data->FreeFileNodes);
4691 cifs_buf_release(pSMB);
4693 if (rc == -EAGAIN)
4694 goto QFSPosixRetry;
4696 return rc;
4700 /* We can not use write of zero bytes trick to
4701 set file size due to need for large file support. Also note that
4702 this SetPathInfo is preferred to SetFileInfo based method in next
4703 routine which is only needed to work around a sharing violation bug
4704 in Samba which this routine can run into */
4707 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4708 __u64 size, bool SetAllocation,
4709 const struct nls_table *nls_codepage, int remap)
4711 struct smb_com_transaction2_spi_req *pSMB = NULL;
4712 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4713 struct file_end_of_file_info *parm_data;
4714 int name_len;
4715 int rc = 0;
4716 int bytes_returned = 0;
4717 __u16 params, byte_count, data_count, param_offset, offset;
4719 cFYI(1, ("In SetEOF"));
4720 SetEOFRetry:
4721 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4722 (void **) &pSMBr);
4723 if (rc)
4724 return rc;
4726 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4727 name_len =
4728 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4729 PATH_MAX, nls_codepage, remap);
4730 name_len++; /* trailing null */
4731 name_len *= 2;
4732 } else { /* BB improve the check for buffer overruns BB */
4733 name_len = strnlen(fileName, PATH_MAX);
4734 name_len++; /* trailing null */
4735 strncpy(pSMB->FileName, fileName, name_len);
4737 params = 6 + name_len;
4738 data_count = sizeof(struct file_end_of_file_info);
4739 pSMB->MaxParameterCount = cpu_to_le16(2);
4740 pSMB->MaxDataCount = cpu_to_le16(4100);
4741 pSMB->MaxSetupCount = 0;
4742 pSMB->Reserved = 0;
4743 pSMB->Flags = 0;
4744 pSMB->Timeout = 0;
4745 pSMB->Reserved2 = 0;
4746 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4747 InformationLevel) - 4;
4748 offset = param_offset + params;
4749 if (SetAllocation) {
4750 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4751 pSMB->InformationLevel =
4752 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4753 else
4754 pSMB->InformationLevel =
4755 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4756 } else /* Set File Size */ {
4757 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4758 pSMB->InformationLevel =
4759 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4760 else
4761 pSMB->InformationLevel =
4762 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4765 parm_data =
4766 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4767 offset);
4768 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4769 pSMB->DataOffset = cpu_to_le16(offset);
4770 pSMB->SetupCount = 1;
4771 pSMB->Reserved3 = 0;
4772 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4773 byte_count = 3 /* pad */ + params + data_count;
4774 pSMB->DataCount = cpu_to_le16(data_count);
4775 pSMB->TotalDataCount = pSMB->DataCount;
4776 pSMB->ParameterCount = cpu_to_le16(params);
4777 pSMB->TotalParameterCount = pSMB->ParameterCount;
4778 pSMB->Reserved4 = 0;
4779 pSMB->hdr.smb_buf_length += byte_count;
4780 parm_data->FileSize = cpu_to_le64(size);
4781 pSMB->ByteCount = cpu_to_le16(byte_count);
4782 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4783 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4784 if (rc)
4785 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4787 cifs_buf_release(pSMB);
4789 if (rc == -EAGAIN)
4790 goto SetEOFRetry;
4792 return rc;
4796 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4797 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4799 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4800 char *data_offset;
4801 struct file_end_of_file_info *parm_data;
4802 int rc = 0;
4803 __u16 params, param_offset, offset, byte_count, count;
4805 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4806 (long long)size));
4807 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4809 if (rc)
4810 return rc;
4812 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4813 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4815 params = 6;
4816 pSMB->MaxSetupCount = 0;
4817 pSMB->Reserved = 0;
4818 pSMB->Flags = 0;
4819 pSMB->Timeout = 0;
4820 pSMB->Reserved2 = 0;
4821 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4822 offset = param_offset + params;
4824 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4826 count = sizeof(struct file_end_of_file_info);
4827 pSMB->MaxParameterCount = cpu_to_le16(2);
4828 /* BB find exact max SMB PDU from sess structure BB */
4829 pSMB->MaxDataCount = cpu_to_le16(1000);
4830 pSMB->SetupCount = 1;
4831 pSMB->Reserved3 = 0;
4832 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4833 byte_count = 3 /* pad */ + params + count;
4834 pSMB->DataCount = cpu_to_le16(count);
4835 pSMB->ParameterCount = cpu_to_le16(params);
4836 pSMB->TotalDataCount = pSMB->DataCount;
4837 pSMB->TotalParameterCount = pSMB->ParameterCount;
4838 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4839 parm_data =
4840 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4841 + offset);
4842 pSMB->DataOffset = cpu_to_le16(offset);
4843 parm_data->FileSize = cpu_to_le64(size);
4844 pSMB->Fid = fid;
4845 if (SetAllocation) {
4846 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4847 pSMB->InformationLevel =
4848 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4849 else
4850 pSMB->InformationLevel =
4851 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4852 } else /* Set File Size */ {
4853 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4854 pSMB->InformationLevel =
4855 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4856 else
4857 pSMB->InformationLevel =
4858 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4860 pSMB->Reserved4 = 0;
4861 pSMB->hdr.smb_buf_length += byte_count;
4862 pSMB->ByteCount = cpu_to_le16(byte_count);
4863 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4864 if (rc) {
4865 cFYI(1,
4866 ("Send error in SetFileInfo (SetFileSize) = %d",
4867 rc));
4870 /* Note: On -EAGAIN error only caller can retry on handle based calls
4871 since file handle passed in no longer valid */
4873 return rc;
4876 /* Some legacy servers such as NT4 require that the file times be set on
4877 an open handle, rather than by pathname - this is awkward due to
4878 potential access conflicts on the open, but it is unavoidable for these
4879 old servers since the only other choice is to go from 100 nanosecond DCE
4880 time and resort to the original setpathinfo level which takes the ancient
4881 DOS time format with 2 second granularity */
4883 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4884 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4886 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4887 char *data_offset;
4888 int rc = 0;
4889 __u16 params, param_offset, offset, byte_count, count;
4891 cFYI(1, ("Set Times (via SetFileInfo)"));
4892 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4894 if (rc)
4895 return rc;
4897 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4898 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4900 params = 6;
4901 pSMB->MaxSetupCount = 0;
4902 pSMB->Reserved = 0;
4903 pSMB->Flags = 0;
4904 pSMB->Timeout = 0;
4905 pSMB->Reserved2 = 0;
4906 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4907 offset = param_offset + params;
4909 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4911 count = sizeof(FILE_BASIC_INFO);
4912 pSMB->MaxParameterCount = cpu_to_le16(2);
4913 /* BB find max SMB PDU from sess */
4914 pSMB->MaxDataCount = cpu_to_le16(1000);
4915 pSMB->SetupCount = 1;
4916 pSMB->Reserved3 = 0;
4917 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4918 byte_count = 3 /* pad */ + params + count;
4919 pSMB->DataCount = cpu_to_le16(count);
4920 pSMB->ParameterCount = cpu_to_le16(params);
4921 pSMB->TotalDataCount = pSMB->DataCount;
4922 pSMB->TotalParameterCount = pSMB->ParameterCount;
4923 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4924 pSMB->DataOffset = cpu_to_le16(offset);
4925 pSMB->Fid = fid;
4926 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4927 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4928 else
4929 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4930 pSMB->Reserved4 = 0;
4931 pSMB->hdr.smb_buf_length += byte_count;
4932 pSMB->ByteCount = cpu_to_le16(byte_count);
4933 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4934 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4935 if (rc)
4936 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4938 /* Note: On -EAGAIN error only caller can retry on handle based calls
4939 since file handle passed in no longer valid */
4941 return rc;
4945 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4946 bool delete_file, __u16 fid, __u32 pid_of_opener)
4948 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4949 char *data_offset;
4950 int rc = 0;
4951 __u16 params, param_offset, offset, byte_count, count;
4953 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4954 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4956 if (rc)
4957 return rc;
4959 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4960 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4962 params = 6;
4963 pSMB->MaxSetupCount = 0;
4964 pSMB->Reserved = 0;
4965 pSMB->Flags = 0;
4966 pSMB->Timeout = 0;
4967 pSMB->Reserved2 = 0;
4968 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4969 offset = param_offset + params;
4971 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4973 count = 1;
4974 pSMB->MaxParameterCount = cpu_to_le16(2);
4975 /* BB find max SMB PDU from sess */
4976 pSMB->MaxDataCount = cpu_to_le16(1000);
4977 pSMB->SetupCount = 1;
4978 pSMB->Reserved3 = 0;
4979 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4980 byte_count = 3 /* pad */ + params + count;
4981 pSMB->DataCount = cpu_to_le16(count);
4982 pSMB->ParameterCount = cpu_to_le16(params);
4983 pSMB->TotalDataCount = pSMB->DataCount;
4984 pSMB->TotalParameterCount = pSMB->ParameterCount;
4985 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4986 pSMB->DataOffset = cpu_to_le16(offset);
4987 pSMB->Fid = fid;
4988 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4989 pSMB->Reserved4 = 0;
4990 pSMB->hdr.smb_buf_length += byte_count;
4991 pSMB->ByteCount = cpu_to_le16(byte_count);
4992 *data_offset = delete_file ? 1 : 0;
4993 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4994 if (rc)
4995 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4997 return rc;
5001 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5002 const char *fileName, const FILE_BASIC_INFO *data,
5003 const struct nls_table *nls_codepage, int remap)
5005 TRANSACTION2_SPI_REQ *pSMB = NULL;
5006 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5007 int name_len;
5008 int rc = 0;
5009 int bytes_returned = 0;
5010 char *data_offset;
5011 __u16 params, param_offset, offset, byte_count, count;
5013 cFYI(1, ("In SetTimes"));
5015 SetTimesRetry:
5016 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5017 (void **) &pSMBr);
5018 if (rc)
5019 return rc;
5021 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5022 name_len =
5023 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5024 PATH_MAX, nls_codepage, remap);
5025 name_len++; /* trailing null */
5026 name_len *= 2;
5027 } else { /* BB improve the check for buffer overruns BB */
5028 name_len = strnlen(fileName, PATH_MAX);
5029 name_len++; /* trailing null */
5030 strncpy(pSMB->FileName, fileName, name_len);
5033 params = 6 + name_len;
5034 count = sizeof(FILE_BASIC_INFO);
5035 pSMB->MaxParameterCount = cpu_to_le16(2);
5036 /* BB find max SMB PDU from sess structure BB */
5037 pSMB->MaxDataCount = cpu_to_le16(1000);
5038 pSMB->MaxSetupCount = 0;
5039 pSMB->Reserved = 0;
5040 pSMB->Flags = 0;
5041 pSMB->Timeout = 0;
5042 pSMB->Reserved2 = 0;
5043 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5044 InformationLevel) - 4;
5045 offset = param_offset + params;
5046 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5047 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5048 pSMB->DataOffset = cpu_to_le16(offset);
5049 pSMB->SetupCount = 1;
5050 pSMB->Reserved3 = 0;
5051 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5052 byte_count = 3 /* pad */ + params + count;
5054 pSMB->DataCount = cpu_to_le16(count);
5055 pSMB->ParameterCount = cpu_to_le16(params);
5056 pSMB->TotalDataCount = pSMB->DataCount;
5057 pSMB->TotalParameterCount = pSMB->ParameterCount;
5058 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5059 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5060 else
5061 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5062 pSMB->Reserved4 = 0;
5063 pSMB->hdr.smb_buf_length += byte_count;
5064 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5065 pSMB->ByteCount = cpu_to_le16(byte_count);
5066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5067 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5068 if (rc)
5069 cFYI(1, ("SetPathInfo (times) returned %d", rc));
5071 cifs_buf_release(pSMB);
5073 if (rc == -EAGAIN)
5074 goto SetTimesRetry;
5076 return rc;
5079 /* Can not be used to set time stamps yet (due to old DOS time format) */
5080 /* Can be used to set attributes */
5081 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5082 handling it anyway and NT4 was what we thought it would be needed for
5083 Do not delete it until we prove whether needed for Win9x though */
5085 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5086 __u16 dos_attrs, const struct nls_table *nls_codepage)
5088 SETATTR_REQ *pSMB = NULL;
5089 SETATTR_RSP *pSMBr = NULL;
5090 int rc = 0;
5091 int bytes_returned;
5092 int name_len;
5094 cFYI(1, ("In SetAttrLegacy"));
5096 SetAttrLgcyRetry:
5097 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5098 (void **) &pSMBr);
5099 if (rc)
5100 return rc;
5102 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5103 name_len =
5104 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5105 PATH_MAX, nls_codepage);
5106 name_len++; /* trailing null */
5107 name_len *= 2;
5108 } else { /* BB improve the check for buffer overruns BB */
5109 name_len = strnlen(fileName, PATH_MAX);
5110 name_len++; /* trailing null */
5111 strncpy(pSMB->fileName, fileName, name_len);
5113 pSMB->attr = cpu_to_le16(dos_attrs);
5114 pSMB->BufferFormat = 0x04;
5115 pSMB->hdr.smb_buf_length += name_len + 1;
5116 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5117 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5119 if (rc)
5120 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5122 cifs_buf_release(pSMB);
5124 if (rc == -EAGAIN)
5125 goto SetAttrLgcyRetry;
5127 return rc;
5129 #endif /* temporarily unneeded SetAttr legacy function */
5132 CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5133 const struct cifs_unix_set_info_args *args,
5134 const struct nls_table *nls_codepage, int remap)
5136 TRANSACTION2_SPI_REQ *pSMB = NULL;
5137 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5138 int name_len;
5139 int rc = 0;
5140 int bytes_returned = 0;
5141 FILE_UNIX_BASIC_INFO *data_offset;
5142 __u16 params, param_offset, offset, count, byte_count;
5143 __u64 mode = args->mode;
5145 cFYI(1, ("In SetUID/GID/Mode"));
5146 setPermsRetry:
5147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5148 (void **) &pSMBr);
5149 if (rc)
5150 return rc;
5152 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5153 name_len =
5154 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5155 PATH_MAX, nls_codepage, remap);
5156 name_len++; /* trailing null */
5157 name_len *= 2;
5158 } else { /* BB improve the check for buffer overruns BB */
5159 name_len = strnlen(fileName, PATH_MAX);
5160 name_len++; /* trailing null */
5161 strncpy(pSMB->FileName, fileName, name_len);
5164 params = 6 + name_len;
5165 count = sizeof(FILE_UNIX_BASIC_INFO);
5166 pSMB->MaxParameterCount = cpu_to_le16(2);
5167 /* BB find max SMB PDU from sess structure BB */
5168 pSMB->MaxDataCount = cpu_to_le16(1000);
5169 pSMB->MaxSetupCount = 0;
5170 pSMB->Reserved = 0;
5171 pSMB->Flags = 0;
5172 pSMB->Timeout = 0;
5173 pSMB->Reserved2 = 0;
5174 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5175 InformationLevel) - 4;
5176 offset = param_offset + params;
5177 data_offset =
5178 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5179 offset);
5180 memset(data_offset, 0, count);
5181 pSMB->DataOffset = cpu_to_le16(offset);
5182 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5183 pSMB->SetupCount = 1;
5184 pSMB->Reserved3 = 0;
5185 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5186 byte_count = 3 /* pad */ + params + count;
5187 pSMB->ParameterCount = cpu_to_le16(params);
5188 pSMB->DataCount = cpu_to_le16(count);
5189 pSMB->TotalParameterCount = pSMB->ParameterCount;
5190 pSMB->TotalDataCount = pSMB->DataCount;
5191 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5192 pSMB->Reserved4 = 0;
5193 pSMB->hdr.smb_buf_length += byte_count;
5194 /* Samba server ignores set of file size to zero due to bugs in some
5195 older clients, but we should be precise - we use SetFileSize to
5196 set file size and do not want to truncate file size to zero
5197 accidently as happened on one Samba server beta by putting
5198 zero instead of -1 here */
5199 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5200 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5201 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5202 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5203 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5204 data_offset->Uid = cpu_to_le64(args->uid);
5205 data_offset->Gid = cpu_to_le64(args->gid);
5206 /* better to leave device as zero when it is */
5207 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5208 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5209 data_offset->Permissions = cpu_to_le64(mode);
5211 if (S_ISREG(mode))
5212 data_offset->Type = cpu_to_le32(UNIX_FILE);
5213 else if (S_ISDIR(mode))
5214 data_offset->Type = cpu_to_le32(UNIX_DIR);
5215 else if (S_ISLNK(mode))
5216 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5217 else if (S_ISCHR(mode))
5218 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5219 else if (S_ISBLK(mode))
5220 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5221 else if (S_ISFIFO(mode))
5222 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5223 else if (S_ISSOCK(mode))
5224 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5227 pSMB->ByteCount = cpu_to_le16(byte_count);
5228 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5229 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5230 if (rc)
5231 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5233 cifs_buf_release(pSMB);
5234 if (rc == -EAGAIN)
5235 goto setPermsRetry;
5236 return rc;
5239 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5240 const int notify_subdirs, const __u16 netfid,
5241 __u32 filter, struct file *pfile, int multishot,
5242 const struct nls_table *nls_codepage)
5244 int rc = 0;
5245 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5246 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5247 struct dir_notify_req *dnotify_req;
5248 int bytes_returned;
5250 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5251 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5252 (void **) &pSMBr);
5253 if (rc)
5254 return rc;
5256 pSMB->TotalParameterCount = 0 ;
5257 pSMB->TotalDataCount = 0;
5258 pSMB->MaxParameterCount = cpu_to_le32(2);
5259 /* BB find exact data count max from sess structure BB */
5260 pSMB->MaxDataCount = 0; /* same in little endian or be */
5261 /* BB VERIFY verify which is correct for above BB */
5262 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5263 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5265 pSMB->MaxSetupCount = 4;
5266 pSMB->Reserved = 0;
5267 pSMB->ParameterOffset = 0;
5268 pSMB->DataCount = 0;
5269 pSMB->DataOffset = 0;
5270 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5271 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5272 pSMB->ParameterCount = pSMB->TotalParameterCount;
5273 if (notify_subdirs)
5274 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5275 pSMB->Reserved2 = 0;
5276 pSMB->CompletionFilter = cpu_to_le32(filter);
5277 pSMB->Fid = netfid; /* file handle always le */
5278 pSMB->ByteCount = 0;
5280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5281 (struct smb_hdr *)pSMBr, &bytes_returned,
5282 CIFS_ASYNC_OP);
5283 if (rc) {
5284 cFYI(1, ("Error in Notify = %d", rc));
5285 } else {
5286 /* Add file to outstanding requests */
5287 /* BB change to kmem cache alloc */
5288 dnotify_req = kmalloc(
5289 sizeof(struct dir_notify_req),
5290 GFP_KERNEL);
5291 if (dnotify_req) {
5292 dnotify_req->Pid = pSMB->hdr.Pid;
5293 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5294 dnotify_req->Mid = pSMB->hdr.Mid;
5295 dnotify_req->Tid = pSMB->hdr.Tid;
5296 dnotify_req->Uid = pSMB->hdr.Uid;
5297 dnotify_req->netfid = netfid;
5298 dnotify_req->pfile = pfile;
5299 dnotify_req->filter = filter;
5300 dnotify_req->multishot = multishot;
5301 spin_lock(&GlobalMid_Lock);
5302 list_add_tail(&dnotify_req->lhead,
5303 &GlobalDnotifyReqList);
5304 spin_unlock(&GlobalMid_Lock);
5305 } else
5306 rc = -ENOMEM;
5308 cifs_buf_release(pSMB);
5309 return rc;
5311 #ifdef CONFIG_CIFS_XATTR
5312 ssize_t
5313 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5314 const unsigned char *searchName,
5315 char *EAData, size_t buf_size,
5316 const struct nls_table *nls_codepage, int remap)
5318 /* BB assumes one setup word */
5319 TRANSACTION2_QPI_REQ *pSMB = NULL;
5320 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5321 int rc = 0;
5322 int bytes_returned;
5323 int name_len;
5324 struct fea *temp_fea;
5325 char *temp_ptr;
5326 __u16 params, byte_count;
5328 cFYI(1, ("In Query All EAs path %s", searchName));
5329 QAllEAsRetry:
5330 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5331 (void **) &pSMBr);
5332 if (rc)
5333 return rc;
5335 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5336 name_len =
5337 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5338 PATH_MAX, nls_codepage, remap);
5339 name_len++; /* trailing null */
5340 name_len *= 2;
5341 } else { /* BB improve the check for buffer overruns BB */
5342 name_len = strnlen(searchName, PATH_MAX);
5343 name_len++; /* trailing null */
5344 strncpy(pSMB->FileName, searchName, name_len);
5347 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5348 pSMB->TotalDataCount = 0;
5349 pSMB->MaxParameterCount = cpu_to_le16(2);
5350 /* BB find exact max SMB PDU from sess structure BB */
5351 pSMB->MaxDataCount = cpu_to_le16(4000);
5352 pSMB->MaxSetupCount = 0;
5353 pSMB->Reserved = 0;
5354 pSMB->Flags = 0;
5355 pSMB->Timeout = 0;
5356 pSMB->Reserved2 = 0;
5357 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5358 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5359 pSMB->DataCount = 0;
5360 pSMB->DataOffset = 0;
5361 pSMB->SetupCount = 1;
5362 pSMB->Reserved3 = 0;
5363 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5364 byte_count = params + 1 /* pad */ ;
5365 pSMB->TotalParameterCount = cpu_to_le16(params);
5366 pSMB->ParameterCount = pSMB->TotalParameterCount;
5367 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5368 pSMB->Reserved4 = 0;
5369 pSMB->hdr.smb_buf_length += byte_count;
5370 pSMB->ByteCount = cpu_to_le16(byte_count);
5372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5373 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5374 if (rc) {
5375 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5376 } else { /* decode response */
5377 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5379 /* BB also check enough total bytes returned */
5380 /* BB we need to improve the validity checking
5381 of these trans2 responses */
5382 if (rc || (pSMBr->ByteCount < 4))
5383 rc = -EIO; /* bad smb */
5384 /* else if (pFindData){
5385 memcpy((char *) pFindData,
5386 (char *) &pSMBr->hdr.Protocol +
5387 data_offset, kl);
5388 }*/ else {
5389 /* check that length of list is not more than bcc */
5390 /* check that each entry does not go beyond length
5391 of list */
5392 /* check that each element of each entry does not
5393 go beyond end of list */
5394 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5395 struct fealist *ea_response_data;
5396 rc = 0;
5397 /* validate_trans2_offsets() */
5398 /* BB check if start of smb + data_offset > &bcc+ bcc */
5399 ea_response_data = (struct fealist *)
5400 (((char *) &pSMBr->hdr.Protocol) +
5401 data_offset);
5402 name_len = le32_to_cpu(ea_response_data->list_len);
5403 cFYI(1, ("ea length %d", name_len));
5404 if (name_len <= 8) {
5405 /* returned EA size zeroed at top of function */
5406 cFYI(1, ("empty EA list returned from server"));
5407 } else {
5408 /* account for ea list len */
5409 name_len -= 4;
5410 temp_fea = ea_response_data->list;
5411 temp_ptr = (char *)temp_fea;
5412 while (name_len > 0) {
5413 __u16 value_len;
5414 name_len -= 4;
5415 temp_ptr += 4;
5416 rc += temp_fea->name_len;
5417 /* account for prefix user. and trailing null */
5418 rc = rc + 5 + 1;
5419 if (rc < (int)buf_size) {
5420 memcpy(EAData, "user.", 5);
5421 EAData += 5;
5422 memcpy(EAData, temp_ptr,
5423 temp_fea->name_len);
5424 EAData += temp_fea->name_len;
5425 /* null terminate name */
5426 *EAData = 0;
5427 EAData = EAData + 1;
5428 } else if (buf_size == 0) {
5429 /* skip copy - calc size only */
5430 } else {
5431 /* stop before overrun buffer */
5432 rc = -ERANGE;
5433 break;
5435 name_len -= temp_fea->name_len;
5436 temp_ptr += temp_fea->name_len;
5437 /* account for trailing null */
5438 name_len--;
5439 temp_ptr++;
5440 value_len =
5441 le16_to_cpu(temp_fea->value_len);
5442 name_len -= value_len;
5443 temp_ptr += value_len;
5444 /* BB check that temp_ptr is still
5445 within the SMB BB*/
5447 /* no trailing null to account for
5448 in value len */
5449 /* go on to next EA */
5450 temp_fea = (struct fea *)temp_ptr;
5455 cifs_buf_release(pSMB);
5456 if (rc == -EAGAIN)
5457 goto QAllEAsRetry;
5459 return (ssize_t)rc;
5462 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5463 const unsigned char *searchName, const unsigned char *ea_name,
5464 unsigned char *ea_value, size_t buf_size,
5465 const struct nls_table *nls_codepage, int remap)
5467 TRANSACTION2_QPI_REQ *pSMB = NULL;
5468 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5469 int rc = 0;
5470 int bytes_returned;
5471 int name_len;
5472 struct fea *temp_fea;
5473 char *temp_ptr;
5474 __u16 params, byte_count;
5476 cFYI(1, ("In Query EA path %s", searchName));
5477 QEARetry:
5478 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5479 (void **) &pSMBr);
5480 if (rc)
5481 return rc;
5483 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5484 name_len =
5485 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5486 PATH_MAX, nls_codepage, remap);
5487 name_len++; /* trailing null */
5488 name_len *= 2;
5489 } else { /* BB improve the check for buffer overruns BB */
5490 name_len = strnlen(searchName, PATH_MAX);
5491 name_len++; /* trailing null */
5492 strncpy(pSMB->FileName, searchName, name_len);
5495 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5496 pSMB->TotalDataCount = 0;
5497 pSMB->MaxParameterCount = cpu_to_le16(2);
5498 /* BB find exact max SMB PDU from sess structure BB */
5499 pSMB->MaxDataCount = cpu_to_le16(4000);
5500 pSMB->MaxSetupCount = 0;
5501 pSMB->Reserved = 0;
5502 pSMB->Flags = 0;
5503 pSMB->Timeout = 0;
5504 pSMB->Reserved2 = 0;
5505 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5506 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5507 pSMB->DataCount = 0;
5508 pSMB->DataOffset = 0;
5509 pSMB->SetupCount = 1;
5510 pSMB->Reserved3 = 0;
5511 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5512 byte_count = params + 1 /* pad */ ;
5513 pSMB->TotalParameterCount = cpu_to_le16(params);
5514 pSMB->ParameterCount = pSMB->TotalParameterCount;
5515 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5516 pSMB->Reserved4 = 0;
5517 pSMB->hdr.smb_buf_length += byte_count;
5518 pSMB->ByteCount = cpu_to_le16(byte_count);
5520 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5521 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5522 if (rc) {
5523 cFYI(1, ("Send error in Query EA = %d", rc));
5524 } else { /* decode response */
5525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5527 /* BB also check enough total bytes returned */
5528 /* BB we need to improve the validity checking
5529 of these trans2 responses */
5530 if (rc || (pSMBr->ByteCount < 4))
5531 rc = -EIO; /* bad smb */
5532 /* else if (pFindData){
5533 memcpy((char *) pFindData,
5534 (char *) &pSMBr->hdr.Protocol +
5535 data_offset, kl);
5536 }*/ else {
5537 /* check that length of list is not more than bcc */
5538 /* check that each entry does not go beyond length
5539 of list */
5540 /* check that each element of each entry does not
5541 go beyond end of list */
5542 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5543 struct fealist *ea_response_data;
5544 rc = -ENODATA;
5545 /* validate_trans2_offsets() */
5546 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5547 ea_response_data = (struct fealist *)
5548 (((char *) &pSMBr->hdr.Protocol) +
5549 data_offset);
5550 name_len = le32_to_cpu(ea_response_data->list_len);
5551 cFYI(1, ("ea length %d", name_len));
5552 if (name_len <= 8) {
5553 /* returned EA size zeroed at top of function */
5554 cFYI(1, ("empty EA list returned from server"));
5555 } else {
5556 /* account for ea list len */
5557 name_len -= 4;
5558 temp_fea = ea_response_data->list;
5559 temp_ptr = (char *)temp_fea;
5560 /* loop through checking if we have a matching
5561 name and then return the associated value */
5562 while (name_len > 0) {
5563 __u16 value_len;
5564 name_len -= 4;
5565 temp_ptr += 4;
5566 value_len =
5567 le16_to_cpu(temp_fea->value_len);
5568 /* BB validate that value_len falls within SMB,
5569 even though maximum for name_len is 255 */
5570 if (memcmp(temp_fea->name, ea_name,
5571 temp_fea->name_len) == 0) {
5572 /* found a match */
5573 rc = value_len;
5574 /* account for prefix user. and trailing null */
5575 if (rc <= (int)buf_size) {
5576 memcpy(ea_value,
5577 temp_fea->name+temp_fea->name_len+1,
5578 rc);
5579 /* ea values, unlike ea
5580 names, are not null
5581 terminated */
5582 } else if (buf_size == 0) {
5583 /* skip copy - calc size only */
5584 } else {
5585 /* stop before overrun buffer */
5586 rc = -ERANGE;
5588 break;
5590 name_len -= temp_fea->name_len;
5591 temp_ptr += temp_fea->name_len;
5592 /* account for trailing null */
5593 name_len--;
5594 temp_ptr++;
5595 name_len -= value_len;
5596 temp_ptr += value_len;
5597 /* No trailing null to account for in
5598 value_len. Go on to next EA */
5599 temp_fea = (struct fea *)temp_ptr;
5604 cifs_buf_release(pSMB);
5605 if (rc == -EAGAIN)
5606 goto QEARetry;
5608 return (ssize_t)rc;
5612 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5613 const char *ea_name, const void *ea_value,
5614 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5615 int remap)
5617 struct smb_com_transaction2_spi_req *pSMB = NULL;
5618 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5619 struct fealist *parm_data;
5620 int name_len;
5621 int rc = 0;
5622 int bytes_returned = 0;
5623 __u16 params, param_offset, byte_count, offset, count;
5625 cFYI(1, ("In SetEA"));
5626 SetEARetry:
5627 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5628 (void **) &pSMBr);
5629 if (rc)
5630 return rc;
5632 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5633 name_len =
5634 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5635 PATH_MAX, nls_codepage, remap);
5636 name_len++; /* trailing null */
5637 name_len *= 2;
5638 } else { /* BB improve the check for buffer overruns BB */
5639 name_len = strnlen(fileName, PATH_MAX);
5640 name_len++; /* trailing null */
5641 strncpy(pSMB->FileName, fileName, name_len);
5644 params = 6 + name_len;
5646 /* done calculating parms using name_len of file name,
5647 now use name_len to calculate length of ea name
5648 we are going to create in the inode xattrs */
5649 if (ea_name == NULL)
5650 name_len = 0;
5651 else
5652 name_len = strnlen(ea_name, 255);
5654 count = sizeof(*parm_data) + ea_value_len + name_len;
5655 pSMB->MaxParameterCount = cpu_to_le16(2);
5656 /* BB find max SMB PDU from sess */
5657 pSMB->MaxDataCount = cpu_to_le16(1000);
5658 pSMB->MaxSetupCount = 0;
5659 pSMB->Reserved = 0;
5660 pSMB->Flags = 0;
5661 pSMB->Timeout = 0;
5662 pSMB->Reserved2 = 0;
5663 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5664 InformationLevel) - 4;
5665 offset = param_offset + params;
5666 pSMB->InformationLevel =
5667 cpu_to_le16(SMB_SET_FILE_EA);
5669 parm_data =
5670 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5671 offset);
5672 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5673 pSMB->DataOffset = cpu_to_le16(offset);
5674 pSMB->SetupCount = 1;
5675 pSMB->Reserved3 = 0;
5676 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5677 byte_count = 3 /* pad */ + params + count;
5678 pSMB->DataCount = cpu_to_le16(count);
5679 parm_data->list_len = cpu_to_le32(count);
5680 parm_data->list[0].EA_flags = 0;
5681 /* we checked above that name len is less than 255 */
5682 parm_data->list[0].name_len = (__u8)name_len;
5683 /* EA names are always ASCII */
5684 if (ea_name)
5685 strncpy(parm_data->list[0].name, ea_name, name_len);
5686 parm_data->list[0].name[name_len] = 0;
5687 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5688 /* caller ensures that ea_value_len is less than 64K but
5689 we need to ensure that it fits within the smb */
5691 /*BB add length check to see if it would fit in
5692 negotiated SMB buffer size BB */
5693 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5694 if (ea_value_len)
5695 memcpy(parm_data->list[0].name+name_len+1,
5696 ea_value, ea_value_len);
5698 pSMB->TotalDataCount = pSMB->DataCount;
5699 pSMB->ParameterCount = cpu_to_le16(params);
5700 pSMB->TotalParameterCount = pSMB->ParameterCount;
5701 pSMB->Reserved4 = 0;
5702 pSMB->hdr.smb_buf_length += byte_count;
5703 pSMB->ByteCount = cpu_to_le16(byte_count);
5704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5706 if (rc)
5707 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5709 cifs_buf_release(pSMB);
5711 if (rc == -EAGAIN)
5712 goto SetEARetry;
5714 return rc;
5717 #endif