workqueues: add comments to __create_workqueue_key()
[linux-2.6/mini2440.git] / fs / cifs / cifssmb.c
blobc621ffa2ca90632173d83b59b4eb203dadbc496c
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 if (open_file)
132 open_file->invalidHandle = true;
134 write_unlock(&GlobalSMBSeslock);
135 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
136 to this tcon */
139 /* Allocate and return pointer to an SMB request buffer, and set basic
140 SMB information in the SMB header. If the return code is zero, this
141 function must have filled in request_buf pointer */
142 static int
143 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
144 void **request_buf)
146 int rc = 0;
148 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
149 check for tcp and smb session status done differently
150 for those three - in the calling routine */
151 if (tcon) {
152 if (tcon->tidStatus == CifsExiting) {
153 /* only tree disconnect, open, and write,
154 (and ulogoff which does not have tcon)
155 are allowed as we start force umount */
156 if ((smb_command != SMB_COM_WRITE_ANDX) &&
157 (smb_command != SMB_COM_OPEN_ANDX) &&
158 (smb_command != SMB_COM_TREE_DISCONNECT)) {
159 cFYI(1, ("can not send cmd %d while umounting",
160 smb_command));
161 return -ENODEV;
164 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
165 (tcon->ses->server)) {
166 struct nls_table *nls_codepage;
167 /* Give Demultiplex thread up to 10 seconds to
168 reconnect, should be greater than cifs socket
169 timeout which is 7 seconds */
170 while (tcon->ses->server->tcpStatus ==
171 CifsNeedReconnect) {
172 wait_event_interruptible_timeout(tcon->ses->server->response_q,
173 (tcon->ses->server->tcpStatus ==
174 CifsGood), 10 * HZ);
175 if (tcon->ses->server->tcpStatus ==
176 CifsNeedReconnect) {
177 /* on "soft" mounts we wait once */
178 if (!tcon->retry ||
179 (tcon->ses->status == CifsExiting)) {
180 cFYI(1, ("gave up waiting on "
181 "reconnect in smb_init"));
182 return -EHOSTDOWN;
183 } /* else "hard" mount - keep retrying
184 until process is killed or server
185 comes back on-line */
186 } else /* TCP session is reestablished now */
187 break;
190 nls_codepage = load_nls_default();
191 /* need to prevent multiple threads trying to
192 simultaneously reconnect the same SMB session */
193 down(&tcon->ses->sesSem);
194 if (tcon->ses->status == CifsNeedReconnect)
195 rc = cifs_setup_session(0, tcon->ses,
196 nls_codepage);
197 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
198 mark_open_files_invalid(tcon);
199 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
200 tcon, nls_codepage);
201 up(&tcon->ses->sesSem);
202 /* BB FIXME add code to check if wsize needs
203 update due to negotiated smb buffer size
204 shrinking */
205 if (rc == 0) {
206 atomic_inc(&tconInfoReconnectCount);
207 /* tell server Unix caps we support */
208 if (tcon->ses->capabilities & CAP_UNIX)
209 reset_cifs_unix_caps(
210 0 /* no xid */,
211 tcon,
212 NULL /* we do not know sb */,
213 NULL /* no vol info */);
216 cFYI(1, ("reconnect tcon rc = %d", rc));
217 /* Removed call to reopen open files here.
218 It is safer (and faster) to reopen files
219 one at a time as needed in read and write */
221 /* Check if handle based operation so we
222 know whether we can continue or not without
223 returning to caller to reset file handle */
224 switch (smb_command) {
225 case SMB_COM_READ_ANDX:
226 case SMB_COM_WRITE_ANDX:
227 case SMB_COM_CLOSE:
228 case SMB_COM_FIND_CLOSE2:
229 case SMB_COM_LOCKING_ANDX: {
230 unload_nls(nls_codepage);
231 return -EAGAIN;
234 } else {
235 up(&tcon->ses->sesSem);
237 unload_nls(nls_codepage);
239 } else {
240 return -EIO;
243 if (rc)
244 return rc;
246 *request_buf = cifs_small_buf_get();
247 if (*request_buf == NULL) {
248 /* BB should we add a retry in here if not a writepage? */
249 return -ENOMEM;
252 header_assemble((struct smb_hdr *) *request_buf, smb_command,
253 tcon, wct);
255 if (tcon != NULL)
256 cifs_stats_inc(&tcon->num_smbs_sent);
258 return rc;
262 small_smb_init_no_tc(const int smb_command, const int wct,
263 struct cifsSesInfo *ses, void **request_buf)
265 int rc;
266 struct smb_hdr *buffer;
268 rc = small_smb_init(smb_command, wct, NULL, request_buf);
269 if (rc)
270 return rc;
272 buffer = (struct smb_hdr *)*request_buf;
273 buffer->Mid = GetNextMid(ses->server);
274 if (ses->capabilities & CAP_UNICODE)
275 buffer->Flags2 |= SMBFLG2_UNICODE;
276 if (ses->capabilities & CAP_STATUS32)
277 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
279 /* uid, tid can stay at zero as set in header assemble */
281 /* BB add support for turning on the signing when
282 this function is used after 1st of session setup requests */
284 return rc;
287 /* If the return code is zero, this function must fill in request_buf pointer */
288 static int
289 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
290 void **request_buf /* returned */ ,
291 void **response_buf /* returned */ )
293 int rc = 0;
295 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
296 check for tcp and smb session status done differently
297 for those three - in the calling routine */
298 if (tcon) {
299 if (tcon->tidStatus == CifsExiting) {
300 /* only tree disconnect, open, and write,
301 (and ulogoff which does not have tcon)
302 are allowed as we start force umount */
303 if ((smb_command != SMB_COM_WRITE_ANDX) &&
304 (smb_command != SMB_COM_OPEN_ANDX) &&
305 (smb_command != SMB_COM_TREE_DISCONNECT)) {
306 cFYI(1, ("can not send cmd %d while umounting",
307 smb_command));
308 return -ENODEV;
312 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
313 (tcon->ses->server)) {
314 struct nls_table *nls_codepage;
315 /* Give Demultiplex thread up to 10 seconds to
316 reconnect, should be greater than cifs socket
317 timeout which is 7 seconds */
318 while (tcon->ses->server->tcpStatus ==
319 CifsNeedReconnect) {
320 wait_event_interruptible_timeout(tcon->ses->server->response_q,
321 (tcon->ses->server->tcpStatus ==
322 CifsGood), 10 * HZ);
323 if (tcon->ses->server->tcpStatus ==
324 CifsNeedReconnect) {
325 /* on "soft" mounts we wait once */
326 if (!tcon->retry ||
327 (tcon->ses->status == CifsExiting)) {
328 cFYI(1, ("gave up waiting on "
329 "reconnect in smb_init"));
330 return -EHOSTDOWN;
331 } /* else "hard" mount - keep retrying
332 until process is killed or server
333 comes on-line */
334 } else /* TCP session is reestablished now */
335 break;
337 nls_codepage = load_nls_default();
338 /* need to prevent multiple threads trying to
339 simultaneously reconnect the same SMB session */
340 down(&tcon->ses->sesSem);
341 if (tcon->ses->status == CifsNeedReconnect)
342 rc = cifs_setup_session(0, tcon->ses,
343 nls_codepage);
344 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
345 mark_open_files_invalid(tcon);
346 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
347 tcon, nls_codepage);
348 up(&tcon->ses->sesSem);
349 /* BB FIXME add code to check if wsize needs
350 update due to negotiated smb buffer size
351 shrinking */
352 if (rc == 0) {
353 atomic_inc(&tconInfoReconnectCount);
354 /* tell server Unix caps we support */
355 if (tcon->ses->capabilities & CAP_UNIX)
356 reset_cifs_unix_caps(
357 0 /* no xid */,
358 tcon,
359 NULL /* do not know sb */,
360 NULL /* no vol info */);
363 cFYI(1, ("reconnect tcon rc = %d", rc));
364 /* Removed call to reopen open files here.
365 It is safer (and faster) to reopen files
366 one at a time as needed in read and write */
368 /* Check if handle based operation so we
369 know whether we can continue or not without
370 returning to caller to reset file handle */
371 switch (smb_command) {
372 case SMB_COM_READ_ANDX:
373 case SMB_COM_WRITE_ANDX:
374 case SMB_COM_CLOSE:
375 case SMB_COM_FIND_CLOSE2:
376 case SMB_COM_LOCKING_ANDX: {
377 unload_nls(nls_codepage);
378 return -EAGAIN;
381 } else {
382 up(&tcon->ses->sesSem);
384 unload_nls(nls_codepage);
386 } else {
387 return -EIO;
390 if (rc)
391 return rc;
393 *request_buf = cifs_buf_get();
394 if (*request_buf == NULL) {
395 /* BB should we add a retry in here if not a writepage? */
396 return -ENOMEM;
398 /* Although the original thought was we needed the response buf for */
399 /* potential retries of smb operations it turns out we can determine */
400 /* from the mid flags when the request buffer can be resent without */
401 /* having to use a second distinct buffer for the response */
402 if (response_buf)
403 *response_buf = *request_buf;
405 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
406 wct);
408 if (tcon != NULL)
409 cifs_stats_inc(&tcon->num_smbs_sent);
411 return rc;
414 static int validate_t2(struct smb_t2_rsp *pSMB)
416 int rc = -EINVAL;
417 int total_size;
418 char *pBCC;
420 /* check for plausible wct, bcc and t2 data and parm sizes */
421 /* check for parm and data offset going beyond end of smb */
422 if (pSMB->hdr.WordCount >= 10) {
423 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
424 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
425 /* check that bcc is at least as big as parms + data */
426 /* check that bcc is less than negotiated smb buffer */
427 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
428 if (total_size < 512) {
429 total_size +=
430 le16_to_cpu(pSMB->t2_rsp.DataCount);
431 /* BCC le converted in SendReceive */
432 pBCC = (pSMB->hdr.WordCount * 2) +
433 sizeof(struct smb_hdr) +
434 (char *)pSMB;
435 if ((total_size <= (*(u16 *)pBCC)) &&
436 (total_size <
437 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
438 return 0;
443 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
444 sizeof(struct smb_t2_rsp) + 16);
445 return rc;
448 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
450 NEGOTIATE_REQ *pSMB;
451 NEGOTIATE_RSP *pSMBr;
452 int rc = 0;
453 int bytes_returned;
454 int i;
455 struct TCP_Server_Info *server;
456 u16 count;
457 unsigned int secFlags;
458 u16 dialect;
460 if (ses->server)
461 server = ses->server;
462 else {
463 rc = -EIO;
464 return rc;
466 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
467 (void **) &pSMB, (void **) &pSMBr);
468 if (rc)
469 return rc;
471 /* if any of auth flags (ie not sign or seal) are overriden use them */
472 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
473 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
474 else /* if override flags set only sign/seal OR them with global auth */
475 secFlags = extended_security | ses->overrideSecFlg;
477 cFYI(1, ("secFlags 0x%x", secFlags));
479 pSMB->hdr.Mid = GetNextMid(server);
480 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
482 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
483 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
484 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
485 cFYI(1, ("Kerberos only mechanism, enable extended security"));
486 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
489 count = 0;
490 for (i = 0; i < CIFS_NUM_PROT; i++) {
491 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
492 count += strlen(protocols[i].name) + 1;
493 /* null at end of source and target buffers anyway */
495 pSMB->hdr.smb_buf_length += count;
496 pSMB->ByteCount = cpu_to_le16(count);
498 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
500 if (rc != 0)
501 goto neg_err_exit;
503 dialect = le16_to_cpu(pSMBr->DialectIndex);
504 cFYI(1, ("Dialect: %d", dialect));
505 /* Check wct = 1 error case */
506 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
507 /* core returns wct = 1, but we do not ask for core - otherwise
508 small wct just comes when dialect index is -1 indicating we
509 could not negotiate a common dialect */
510 rc = -EOPNOTSUPP;
511 goto neg_err_exit;
512 #ifdef CONFIG_CIFS_WEAK_PW_HASH
513 } else if ((pSMBr->hdr.WordCount == 13)
514 && ((dialect == LANMAN_PROT)
515 || (dialect == LANMAN2_PROT))) {
516 __s16 tmp;
517 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
519 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
520 (secFlags & CIFSSEC_MAY_PLNTXT))
521 server->secType = LANMAN;
522 else {
523 cERROR(1, ("mount failed weak security disabled"
524 " in /proc/fs/cifs/SecurityFlags"));
525 rc = -EOPNOTSUPP;
526 goto neg_err_exit;
528 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
529 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
530 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
531 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
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->maxRw = 0xFF00;
537 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
538 } else {
539 server->maxRw = 0;/* we 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->maxRw = 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;
669 if (server->socketUseCount.counter > 1) {
670 if (memcmp(server->server_GUID,
671 pSMBr->u.extended_response.
672 GUID, 16) != 0) {
673 cFYI(1, ("server UID changed"));
674 memcpy(server->server_GUID,
675 pSMBr->u.extended_response.GUID,
676 16);
678 } else
679 memcpy(server->server_GUID,
680 pSMBr->u.extended_response.GUID, 16);
682 if (count == 16) {
683 server->secType = RawNTLMSSP;
684 } else {
685 rc = decode_negTokenInit(pSMBr->u.extended_response.
686 SecurityBlob,
687 count - 16,
688 &server->secType);
689 if (rc == 1)
690 rc = 0;
691 else
692 rc = -EINVAL;
694 } else
695 server->capabilities &= ~CAP_EXTENDED_SECURITY;
697 #ifdef CONFIG_CIFS_WEAK_PW_HASH
698 signing_check:
699 #endif
700 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
701 /* MUST_SIGN already includes the MAY_SIGN FLAG
702 so if this is zero it means that signing is disabled */
703 cFYI(1, ("Signing disabled"));
704 if (server->secMode & SECMODE_SIGN_REQUIRED) {
705 cERROR(1, ("Server requires "
706 "packet signing to be enabled in "
707 "/proc/fs/cifs/SecurityFlags."));
708 rc = -EOPNOTSUPP;
710 server->secMode &=
711 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
712 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
713 /* signing required */
714 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
715 if ((server->secMode &
716 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
717 cERROR(1,
718 ("signing required but server lacks support"));
719 rc = -EOPNOTSUPP;
720 } else
721 server->secMode |= SECMODE_SIGN_REQUIRED;
722 } else {
723 /* signing optional ie CIFSSEC_MAY_SIGN */
724 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
725 server->secMode &=
726 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
729 neg_err_exit:
730 cifs_buf_release(pSMB);
732 cFYI(1, ("negprot rc %d", rc));
733 return rc;
737 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
739 struct smb_hdr *smb_buffer;
740 int rc = 0;
742 cFYI(1, ("In tree disconnect"));
744 * If last user of the connection and
745 * connection alive - disconnect it
746 * If this is the last connection on the server session disconnect it
747 * (and inside session disconnect we should check if tcp socket needs
748 * to be freed and kernel thread woken up).
750 if (tcon)
751 down(&tcon->tconSem);
752 else
753 return -EIO;
755 atomic_dec(&tcon->useCount);
756 if (atomic_read(&tcon->useCount) > 0) {
757 up(&tcon->tconSem);
758 return -EBUSY;
761 /* No need to return error on this operation if tid invalidated and
762 closed on server already e.g. due to tcp session crashing */
763 if (tcon->tidStatus == CifsNeedReconnect) {
764 up(&tcon->tconSem);
765 return 0;
768 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
769 up(&tcon->tconSem);
770 return -EIO;
772 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
773 (void **)&smb_buffer);
774 if (rc) {
775 up(&tcon->tconSem);
776 return rc;
779 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
780 if (rc)
781 cFYI(1, ("Tree disconnect failed %d", rc));
783 up(&tcon->tconSem);
785 /* No need to return error on this operation if tid invalidated and
786 closed on server already e.g. due to tcp session crashing */
787 if (rc == -EAGAIN)
788 rc = 0;
790 return rc;
794 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
796 LOGOFF_ANDX_REQ *pSMB;
797 int rc = 0;
799 cFYI(1, ("In SMBLogoff for session disconnect"));
800 if (ses)
801 down(&ses->sesSem);
802 else
803 return -EIO;
805 atomic_dec(&ses->inUse);
806 if (atomic_read(&ses->inUse) > 0) {
807 up(&ses->sesSem);
808 return -EBUSY;
810 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
811 if (rc) {
812 up(&ses->sesSem);
813 return rc;
816 if (ses->server) {
817 pSMB->hdr.Mid = GetNextMid(ses->server);
819 if (ses->server->secMode &
820 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
821 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
824 pSMB->hdr.Uid = ses->Suid;
826 pSMB->AndXCommand = 0xFF;
827 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
828 if (ses->server) {
829 atomic_dec(&ses->server->socketUseCount);
830 if (atomic_read(&ses->server->socketUseCount) == 0) {
831 spin_lock(&GlobalMid_Lock);
832 ses->server->tcpStatus = CifsExiting;
833 spin_unlock(&GlobalMid_Lock);
834 rc = -ESHUTDOWN;
837 up(&ses->sesSem);
839 /* if session dead then we do not need to do ulogoff,
840 since server closed smb session, no sense reporting
841 error */
842 if (rc == -EAGAIN)
843 rc = 0;
844 return rc;
848 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
849 __u16 type, const struct nls_table *nls_codepage, int remap)
851 TRANSACTION2_SPI_REQ *pSMB = NULL;
852 TRANSACTION2_SPI_RSP *pSMBr = NULL;
853 struct unlink_psx_rq *pRqD;
854 int name_len;
855 int rc = 0;
856 int bytes_returned = 0;
857 __u16 params, param_offset, offset, byte_count;
859 cFYI(1, ("In POSIX delete"));
860 PsxDelete:
861 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
862 (void **) &pSMBr);
863 if (rc)
864 return rc;
866 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
867 name_len =
868 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
869 PATH_MAX, nls_codepage, remap);
870 name_len++; /* trailing null */
871 name_len *= 2;
872 } else { /* BB add path length overrun check */
873 name_len = strnlen(fileName, PATH_MAX);
874 name_len++; /* trailing null */
875 strncpy(pSMB->FileName, fileName, name_len);
878 params = 6 + name_len;
879 pSMB->MaxParameterCount = cpu_to_le16(2);
880 pSMB->MaxDataCount = 0; /* BB double check this with jra */
881 pSMB->MaxSetupCount = 0;
882 pSMB->Reserved = 0;
883 pSMB->Flags = 0;
884 pSMB->Timeout = 0;
885 pSMB->Reserved2 = 0;
886 param_offset = offsetof(struct smb_com_transaction2_spi_req,
887 InformationLevel) - 4;
888 offset = param_offset + params;
890 /* Setup pointer to Request Data (inode type) */
891 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
892 pRqD->type = cpu_to_le16(type);
893 pSMB->ParameterOffset = cpu_to_le16(param_offset);
894 pSMB->DataOffset = cpu_to_le16(offset);
895 pSMB->SetupCount = 1;
896 pSMB->Reserved3 = 0;
897 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
898 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
900 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
901 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
902 pSMB->ParameterCount = cpu_to_le16(params);
903 pSMB->TotalParameterCount = pSMB->ParameterCount;
904 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
905 pSMB->Reserved4 = 0;
906 pSMB->hdr.smb_buf_length += byte_count;
907 pSMB->ByteCount = cpu_to_le16(byte_count);
908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
910 if (rc)
911 cFYI(1, ("Posix delete returned %d", rc));
912 cifs_buf_release(pSMB);
914 cifs_stats_inc(&tcon->num_deletes);
916 if (rc == -EAGAIN)
917 goto PsxDelete;
919 return rc;
923 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
924 const struct nls_table *nls_codepage, int remap)
926 DELETE_FILE_REQ *pSMB = NULL;
927 DELETE_FILE_RSP *pSMBr = NULL;
928 int rc = 0;
929 int bytes_returned;
930 int name_len;
932 DelFileRetry:
933 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
934 (void **) &pSMBr);
935 if (rc)
936 return rc;
938 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
939 name_len =
940 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
941 PATH_MAX, nls_codepage, remap);
942 name_len++; /* trailing null */
943 name_len *= 2;
944 } else { /* BB improve check for buffer overruns BB */
945 name_len = strnlen(fileName, PATH_MAX);
946 name_len++; /* trailing null */
947 strncpy(pSMB->fileName, fileName, name_len);
949 pSMB->SearchAttributes =
950 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
951 pSMB->BufferFormat = 0x04;
952 pSMB->hdr.smb_buf_length += name_len + 1;
953 pSMB->ByteCount = cpu_to_le16(name_len + 1);
954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
956 cifs_stats_inc(&tcon->num_deletes);
957 if (rc)
958 cFYI(1, ("Error in RMFile = %d", rc));
960 cifs_buf_release(pSMB);
961 if (rc == -EAGAIN)
962 goto DelFileRetry;
964 return rc;
968 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
969 const struct nls_table *nls_codepage, int remap)
971 DELETE_DIRECTORY_REQ *pSMB = NULL;
972 DELETE_DIRECTORY_RSP *pSMBr = NULL;
973 int rc = 0;
974 int bytes_returned;
975 int name_len;
977 cFYI(1, ("In CIFSSMBRmDir"));
978 RmDirRetry:
979 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
980 (void **) &pSMBr);
981 if (rc)
982 return rc;
984 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
985 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
986 PATH_MAX, nls_codepage, remap);
987 name_len++; /* trailing null */
988 name_len *= 2;
989 } else { /* BB improve check for buffer overruns BB */
990 name_len = strnlen(dirName, PATH_MAX);
991 name_len++; /* trailing null */
992 strncpy(pSMB->DirName, dirName, name_len);
995 pSMB->BufferFormat = 0x04;
996 pSMB->hdr.smb_buf_length += name_len + 1;
997 pSMB->ByteCount = cpu_to_le16(name_len + 1);
998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1000 cifs_stats_inc(&tcon->num_rmdirs);
1001 if (rc)
1002 cFYI(1, ("Error in RMDir = %d", rc));
1004 cifs_buf_release(pSMB);
1005 if (rc == -EAGAIN)
1006 goto RmDirRetry;
1007 return rc;
1011 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
1012 const char *name, const struct nls_table *nls_codepage, int remap)
1014 int rc = 0;
1015 CREATE_DIRECTORY_REQ *pSMB = NULL;
1016 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1017 int bytes_returned;
1018 int name_len;
1020 cFYI(1, ("In CIFSSMBMkDir"));
1021 MkDirRetry:
1022 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1023 (void **) &pSMBr);
1024 if (rc)
1025 return rc;
1027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1028 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
1029 PATH_MAX, nls_codepage, remap);
1030 name_len++; /* trailing null */
1031 name_len *= 2;
1032 } else { /* BB improve check for buffer overruns BB */
1033 name_len = strnlen(name, PATH_MAX);
1034 name_len++; /* trailing null */
1035 strncpy(pSMB->DirName, name, name_len);
1038 pSMB->BufferFormat = 0x04;
1039 pSMB->hdr.smb_buf_length += name_len + 1;
1040 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1041 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1042 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1043 cifs_stats_inc(&tcon->num_mkdirs);
1044 if (rc)
1045 cFYI(1, ("Error in Mkdir = %d", rc));
1047 cifs_buf_release(pSMB);
1048 if (rc == -EAGAIN)
1049 goto MkDirRetry;
1050 return rc;
1054 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1055 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1056 __u32 *pOplock, const char *name,
1057 const struct nls_table *nls_codepage, int remap)
1059 TRANSACTION2_SPI_REQ *pSMB = NULL;
1060 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1061 int name_len;
1062 int rc = 0;
1063 int bytes_returned = 0;
1064 __u16 params, param_offset, offset, byte_count, count;
1065 OPEN_PSX_REQ *pdata;
1066 OPEN_PSX_RSP *psx_rsp;
1068 cFYI(1, ("In POSIX Create"));
1069 PsxCreat:
1070 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1071 (void **) &pSMBr);
1072 if (rc)
1073 return rc;
1075 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1076 name_len =
1077 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1078 PATH_MAX, nls_codepage, remap);
1079 name_len++; /* trailing null */
1080 name_len *= 2;
1081 } else { /* BB improve the check for buffer overruns BB */
1082 name_len = strnlen(name, PATH_MAX);
1083 name_len++; /* trailing null */
1084 strncpy(pSMB->FileName, name, name_len);
1087 params = 6 + name_len;
1088 count = sizeof(OPEN_PSX_REQ);
1089 pSMB->MaxParameterCount = cpu_to_le16(2);
1090 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1091 pSMB->MaxSetupCount = 0;
1092 pSMB->Reserved = 0;
1093 pSMB->Flags = 0;
1094 pSMB->Timeout = 0;
1095 pSMB->Reserved2 = 0;
1096 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1097 InformationLevel) - 4;
1098 offset = param_offset + params;
1099 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1100 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1101 pdata->Permissions = cpu_to_le64(mode);
1102 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1103 pdata->OpenFlags = cpu_to_le32(*pOplock);
1104 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1105 pSMB->DataOffset = cpu_to_le16(offset);
1106 pSMB->SetupCount = 1;
1107 pSMB->Reserved3 = 0;
1108 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1109 byte_count = 3 /* pad */ + params + count;
1111 pSMB->DataCount = cpu_to_le16(count);
1112 pSMB->ParameterCount = cpu_to_le16(params);
1113 pSMB->TotalDataCount = pSMB->DataCount;
1114 pSMB->TotalParameterCount = pSMB->ParameterCount;
1115 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1116 pSMB->Reserved4 = 0;
1117 pSMB->hdr.smb_buf_length += byte_count;
1118 pSMB->ByteCount = cpu_to_le16(byte_count);
1119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1121 if (rc) {
1122 cFYI(1, ("Posix create returned %d", rc));
1123 goto psx_create_err;
1126 cFYI(1, ("copying inode info"));
1127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1129 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1130 rc = -EIO; /* bad smb */
1131 goto psx_create_err;
1134 /* copy return information to pRetData */
1135 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1136 + le16_to_cpu(pSMBr->t2.DataOffset));
1138 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1139 if (netfid)
1140 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1141 /* Let caller know file was created so we can set the mode. */
1142 /* Do we care about the CreateAction in any other cases? */
1143 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1144 *pOplock |= CIFS_CREATE_ACTION;
1145 /* check to make sure response data is there */
1146 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1147 pRetData->Type = cpu_to_le32(-1); /* unknown */
1148 cFYI(DBG2, ("unknown type"));
1149 } else {
1150 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1151 + sizeof(FILE_UNIX_BASIC_INFO)) {
1152 cERROR(1, ("Open response data too small"));
1153 pRetData->Type = cpu_to_le32(-1);
1154 goto psx_create_err;
1156 memcpy((char *) pRetData,
1157 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1158 sizeof(FILE_UNIX_BASIC_INFO));
1161 psx_create_err:
1162 cifs_buf_release(pSMB);
1164 cifs_stats_inc(&tcon->num_mkdirs);
1166 if (rc == -EAGAIN)
1167 goto PsxCreat;
1169 return rc;
1172 static __u16 convert_disposition(int disposition)
1174 __u16 ofun = 0;
1176 switch (disposition) {
1177 case FILE_SUPERSEDE:
1178 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1179 break;
1180 case FILE_OPEN:
1181 ofun = SMBOPEN_OAPPEND;
1182 break;
1183 case FILE_CREATE:
1184 ofun = SMBOPEN_OCREATE;
1185 break;
1186 case FILE_OPEN_IF:
1187 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1188 break;
1189 case FILE_OVERWRITE:
1190 ofun = SMBOPEN_OTRUNC;
1191 break;
1192 case FILE_OVERWRITE_IF:
1193 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1194 break;
1195 default:
1196 cFYI(1, ("unknown disposition %d", disposition));
1197 ofun = SMBOPEN_OAPPEND; /* regular open */
1199 return ofun;
1202 static int
1203 access_flags_to_smbopen_mode(const int access_flags)
1205 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1207 if (masked_flags == GENERIC_READ)
1208 return SMBOPEN_READ;
1209 else if (masked_flags == GENERIC_WRITE)
1210 return SMBOPEN_WRITE;
1212 /* just go for read/write */
1213 return SMBOPEN_READWRITE;
1217 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1218 const char *fileName, const int openDisposition,
1219 const int access_flags, const int create_options, __u16 *netfid,
1220 int *pOplock, FILE_ALL_INFO *pfile_info,
1221 const struct nls_table *nls_codepage, int remap)
1223 int rc = -EACCES;
1224 OPENX_REQ *pSMB = NULL;
1225 OPENX_RSP *pSMBr = NULL;
1226 int bytes_returned;
1227 int name_len;
1228 __u16 count;
1230 OldOpenRetry:
1231 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1232 (void **) &pSMBr);
1233 if (rc)
1234 return rc;
1236 pSMB->AndXCommand = 0xFF; /* none */
1238 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1239 count = 1; /* account for one byte pad to word boundary */
1240 name_len =
1241 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1242 fileName, PATH_MAX, nls_codepage, remap);
1243 name_len++; /* trailing null */
1244 name_len *= 2;
1245 } else { /* BB improve check for buffer overruns BB */
1246 count = 0; /* no pad */
1247 name_len = strnlen(fileName, PATH_MAX);
1248 name_len++; /* trailing null */
1249 strncpy(pSMB->fileName, fileName, name_len);
1251 if (*pOplock & REQ_OPLOCK)
1252 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1253 else if (*pOplock & REQ_BATCHOPLOCK)
1254 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1256 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1257 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1258 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1259 /* set file as system file if special file such
1260 as fifo and server expecting SFU style and
1261 no Unix extensions */
1263 if (create_options & CREATE_OPTION_SPECIAL)
1264 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1265 else /* BB FIXME BB */
1266 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1268 if (create_options & CREATE_OPTION_READONLY)
1269 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1271 /* BB FIXME BB */
1272 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1273 CREATE_OPTIONS_MASK); */
1274 /* BB FIXME END BB */
1276 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1277 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1278 count += name_len;
1279 pSMB->hdr.smb_buf_length += count;
1281 pSMB->ByteCount = cpu_to_le16(count);
1282 /* long_op set to 1 to allow for oplock break timeouts */
1283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1284 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1285 cifs_stats_inc(&tcon->num_opens);
1286 if (rc) {
1287 cFYI(1, ("Error in Open = %d", rc));
1288 } else {
1289 /* BB verify if wct == 15 */
1291 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1293 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1294 /* Let caller know file was created so we can set the mode. */
1295 /* Do we care about the CreateAction in any other cases? */
1296 /* BB FIXME BB */
1297 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1298 *pOplock |= CIFS_CREATE_ACTION; */
1299 /* BB FIXME END */
1301 if (pfile_info) {
1302 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1303 pfile_info->LastAccessTime = 0; /* BB fixme */
1304 pfile_info->LastWriteTime = 0; /* BB fixme */
1305 pfile_info->ChangeTime = 0; /* BB fixme */
1306 pfile_info->Attributes =
1307 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1308 /* the file_info buf is endian converted by caller */
1309 pfile_info->AllocationSize =
1310 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1311 pfile_info->EndOfFile = pfile_info->AllocationSize;
1312 pfile_info->NumberOfLinks = cpu_to_le32(1);
1316 cifs_buf_release(pSMB);
1317 if (rc == -EAGAIN)
1318 goto OldOpenRetry;
1319 return rc;
1323 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1324 const char *fileName, const int openDisposition,
1325 const int access_flags, const int create_options, __u16 *netfid,
1326 int *pOplock, FILE_ALL_INFO *pfile_info,
1327 const struct nls_table *nls_codepage, int remap)
1329 int rc = -EACCES;
1330 OPEN_REQ *pSMB = NULL;
1331 OPEN_RSP *pSMBr = NULL;
1332 int bytes_returned;
1333 int name_len;
1334 __u16 count;
1336 openRetry:
1337 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1338 (void **) &pSMBr);
1339 if (rc)
1340 return rc;
1342 pSMB->AndXCommand = 0xFF; /* none */
1344 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1345 count = 1; /* account for one byte pad to word boundary */
1346 name_len =
1347 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1348 fileName, PATH_MAX, nls_codepage, remap);
1349 name_len++; /* trailing null */
1350 name_len *= 2;
1351 pSMB->NameLength = cpu_to_le16(name_len);
1352 } else { /* BB improve check for buffer overruns BB */
1353 count = 0; /* no pad */
1354 name_len = strnlen(fileName, PATH_MAX);
1355 name_len++; /* trailing null */
1356 pSMB->NameLength = cpu_to_le16(name_len);
1357 strncpy(pSMB->fileName, fileName, name_len);
1359 if (*pOplock & REQ_OPLOCK)
1360 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1361 else if (*pOplock & REQ_BATCHOPLOCK)
1362 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1363 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1364 pSMB->AllocationSize = 0;
1365 /* set file as system file if special file such
1366 as fifo and server expecting SFU style and
1367 no Unix extensions */
1368 if (create_options & CREATE_OPTION_SPECIAL)
1369 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1370 else
1371 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1373 /* XP does not handle ATTR_POSIX_SEMANTICS */
1374 /* but it helps speed up case sensitive checks for other
1375 servers such as Samba */
1376 if (tcon->ses->capabilities & CAP_UNIX)
1377 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1379 if (create_options & CREATE_OPTION_READONLY)
1380 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1382 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1383 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1384 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1385 /* BB Expirement with various impersonation levels and verify */
1386 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1387 pSMB->SecurityFlags =
1388 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1390 count += name_len;
1391 pSMB->hdr.smb_buf_length += count;
1393 pSMB->ByteCount = cpu_to_le16(count);
1394 /* long_op set to 1 to allow for oplock break timeouts */
1395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1396 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1397 cifs_stats_inc(&tcon->num_opens);
1398 if (rc) {
1399 cFYI(1, ("Error in Open = %d", rc));
1400 } else {
1401 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1402 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1403 /* Let caller know file was created so we can set the mode. */
1404 /* Do we care about the CreateAction in any other cases? */
1405 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1406 *pOplock |= CIFS_CREATE_ACTION;
1407 if (pfile_info) {
1408 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1409 36 /* CreationTime to Attributes */);
1410 /* the file_info buf is endian converted by caller */
1411 pfile_info->AllocationSize = pSMBr->AllocationSize;
1412 pfile_info->EndOfFile = pSMBr->EndOfFile;
1413 pfile_info->NumberOfLinks = cpu_to_le32(1);
1417 cifs_buf_release(pSMB);
1418 if (rc == -EAGAIN)
1419 goto openRetry;
1420 return rc;
1424 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1425 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1426 char **buf, int *pbuf_type)
1428 int rc = -EACCES;
1429 READ_REQ *pSMB = NULL;
1430 READ_RSP *pSMBr = NULL;
1431 char *pReadData = NULL;
1432 int wct;
1433 int resp_buf_type = 0;
1434 struct kvec iov[1];
1436 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1437 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1438 wct = 12;
1439 else
1440 wct = 10; /* old style read */
1442 *nbytes = 0;
1443 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1444 if (rc)
1445 return rc;
1447 /* tcon and ses pointer are checked in smb_init */
1448 if (tcon->ses->server == NULL)
1449 return -ECONNABORTED;
1451 pSMB->AndXCommand = 0xFF; /* none */
1452 pSMB->Fid = netfid;
1453 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1454 if (wct == 12)
1455 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1456 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
1457 return -EIO;
1459 pSMB->Remaining = 0;
1460 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1461 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1462 if (wct == 12)
1463 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1464 else {
1465 /* old style read */
1466 struct smb_com_readx_req *pSMBW =
1467 (struct smb_com_readx_req *)pSMB;
1468 pSMBW->ByteCount = 0;
1471 iov[0].iov_base = (char *)pSMB;
1472 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1473 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1474 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1475 cifs_stats_inc(&tcon->num_reads);
1476 pSMBr = (READ_RSP *)iov[0].iov_base;
1477 if (rc) {
1478 cERROR(1, ("Send error in read = %d", rc));
1479 } else {
1480 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1481 data_length = data_length << 16;
1482 data_length += le16_to_cpu(pSMBr->DataLength);
1483 *nbytes = data_length;
1485 /*check that DataLength would not go beyond end of SMB */
1486 if ((data_length > CIFSMaxBufSize)
1487 || (data_length > count)) {
1488 cFYI(1, ("bad length %d for count %d",
1489 data_length, count));
1490 rc = -EIO;
1491 *nbytes = 0;
1492 } else {
1493 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1494 le16_to_cpu(pSMBr->DataOffset);
1495 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1496 cERROR(1,("Faulting on read rc = %d",rc));
1497 rc = -EFAULT;
1498 }*/ /* can not use copy_to_user when using page cache*/
1499 if (*buf)
1500 memcpy(*buf, pReadData, data_length);
1504 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1505 if (*buf) {
1506 if (resp_buf_type == CIFS_SMALL_BUFFER)
1507 cifs_small_buf_release(iov[0].iov_base);
1508 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1509 cifs_buf_release(iov[0].iov_base);
1510 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1511 /* return buffer to caller to free */
1512 *buf = iov[0].iov_base;
1513 if (resp_buf_type == CIFS_SMALL_BUFFER)
1514 *pbuf_type = CIFS_SMALL_BUFFER;
1515 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1516 *pbuf_type = CIFS_LARGE_BUFFER;
1517 } /* else no valid buffer on return - leave as null */
1519 /* Note: On -EAGAIN error only caller can retry on handle based calls
1520 since file handle passed in no longer valid */
1521 return rc;
1526 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1527 const int netfid, const unsigned int count,
1528 const __u64 offset, unsigned int *nbytes, const char *buf,
1529 const char __user *ubuf, const int long_op)
1531 int rc = -EACCES;
1532 WRITE_REQ *pSMB = NULL;
1533 WRITE_RSP *pSMBr = NULL;
1534 int bytes_returned, wct;
1535 __u32 bytes_sent;
1536 __u16 byte_count;
1538 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1539 if (tcon->ses == NULL)
1540 return -ECONNABORTED;
1542 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1543 wct = 14;
1544 else
1545 wct = 12;
1547 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1548 (void **) &pSMBr);
1549 if (rc)
1550 return rc;
1551 /* tcon and ses pointer are checked in smb_init */
1552 if (tcon->ses->server == NULL)
1553 return -ECONNABORTED;
1555 pSMB->AndXCommand = 0xFF; /* none */
1556 pSMB->Fid = netfid;
1557 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1558 if (wct == 14)
1559 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1560 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1561 return -EIO;
1563 pSMB->Reserved = 0xFFFFFFFF;
1564 pSMB->WriteMode = 0;
1565 pSMB->Remaining = 0;
1567 /* Can increase buffer size if buffer is big enough in some cases ie we
1568 can send more if LARGE_WRITE_X capability returned by the server and if
1569 our buffer is big enough or if we convert to iovecs on socket writes
1570 and eliminate the copy to the CIFS buffer */
1571 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1572 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1573 } else {
1574 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1575 & ~0xFF;
1578 if (bytes_sent > count)
1579 bytes_sent = count;
1580 pSMB->DataOffset =
1581 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1582 if (buf)
1583 memcpy(pSMB->Data, buf, bytes_sent);
1584 else if (ubuf) {
1585 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1586 cifs_buf_release(pSMB);
1587 return -EFAULT;
1589 } else if (count != 0) {
1590 /* No buffer */
1591 cifs_buf_release(pSMB);
1592 return -EINVAL;
1593 } /* else setting file size with write of zero bytes */
1594 if (wct == 14)
1595 byte_count = bytes_sent + 1; /* pad */
1596 else /* wct == 12 */
1597 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1599 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1600 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1601 pSMB->hdr.smb_buf_length += byte_count;
1603 if (wct == 14)
1604 pSMB->ByteCount = cpu_to_le16(byte_count);
1605 else { /* old style write has byte count 4 bytes earlier
1606 so 4 bytes pad */
1607 struct smb_com_writex_req *pSMBW =
1608 (struct smb_com_writex_req *)pSMB;
1609 pSMBW->ByteCount = cpu_to_le16(byte_count);
1612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1613 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1614 cifs_stats_inc(&tcon->num_writes);
1615 if (rc) {
1616 cFYI(1, ("Send error in write = %d", rc));
1617 *nbytes = 0;
1618 } else {
1619 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1620 *nbytes = (*nbytes) << 16;
1621 *nbytes += le16_to_cpu(pSMBr->Count);
1624 cifs_buf_release(pSMB);
1626 /* Note: On -EAGAIN error only caller can retry on handle based calls
1627 since file handle passed in no longer valid */
1629 return rc;
1633 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1634 const int netfid, const unsigned int count,
1635 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1636 int n_vec, const int long_op)
1638 int rc = -EACCES;
1639 WRITE_REQ *pSMB = NULL;
1640 int wct;
1641 int smb_hdr_len;
1642 int resp_buf_type = 0;
1644 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1646 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1647 wct = 14;
1648 else
1649 wct = 12;
1650 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1651 if (rc)
1652 return rc;
1653 /* tcon and ses pointer are checked in smb_init */
1654 if (tcon->ses->server == NULL)
1655 return -ECONNABORTED;
1657 pSMB->AndXCommand = 0xFF; /* none */
1658 pSMB->Fid = netfid;
1659 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1660 if (wct == 14)
1661 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1662 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1663 return -EIO;
1664 pSMB->Reserved = 0xFFFFFFFF;
1665 pSMB->WriteMode = 0;
1666 pSMB->Remaining = 0;
1668 pSMB->DataOffset =
1669 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1671 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1672 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1673 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1674 if (wct == 14)
1675 pSMB->hdr.smb_buf_length += count+1;
1676 else /* wct == 12 */
1677 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1678 if (wct == 14)
1679 pSMB->ByteCount = cpu_to_le16(count + 1);
1680 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1681 struct smb_com_writex_req *pSMBW =
1682 (struct smb_com_writex_req *)pSMB;
1683 pSMBW->ByteCount = cpu_to_le16(count + 5);
1685 iov[0].iov_base = pSMB;
1686 if (wct == 14)
1687 iov[0].iov_len = smb_hdr_len + 4;
1688 else /* wct == 12 pad bigger by four bytes */
1689 iov[0].iov_len = smb_hdr_len + 8;
1692 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1693 long_op);
1694 cifs_stats_inc(&tcon->num_writes);
1695 if (rc) {
1696 cFYI(1, ("Send error Write2 = %d", rc));
1697 *nbytes = 0;
1698 } else if (resp_buf_type == 0) {
1699 /* presumably this can not happen, but best to be safe */
1700 rc = -EIO;
1701 *nbytes = 0;
1702 } else {
1703 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1704 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1705 *nbytes = (*nbytes) << 16;
1706 *nbytes += le16_to_cpu(pSMBr->Count);
1709 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1710 if (resp_buf_type == CIFS_SMALL_BUFFER)
1711 cifs_small_buf_release(iov[0].iov_base);
1712 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1713 cifs_buf_release(iov[0].iov_base);
1715 /* Note: On -EAGAIN error only caller can retry on handle based calls
1716 since file handle passed in no longer valid */
1718 return rc;
1723 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1724 const __u16 smb_file_id, const __u64 len,
1725 const __u64 offset, const __u32 numUnlock,
1726 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1728 int rc = 0;
1729 LOCK_REQ *pSMB = NULL;
1730 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1731 int bytes_returned;
1732 int timeout = 0;
1733 __u16 count;
1735 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1736 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1738 if (rc)
1739 return rc;
1741 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1742 timeout = CIFS_ASYNC_OP; /* no response expected */
1743 pSMB->Timeout = 0;
1744 } else if (waitFlag) {
1745 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1746 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1747 } else {
1748 pSMB->Timeout = 0;
1751 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1752 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1753 pSMB->LockType = lockType;
1754 pSMB->AndXCommand = 0xFF; /* none */
1755 pSMB->Fid = smb_file_id; /* netfid stays le */
1757 if ((numLock != 0) || (numUnlock != 0)) {
1758 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1759 /* BB where to store pid high? */
1760 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1761 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1762 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1763 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1764 count = sizeof(LOCKING_ANDX_RANGE);
1765 } else {
1766 /* oplock break */
1767 count = 0;
1769 pSMB->hdr.smb_buf_length += count;
1770 pSMB->ByteCount = cpu_to_le16(count);
1772 if (waitFlag) {
1773 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1774 (struct smb_hdr *) pSMB, &bytes_returned);
1775 cifs_small_buf_release(pSMB);
1776 } else {
1777 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1778 timeout);
1779 /* SMB buffer freed by function above */
1781 cifs_stats_inc(&tcon->num_locks);
1782 if (rc)
1783 cFYI(1, ("Send error in Lock = %d", rc));
1785 /* Note: On -EAGAIN error only caller can retry on handle based calls
1786 since file handle passed in no longer valid */
1787 return rc;
1791 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1792 const __u16 smb_file_id, const int get_flag, const __u64 len,
1793 struct file_lock *pLockData, const __u16 lock_type,
1794 const bool waitFlag)
1796 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1797 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1798 struct cifs_posix_lock *parm_data;
1799 int rc = 0;
1800 int timeout = 0;
1801 int bytes_returned = 0;
1802 int resp_buf_type = 0;
1803 __u16 params, param_offset, offset, byte_count, count;
1804 struct kvec iov[1];
1806 cFYI(1, ("Posix Lock"));
1808 if (pLockData == NULL)
1809 return -EINVAL;
1811 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1813 if (rc)
1814 return rc;
1816 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1818 params = 6;
1819 pSMB->MaxSetupCount = 0;
1820 pSMB->Reserved = 0;
1821 pSMB->Flags = 0;
1822 pSMB->Reserved2 = 0;
1823 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1824 offset = param_offset + params;
1826 count = sizeof(struct cifs_posix_lock);
1827 pSMB->MaxParameterCount = cpu_to_le16(2);
1828 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1829 pSMB->SetupCount = 1;
1830 pSMB->Reserved3 = 0;
1831 if (get_flag)
1832 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1833 else
1834 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1835 byte_count = 3 /* pad */ + params + count;
1836 pSMB->DataCount = cpu_to_le16(count);
1837 pSMB->ParameterCount = cpu_to_le16(params);
1838 pSMB->TotalDataCount = pSMB->DataCount;
1839 pSMB->TotalParameterCount = pSMB->ParameterCount;
1840 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1841 parm_data = (struct cifs_posix_lock *)
1842 (((char *) &pSMB->hdr.Protocol) + offset);
1844 parm_data->lock_type = cpu_to_le16(lock_type);
1845 if (waitFlag) {
1846 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1847 parm_data->lock_flags = cpu_to_le16(1);
1848 pSMB->Timeout = cpu_to_le32(-1);
1849 } else
1850 pSMB->Timeout = 0;
1852 parm_data->pid = cpu_to_le32(current->tgid);
1853 parm_data->start = cpu_to_le64(pLockData->fl_start);
1854 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1856 pSMB->DataOffset = cpu_to_le16(offset);
1857 pSMB->Fid = smb_file_id;
1858 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1859 pSMB->Reserved4 = 0;
1860 pSMB->hdr.smb_buf_length += byte_count;
1861 pSMB->ByteCount = cpu_to_le16(byte_count);
1862 if (waitFlag) {
1863 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1864 (struct smb_hdr *) pSMBr, &bytes_returned);
1865 } else {
1866 iov[0].iov_base = (char *)pSMB;
1867 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1868 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1869 &resp_buf_type, timeout);
1870 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1871 not try to free it twice below on exit */
1872 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1875 if (rc) {
1876 cFYI(1, ("Send error in Posix Lock = %d", rc));
1877 } else if (get_flag) {
1878 /* lock structure can be returned on get */
1879 __u16 data_offset;
1880 __u16 data_count;
1881 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1883 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1884 rc = -EIO; /* bad smb */
1885 goto plk_err_exit;
1887 if (pLockData == NULL) {
1888 rc = -EINVAL;
1889 goto plk_err_exit;
1891 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1892 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1893 if (data_count < sizeof(struct cifs_posix_lock)) {
1894 rc = -EIO;
1895 goto plk_err_exit;
1897 parm_data = (struct cifs_posix_lock *)
1898 ((char *)&pSMBr->hdr.Protocol + data_offset);
1899 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1900 pLockData->fl_type = F_UNLCK;
1903 plk_err_exit:
1904 if (pSMB)
1905 cifs_small_buf_release(pSMB);
1907 if (resp_buf_type == CIFS_SMALL_BUFFER)
1908 cifs_small_buf_release(iov[0].iov_base);
1909 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1910 cifs_buf_release(iov[0].iov_base);
1912 /* Note: On -EAGAIN error only caller can retry on handle based calls
1913 since file handle passed in no longer valid */
1915 return rc;
1920 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1922 int rc = 0;
1923 CLOSE_REQ *pSMB = NULL;
1924 cFYI(1, ("In CIFSSMBClose"));
1926 /* do not retry on dead session on close */
1927 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1928 if (rc == -EAGAIN)
1929 return 0;
1930 if (rc)
1931 return rc;
1933 pSMB->FileID = (__u16) smb_file_id;
1934 pSMB->LastWriteTime = 0xFFFFFFFF;
1935 pSMB->ByteCount = 0;
1936 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1937 cifs_stats_inc(&tcon->num_closes);
1938 if (rc) {
1939 if (rc != -EINTR) {
1940 /* EINTR is expected when user ctl-c to kill app */
1941 cERROR(1, ("Send error in Close = %d", rc));
1945 /* Since session is dead, file will be closed on server already */
1946 if (rc == -EAGAIN)
1947 rc = 0;
1949 return rc;
1953 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1954 const char *fromName, const char *toName,
1955 const struct nls_table *nls_codepage, int remap)
1957 int rc = 0;
1958 RENAME_REQ *pSMB = NULL;
1959 RENAME_RSP *pSMBr = NULL;
1960 int bytes_returned;
1961 int name_len, name_len2;
1962 __u16 count;
1964 cFYI(1, ("In CIFSSMBRename"));
1965 renameRetry:
1966 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1967 (void **) &pSMBr);
1968 if (rc)
1969 return rc;
1971 pSMB->BufferFormat = 0x04;
1972 pSMB->SearchAttributes =
1973 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1974 ATTR_DIRECTORY);
1976 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1977 name_len =
1978 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1979 PATH_MAX, nls_codepage, remap);
1980 name_len++; /* trailing null */
1981 name_len *= 2;
1982 pSMB->OldFileName[name_len] = 0x04; /* pad */
1983 /* protocol requires ASCII signature byte on Unicode string */
1984 pSMB->OldFileName[name_len + 1] = 0x00;
1985 name_len2 =
1986 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1987 toName, PATH_MAX, nls_codepage, remap);
1988 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1989 name_len2 *= 2; /* convert to bytes */
1990 } else { /* BB improve the check for buffer overruns BB */
1991 name_len = strnlen(fromName, PATH_MAX);
1992 name_len++; /* trailing null */
1993 strncpy(pSMB->OldFileName, fromName, name_len);
1994 name_len2 = strnlen(toName, PATH_MAX);
1995 name_len2++; /* trailing null */
1996 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1997 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1998 name_len2++; /* trailing null */
1999 name_len2++; /* signature byte */
2002 count = 1 /* 1st signature byte */ + name_len + name_len2;
2003 pSMB->hdr.smb_buf_length += count;
2004 pSMB->ByteCount = cpu_to_le16(count);
2006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2008 cifs_stats_inc(&tcon->num_renames);
2009 if (rc)
2010 cFYI(1, ("Send error in rename = %d", rc));
2012 cifs_buf_release(pSMB);
2014 if (rc == -EAGAIN)
2015 goto renameRetry;
2017 return rc;
2020 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2021 int netfid, char *target_name,
2022 const struct nls_table *nls_codepage, int remap)
2024 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2025 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2026 struct set_file_rename *rename_info;
2027 char *data_offset;
2028 char dummy_string[30];
2029 int rc = 0;
2030 int bytes_returned = 0;
2031 int len_of_str;
2032 __u16 params, param_offset, offset, count, byte_count;
2034 cFYI(1, ("Rename to File by handle"));
2035 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2036 (void **) &pSMBr);
2037 if (rc)
2038 return rc;
2040 params = 6;
2041 pSMB->MaxSetupCount = 0;
2042 pSMB->Reserved = 0;
2043 pSMB->Flags = 0;
2044 pSMB->Timeout = 0;
2045 pSMB->Reserved2 = 0;
2046 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2047 offset = param_offset + params;
2049 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2050 rename_info = (struct set_file_rename *) data_offset;
2051 pSMB->MaxParameterCount = cpu_to_le16(2);
2052 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2053 pSMB->SetupCount = 1;
2054 pSMB->Reserved3 = 0;
2055 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2056 byte_count = 3 /* pad */ + params;
2057 pSMB->ParameterCount = cpu_to_le16(params);
2058 pSMB->TotalParameterCount = pSMB->ParameterCount;
2059 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2060 pSMB->DataOffset = cpu_to_le16(offset);
2061 /* construct random name ".cifs_tmp<inodenum><mid>" */
2062 rename_info->overwrite = cpu_to_le32(1);
2063 rename_info->root_fid = 0;
2064 /* unicode only call */
2065 if (target_name == NULL) {
2066 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2067 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2068 dummy_string, 24, nls_codepage, remap);
2069 } else {
2070 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2071 target_name, PATH_MAX, nls_codepage,
2072 remap);
2074 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2075 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2076 byte_count += count;
2077 pSMB->DataCount = cpu_to_le16(count);
2078 pSMB->TotalDataCount = pSMB->DataCount;
2079 pSMB->Fid = netfid;
2080 pSMB->InformationLevel =
2081 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2082 pSMB->Reserved4 = 0;
2083 pSMB->hdr.smb_buf_length += byte_count;
2084 pSMB->ByteCount = cpu_to_le16(byte_count);
2085 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2086 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2087 cifs_stats_inc(&pTcon->num_t2renames);
2088 if (rc)
2089 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2091 cifs_buf_release(pSMB);
2093 /* Note: On -EAGAIN error only caller can retry on handle based calls
2094 since file handle passed in no longer valid */
2096 return rc;
2100 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2101 const __u16 target_tid, const char *toName, const int flags,
2102 const struct nls_table *nls_codepage, int remap)
2104 int rc = 0;
2105 COPY_REQ *pSMB = NULL;
2106 COPY_RSP *pSMBr = NULL;
2107 int bytes_returned;
2108 int name_len, name_len2;
2109 __u16 count;
2111 cFYI(1, ("In CIFSSMBCopy"));
2112 copyRetry:
2113 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2114 (void **) &pSMBr);
2115 if (rc)
2116 return rc;
2118 pSMB->BufferFormat = 0x04;
2119 pSMB->Tid2 = target_tid;
2121 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2123 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2124 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2125 fromName, PATH_MAX, nls_codepage,
2126 remap);
2127 name_len++; /* trailing null */
2128 name_len *= 2;
2129 pSMB->OldFileName[name_len] = 0x04; /* pad */
2130 /* protocol requires ASCII signature byte on Unicode string */
2131 pSMB->OldFileName[name_len + 1] = 0x00;
2132 name_len2 =
2133 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2134 toName, PATH_MAX, nls_codepage, remap);
2135 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2136 name_len2 *= 2; /* convert to bytes */
2137 } else { /* BB improve the check for buffer overruns BB */
2138 name_len = strnlen(fromName, PATH_MAX);
2139 name_len++; /* trailing null */
2140 strncpy(pSMB->OldFileName, fromName, name_len);
2141 name_len2 = strnlen(toName, PATH_MAX);
2142 name_len2++; /* trailing null */
2143 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2144 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2145 name_len2++; /* trailing null */
2146 name_len2++; /* signature byte */
2149 count = 1 /* 1st signature byte */ + name_len + name_len2;
2150 pSMB->hdr.smb_buf_length += count;
2151 pSMB->ByteCount = cpu_to_le16(count);
2153 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2154 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2155 if (rc) {
2156 cFYI(1, ("Send error in copy = %d with %d files copied",
2157 rc, le16_to_cpu(pSMBr->CopyCount)));
2159 cifs_buf_release(pSMB);
2161 if (rc == -EAGAIN)
2162 goto copyRetry;
2164 return rc;
2168 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2169 const char *fromName, const char *toName,
2170 const struct nls_table *nls_codepage)
2172 TRANSACTION2_SPI_REQ *pSMB = NULL;
2173 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2174 char *data_offset;
2175 int name_len;
2176 int name_len_target;
2177 int rc = 0;
2178 int bytes_returned = 0;
2179 __u16 params, param_offset, offset, byte_count;
2181 cFYI(1, ("In Symlink Unix style"));
2182 createSymLinkRetry:
2183 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2184 (void **) &pSMBr);
2185 if (rc)
2186 return rc;
2188 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2189 name_len =
2190 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2191 /* find define for this maxpathcomponent */
2192 , nls_codepage);
2193 name_len++; /* trailing null */
2194 name_len *= 2;
2196 } else { /* BB improve the check for buffer overruns BB */
2197 name_len = strnlen(fromName, PATH_MAX);
2198 name_len++; /* trailing null */
2199 strncpy(pSMB->FileName, fromName, name_len);
2201 params = 6 + name_len;
2202 pSMB->MaxSetupCount = 0;
2203 pSMB->Reserved = 0;
2204 pSMB->Flags = 0;
2205 pSMB->Timeout = 0;
2206 pSMB->Reserved2 = 0;
2207 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2208 InformationLevel) - 4;
2209 offset = param_offset + params;
2211 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2212 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2213 name_len_target =
2214 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2215 /* find define for this maxpathcomponent */
2216 , nls_codepage);
2217 name_len_target++; /* trailing null */
2218 name_len_target *= 2;
2219 } else { /* BB improve the check for buffer overruns BB */
2220 name_len_target = strnlen(toName, PATH_MAX);
2221 name_len_target++; /* trailing null */
2222 strncpy(data_offset, toName, name_len_target);
2225 pSMB->MaxParameterCount = cpu_to_le16(2);
2226 /* BB find exact max on data count below from sess */
2227 pSMB->MaxDataCount = cpu_to_le16(1000);
2228 pSMB->SetupCount = 1;
2229 pSMB->Reserved3 = 0;
2230 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2231 byte_count = 3 /* pad */ + params + name_len_target;
2232 pSMB->DataCount = cpu_to_le16(name_len_target);
2233 pSMB->ParameterCount = cpu_to_le16(params);
2234 pSMB->TotalDataCount = pSMB->DataCount;
2235 pSMB->TotalParameterCount = pSMB->ParameterCount;
2236 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2237 pSMB->DataOffset = cpu_to_le16(offset);
2238 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2239 pSMB->Reserved4 = 0;
2240 pSMB->hdr.smb_buf_length += byte_count;
2241 pSMB->ByteCount = cpu_to_le16(byte_count);
2242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2243 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2244 cifs_stats_inc(&tcon->num_symlinks);
2245 if (rc)
2246 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2248 cifs_buf_release(pSMB);
2250 if (rc == -EAGAIN)
2251 goto createSymLinkRetry;
2253 return rc;
2257 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2258 const char *fromName, const char *toName,
2259 const struct nls_table *nls_codepage, int remap)
2261 TRANSACTION2_SPI_REQ *pSMB = NULL;
2262 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2263 char *data_offset;
2264 int name_len;
2265 int name_len_target;
2266 int rc = 0;
2267 int bytes_returned = 0;
2268 __u16 params, param_offset, offset, byte_count;
2270 cFYI(1, ("In Create Hard link Unix style"));
2271 createHardLinkRetry:
2272 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2273 (void **) &pSMBr);
2274 if (rc)
2275 return rc;
2277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2278 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2279 PATH_MAX, nls_codepage, remap);
2280 name_len++; /* trailing null */
2281 name_len *= 2;
2283 } else { /* BB improve the check for buffer overruns BB */
2284 name_len = strnlen(toName, PATH_MAX);
2285 name_len++; /* trailing null */
2286 strncpy(pSMB->FileName, toName, name_len);
2288 params = 6 + name_len;
2289 pSMB->MaxSetupCount = 0;
2290 pSMB->Reserved = 0;
2291 pSMB->Flags = 0;
2292 pSMB->Timeout = 0;
2293 pSMB->Reserved2 = 0;
2294 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2295 InformationLevel) - 4;
2296 offset = param_offset + params;
2298 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2299 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2300 name_len_target =
2301 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2302 nls_codepage, remap);
2303 name_len_target++; /* trailing null */
2304 name_len_target *= 2;
2305 } else { /* BB improve the check for buffer overruns BB */
2306 name_len_target = strnlen(fromName, PATH_MAX);
2307 name_len_target++; /* trailing null */
2308 strncpy(data_offset, fromName, name_len_target);
2311 pSMB->MaxParameterCount = cpu_to_le16(2);
2312 /* BB find exact max on data count below from sess*/
2313 pSMB->MaxDataCount = cpu_to_le16(1000);
2314 pSMB->SetupCount = 1;
2315 pSMB->Reserved3 = 0;
2316 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2317 byte_count = 3 /* pad */ + params + name_len_target;
2318 pSMB->ParameterCount = cpu_to_le16(params);
2319 pSMB->TotalParameterCount = pSMB->ParameterCount;
2320 pSMB->DataCount = cpu_to_le16(name_len_target);
2321 pSMB->TotalDataCount = pSMB->DataCount;
2322 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2323 pSMB->DataOffset = cpu_to_le16(offset);
2324 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2325 pSMB->Reserved4 = 0;
2326 pSMB->hdr.smb_buf_length += byte_count;
2327 pSMB->ByteCount = cpu_to_le16(byte_count);
2328 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2329 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2330 cifs_stats_inc(&tcon->num_hardlinks);
2331 if (rc)
2332 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2334 cifs_buf_release(pSMB);
2335 if (rc == -EAGAIN)
2336 goto createHardLinkRetry;
2338 return rc;
2342 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2343 const char *fromName, const char *toName,
2344 const struct nls_table *nls_codepage, int remap)
2346 int rc = 0;
2347 NT_RENAME_REQ *pSMB = NULL;
2348 RENAME_RSP *pSMBr = NULL;
2349 int bytes_returned;
2350 int name_len, name_len2;
2351 __u16 count;
2353 cFYI(1, ("In CIFSCreateHardLink"));
2354 winCreateHardLinkRetry:
2356 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2357 (void **) &pSMBr);
2358 if (rc)
2359 return rc;
2361 pSMB->SearchAttributes =
2362 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2363 ATTR_DIRECTORY);
2364 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2365 pSMB->ClusterCount = 0;
2367 pSMB->BufferFormat = 0x04;
2369 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2370 name_len =
2371 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2372 PATH_MAX, nls_codepage, remap);
2373 name_len++; /* trailing null */
2374 name_len *= 2;
2375 pSMB->OldFileName[name_len] = 0; /* pad */
2376 pSMB->OldFileName[name_len + 1] = 0x04;
2377 name_len2 =
2378 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2379 toName, PATH_MAX, nls_codepage, remap);
2380 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2381 name_len2 *= 2; /* convert to bytes */
2382 } else { /* BB improve the check for buffer overruns BB */
2383 name_len = strnlen(fromName, PATH_MAX);
2384 name_len++; /* trailing null */
2385 strncpy(pSMB->OldFileName, fromName, name_len);
2386 name_len2 = strnlen(toName, PATH_MAX);
2387 name_len2++; /* trailing null */
2388 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2389 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2390 name_len2++; /* trailing null */
2391 name_len2++; /* signature byte */
2394 count = 1 /* string type byte */ + name_len + name_len2;
2395 pSMB->hdr.smb_buf_length += count;
2396 pSMB->ByteCount = cpu_to_le16(count);
2398 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2399 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2400 cifs_stats_inc(&tcon->num_hardlinks);
2401 if (rc)
2402 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2404 cifs_buf_release(pSMB);
2405 if (rc == -EAGAIN)
2406 goto winCreateHardLinkRetry;
2408 return rc;
2412 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2413 const unsigned char *searchName,
2414 char *symlinkinfo, const int buflen,
2415 const struct nls_table *nls_codepage)
2417 /* SMB_QUERY_FILE_UNIX_LINK */
2418 TRANSACTION2_QPI_REQ *pSMB = NULL;
2419 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2420 int rc = 0;
2421 int bytes_returned;
2422 int name_len;
2423 __u16 params, byte_count;
2425 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2427 querySymLinkRetry:
2428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2429 (void **) &pSMBr);
2430 if (rc)
2431 return rc;
2433 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2434 name_len =
2435 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2436 PATH_MAX, nls_codepage);
2437 name_len++; /* trailing null */
2438 name_len *= 2;
2439 } else { /* BB improve the check for buffer overruns BB */
2440 name_len = strnlen(searchName, PATH_MAX);
2441 name_len++; /* trailing null */
2442 strncpy(pSMB->FileName, searchName, name_len);
2445 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2446 pSMB->TotalDataCount = 0;
2447 pSMB->MaxParameterCount = cpu_to_le16(2);
2448 /* BB find exact max data count below from sess structure BB */
2449 pSMB->MaxDataCount = cpu_to_le16(4000);
2450 pSMB->MaxSetupCount = 0;
2451 pSMB->Reserved = 0;
2452 pSMB->Flags = 0;
2453 pSMB->Timeout = 0;
2454 pSMB->Reserved2 = 0;
2455 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2456 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2457 pSMB->DataCount = 0;
2458 pSMB->DataOffset = 0;
2459 pSMB->SetupCount = 1;
2460 pSMB->Reserved3 = 0;
2461 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2462 byte_count = params + 1 /* pad */ ;
2463 pSMB->TotalParameterCount = cpu_to_le16(params);
2464 pSMB->ParameterCount = pSMB->TotalParameterCount;
2465 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2466 pSMB->Reserved4 = 0;
2467 pSMB->hdr.smb_buf_length += byte_count;
2468 pSMB->ByteCount = cpu_to_le16(byte_count);
2470 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2472 if (rc) {
2473 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2474 } else {
2475 /* decode response */
2477 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2478 if (rc || (pSMBr->ByteCount < 2))
2479 /* BB also check enough total bytes returned */
2480 rc = -EIO; /* bad smb */
2481 else {
2482 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2483 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2485 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2486 name_len = UniStrnlen((wchar_t *) ((char *)
2487 &pSMBr->hdr.Protocol + data_offset),
2488 min_t(const int, buflen, count) / 2);
2489 /* BB FIXME investigate remapping reserved chars here */
2490 cifs_strfromUCS_le(symlinkinfo,
2491 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2492 + data_offset),
2493 name_len, nls_codepage);
2494 } else {
2495 strncpy(symlinkinfo,
2496 (char *) &pSMBr->hdr.Protocol +
2497 data_offset,
2498 min_t(const int, buflen, count));
2500 symlinkinfo[buflen] = 0;
2501 /* just in case so calling code does not go off the end of buffer */
2504 cifs_buf_release(pSMB);
2505 if (rc == -EAGAIN)
2506 goto querySymLinkRetry;
2507 return rc;
2510 #ifdef CONFIG_CIFS_EXPERIMENTAL
2511 /* Initialize NT TRANSACT SMB into small smb request buffer.
2512 This assumes that all NT TRANSACTS that we init here have
2513 total parm and data under about 400 bytes (to fit in small cifs
2514 buffer size), which is the case so far, it easily fits. NB:
2515 Setup words themselves and ByteCount
2516 MaxSetupCount (size of returned setup area) and
2517 MaxParameterCount (returned parms size) must be set by caller */
2518 static int
2519 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2520 const int parm_len, struct cifsTconInfo *tcon,
2521 void **ret_buf)
2523 int rc;
2524 __u32 temp_offset;
2525 struct smb_com_ntransact_req *pSMB;
2527 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2528 (void **)&pSMB);
2529 if (rc)
2530 return rc;
2531 *ret_buf = (void *)pSMB;
2532 pSMB->Reserved = 0;
2533 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2534 pSMB->TotalDataCount = 0;
2535 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2536 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2537 pSMB->ParameterCount = pSMB->TotalParameterCount;
2538 pSMB->DataCount = pSMB->TotalDataCount;
2539 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2540 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2541 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2542 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2543 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2544 pSMB->SubCommand = cpu_to_le16(sub_command);
2545 return 0;
2548 static int
2549 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2550 __u32 *pparmlen, __u32 *pdatalen)
2552 char *end_of_smb;
2553 __u32 data_count, data_offset, parm_count, parm_offset;
2554 struct smb_com_ntransact_rsp *pSMBr;
2556 *pdatalen = 0;
2557 *pparmlen = 0;
2559 if (buf == NULL)
2560 return -EINVAL;
2562 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2564 /* ByteCount was converted from little endian in SendReceive */
2565 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2566 (char *)&pSMBr->ByteCount;
2568 data_offset = le32_to_cpu(pSMBr->DataOffset);
2569 data_count = le32_to_cpu(pSMBr->DataCount);
2570 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2571 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2573 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2574 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2576 /* should we also check that parm and data areas do not overlap? */
2577 if (*ppparm > end_of_smb) {
2578 cFYI(1, ("parms start after end of smb"));
2579 return -EINVAL;
2580 } else if (parm_count + *ppparm > end_of_smb) {
2581 cFYI(1, ("parm end after end of smb"));
2582 return -EINVAL;
2583 } else if (*ppdata > end_of_smb) {
2584 cFYI(1, ("data starts after end of smb"));
2585 return -EINVAL;
2586 } else if (data_count + *ppdata > end_of_smb) {
2587 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2588 *ppdata, data_count, (data_count + *ppdata),
2589 end_of_smb, pSMBr));
2590 return -EINVAL;
2591 } else if (parm_count + data_count > pSMBr->ByteCount) {
2592 cFYI(1, ("parm count and data count larger than SMB"));
2593 return -EINVAL;
2595 *pdatalen = data_count;
2596 *pparmlen = parm_count;
2597 return 0;
2599 #endif /* CIFS_EXPERIMENTAL */
2602 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2603 const unsigned char *searchName,
2604 char *symlinkinfo, const int buflen, __u16 fid,
2605 const struct nls_table *nls_codepage)
2607 int rc = 0;
2608 int bytes_returned;
2609 int name_len;
2610 struct smb_com_transaction_ioctl_req *pSMB;
2611 struct smb_com_transaction_ioctl_rsp *pSMBr;
2613 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2614 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2615 (void **) &pSMBr);
2616 if (rc)
2617 return rc;
2619 pSMB->TotalParameterCount = 0 ;
2620 pSMB->TotalDataCount = 0;
2621 pSMB->MaxParameterCount = cpu_to_le32(2);
2622 /* BB find exact data count max from sess structure BB */
2623 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2624 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2625 pSMB->MaxSetupCount = 4;
2626 pSMB->Reserved = 0;
2627 pSMB->ParameterOffset = 0;
2628 pSMB->DataCount = 0;
2629 pSMB->DataOffset = 0;
2630 pSMB->SetupCount = 4;
2631 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2632 pSMB->ParameterCount = pSMB->TotalParameterCount;
2633 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2634 pSMB->IsFsctl = 1; /* FSCTL */
2635 pSMB->IsRootFlag = 0;
2636 pSMB->Fid = fid; /* file handle always le */
2637 pSMB->ByteCount = 0;
2639 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2640 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2641 if (rc) {
2642 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2643 } else { /* decode response */
2644 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2645 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2646 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2647 /* BB also check enough total bytes returned */
2648 rc = -EIO; /* bad smb */
2649 else {
2650 if (data_count && (data_count < 2048)) {
2651 char *end_of_smb = 2 /* sizeof byte count */ +
2652 pSMBr->ByteCount +
2653 (char *)&pSMBr->ByteCount;
2655 struct reparse_data *reparse_buf =
2656 (struct reparse_data *)
2657 ((char *)&pSMBr->hdr.Protocol
2658 + data_offset);
2659 if ((char *)reparse_buf >= end_of_smb) {
2660 rc = -EIO;
2661 goto qreparse_out;
2663 if ((reparse_buf->LinkNamesBuf +
2664 reparse_buf->TargetNameOffset +
2665 reparse_buf->TargetNameLen) >
2666 end_of_smb) {
2667 cFYI(1, ("reparse buf beyond SMB"));
2668 rc = -EIO;
2669 goto qreparse_out;
2672 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2673 name_len = UniStrnlen((wchar_t *)
2674 (reparse_buf->LinkNamesBuf +
2675 reparse_buf->TargetNameOffset),
2676 min(buflen/2,
2677 reparse_buf->TargetNameLen / 2));
2678 cifs_strfromUCS_le(symlinkinfo,
2679 (__le16 *) (reparse_buf->LinkNamesBuf +
2680 reparse_buf->TargetNameOffset),
2681 name_len, nls_codepage);
2682 } else { /* ASCII names */
2683 strncpy(symlinkinfo,
2684 reparse_buf->LinkNamesBuf +
2685 reparse_buf->TargetNameOffset,
2686 min_t(const int, buflen,
2687 reparse_buf->TargetNameLen));
2689 } else {
2690 rc = -EIO;
2691 cFYI(1, ("Invalid return data count on "
2692 "get reparse info ioctl"));
2694 symlinkinfo[buflen] = 0; /* just in case so the caller
2695 does not go off the end of the buffer */
2696 cFYI(1, ("readlink result - %s", symlinkinfo));
2699 qreparse_out:
2700 cifs_buf_release(pSMB);
2702 /* Note: On -EAGAIN error only caller can retry on handle based calls
2703 since file handle passed in no longer valid */
2705 return rc;
2708 #ifdef CONFIG_CIFS_POSIX
2710 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2711 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2712 struct cifs_posix_ace *cifs_ace)
2714 /* u8 cifs fields do not need le conversion */
2715 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2716 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2717 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2718 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2720 return;
2723 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2724 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2725 const int acl_type, const int size_of_data_area)
2727 int size = 0;
2728 int i;
2729 __u16 count;
2730 struct cifs_posix_ace *pACE;
2731 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2732 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2734 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2735 return -EOPNOTSUPP;
2737 if (acl_type & ACL_TYPE_ACCESS) {
2738 count = le16_to_cpu(cifs_acl->access_entry_count);
2739 pACE = &cifs_acl->ace_array[0];
2740 size = sizeof(struct cifs_posix_acl);
2741 size += sizeof(struct cifs_posix_ace) * count;
2742 /* check if we would go beyond end of SMB */
2743 if (size_of_data_area < size) {
2744 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2745 size_of_data_area, size));
2746 return -EINVAL;
2748 } else if (acl_type & ACL_TYPE_DEFAULT) {
2749 count = le16_to_cpu(cifs_acl->access_entry_count);
2750 size = sizeof(struct cifs_posix_acl);
2751 size += sizeof(struct cifs_posix_ace) * count;
2752 /* skip past access ACEs to get to default ACEs */
2753 pACE = &cifs_acl->ace_array[count];
2754 count = le16_to_cpu(cifs_acl->default_entry_count);
2755 size += sizeof(struct cifs_posix_ace) * count;
2756 /* check if we would go beyond end of SMB */
2757 if (size_of_data_area < size)
2758 return -EINVAL;
2759 } else {
2760 /* illegal type */
2761 return -EINVAL;
2764 size = posix_acl_xattr_size(count);
2765 if ((buflen == 0) || (local_acl == NULL)) {
2766 /* used to query ACL EA size */
2767 } else if (size > buflen) {
2768 return -ERANGE;
2769 } else /* buffer big enough */ {
2770 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2771 for (i = 0; i < count ; i++) {
2772 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2773 pACE++;
2776 return size;
2779 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2780 const posix_acl_xattr_entry *local_ace)
2782 __u16 rc = 0; /* 0 = ACL converted ok */
2784 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2785 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2786 /* BB is there a better way to handle the large uid? */
2787 if (local_ace->e_id == cpu_to_le32(-1)) {
2788 /* Probably no need to le convert -1 on any arch but can not hurt */
2789 cifs_ace->cifs_uid = cpu_to_le64(-1);
2790 } else
2791 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2792 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2793 return rc;
2796 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2797 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2798 const int buflen, const int acl_type)
2800 __u16 rc = 0;
2801 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2802 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2803 int count;
2804 int i;
2806 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2807 return 0;
2809 count = posix_acl_xattr_count((size_t)buflen);
2810 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2811 "version of %d",
2812 count, buflen, le32_to_cpu(local_acl->a_version)));
2813 if (le32_to_cpu(local_acl->a_version) != 2) {
2814 cFYI(1, ("unknown POSIX ACL version %d",
2815 le32_to_cpu(local_acl->a_version)));
2816 return 0;
2818 cifs_acl->version = cpu_to_le16(1);
2819 if (acl_type == ACL_TYPE_ACCESS)
2820 cifs_acl->access_entry_count = cpu_to_le16(count);
2821 else if (acl_type == ACL_TYPE_DEFAULT)
2822 cifs_acl->default_entry_count = cpu_to_le16(count);
2823 else {
2824 cFYI(1, ("unknown ACL type %d", acl_type));
2825 return 0;
2827 for (i = 0; i < count; i++) {
2828 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2829 &local_acl->a_entries[i]);
2830 if (rc != 0) {
2831 /* ACE not converted */
2832 break;
2835 if (rc == 0) {
2836 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2837 rc += sizeof(struct cifs_posix_acl);
2838 /* BB add check to make sure ACL does not overflow SMB */
2840 return rc;
2844 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2845 const unsigned char *searchName,
2846 char *acl_inf, const int buflen, const int acl_type,
2847 const struct nls_table *nls_codepage, int remap)
2849 /* SMB_QUERY_POSIX_ACL */
2850 TRANSACTION2_QPI_REQ *pSMB = NULL;
2851 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2852 int rc = 0;
2853 int bytes_returned;
2854 int name_len;
2855 __u16 params, byte_count;
2857 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2859 queryAclRetry:
2860 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2861 (void **) &pSMBr);
2862 if (rc)
2863 return rc;
2865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2866 name_len =
2867 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2868 PATH_MAX, nls_codepage, remap);
2869 name_len++; /* trailing null */
2870 name_len *= 2;
2871 pSMB->FileName[name_len] = 0;
2872 pSMB->FileName[name_len+1] = 0;
2873 } else { /* BB improve the check for buffer overruns BB */
2874 name_len = strnlen(searchName, PATH_MAX);
2875 name_len++; /* trailing null */
2876 strncpy(pSMB->FileName, searchName, name_len);
2879 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2880 pSMB->TotalDataCount = 0;
2881 pSMB->MaxParameterCount = cpu_to_le16(2);
2882 /* BB find exact max data count below from sess structure BB */
2883 pSMB->MaxDataCount = cpu_to_le16(4000);
2884 pSMB->MaxSetupCount = 0;
2885 pSMB->Reserved = 0;
2886 pSMB->Flags = 0;
2887 pSMB->Timeout = 0;
2888 pSMB->Reserved2 = 0;
2889 pSMB->ParameterOffset = cpu_to_le16(
2890 offsetof(struct smb_com_transaction2_qpi_req,
2891 InformationLevel) - 4);
2892 pSMB->DataCount = 0;
2893 pSMB->DataOffset = 0;
2894 pSMB->SetupCount = 1;
2895 pSMB->Reserved3 = 0;
2896 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2897 byte_count = params + 1 /* pad */ ;
2898 pSMB->TotalParameterCount = cpu_to_le16(params);
2899 pSMB->ParameterCount = pSMB->TotalParameterCount;
2900 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2901 pSMB->Reserved4 = 0;
2902 pSMB->hdr.smb_buf_length += byte_count;
2903 pSMB->ByteCount = cpu_to_le16(byte_count);
2905 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2906 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2907 cifs_stats_inc(&tcon->num_acl_get);
2908 if (rc) {
2909 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2910 } else {
2911 /* decode response */
2913 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2914 if (rc || (pSMBr->ByteCount < 2))
2915 /* BB also check enough total bytes returned */
2916 rc = -EIO; /* bad smb */
2917 else {
2918 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2919 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2920 rc = cifs_copy_posix_acl(acl_inf,
2921 (char *)&pSMBr->hdr.Protocol+data_offset,
2922 buflen, acl_type, count);
2925 cifs_buf_release(pSMB);
2926 if (rc == -EAGAIN)
2927 goto queryAclRetry;
2928 return rc;
2932 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2933 const unsigned char *fileName,
2934 const char *local_acl, const int buflen,
2935 const int acl_type,
2936 const struct nls_table *nls_codepage, int remap)
2938 struct smb_com_transaction2_spi_req *pSMB = NULL;
2939 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2940 char *parm_data;
2941 int name_len;
2942 int rc = 0;
2943 int bytes_returned = 0;
2944 __u16 params, byte_count, data_count, param_offset, offset;
2946 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2947 setAclRetry:
2948 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2949 (void **) &pSMBr);
2950 if (rc)
2951 return rc;
2952 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2953 name_len =
2954 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2955 PATH_MAX, nls_codepage, remap);
2956 name_len++; /* trailing null */
2957 name_len *= 2;
2958 } else { /* BB improve the check for buffer overruns BB */
2959 name_len = strnlen(fileName, PATH_MAX);
2960 name_len++; /* trailing null */
2961 strncpy(pSMB->FileName, fileName, name_len);
2963 params = 6 + name_len;
2964 pSMB->MaxParameterCount = cpu_to_le16(2);
2965 /* BB find max SMB size from sess */
2966 pSMB->MaxDataCount = cpu_to_le16(1000);
2967 pSMB->MaxSetupCount = 0;
2968 pSMB->Reserved = 0;
2969 pSMB->Flags = 0;
2970 pSMB->Timeout = 0;
2971 pSMB->Reserved2 = 0;
2972 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2973 InformationLevel) - 4;
2974 offset = param_offset + params;
2975 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2976 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2978 /* convert to on the wire format for POSIX ACL */
2979 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2981 if (data_count == 0) {
2982 rc = -EOPNOTSUPP;
2983 goto setACLerrorExit;
2985 pSMB->DataOffset = cpu_to_le16(offset);
2986 pSMB->SetupCount = 1;
2987 pSMB->Reserved3 = 0;
2988 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2989 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2990 byte_count = 3 /* pad */ + params + data_count;
2991 pSMB->DataCount = cpu_to_le16(data_count);
2992 pSMB->TotalDataCount = pSMB->DataCount;
2993 pSMB->ParameterCount = cpu_to_le16(params);
2994 pSMB->TotalParameterCount = pSMB->ParameterCount;
2995 pSMB->Reserved4 = 0;
2996 pSMB->hdr.smb_buf_length += byte_count;
2997 pSMB->ByteCount = cpu_to_le16(byte_count);
2998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3000 if (rc)
3001 cFYI(1, ("Set POSIX ACL returned %d", rc));
3003 setACLerrorExit:
3004 cifs_buf_release(pSMB);
3005 if (rc == -EAGAIN)
3006 goto setAclRetry;
3007 return rc;
3010 /* BB fix tabs in this function FIXME BB */
3012 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
3013 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3015 int rc = 0;
3016 struct smb_t2_qfi_req *pSMB = NULL;
3017 struct smb_t2_qfi_rsp *pSMBr = NULL;
3018 int bytes_returned;
3019 __u16 params, byte_count;
3021 cFYI(1, ("In GetExtAttr"));
3022 if (tcon == NULL)
3023 return -ENODEV;
3025 GetExtAttrRetry:
3026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3027 (void **) &pSMBr);
3028 if (rc)
3029 return rc;
3031 params = 2 /* level */ + 2 /* fid */;
3032 pSMB->t2.TotalDataCount = 0;
3033 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3034 /* BB find exact max data count below from sess structure BB */
3035 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3036 pSMB->t2.MaxSetupCount = 0;
3037 pSMB->t2.Reserved = 0;
3038 pSMB->t2.Flags = 0;
3039 pSMB->t2.Timeout = 0;
3040 pSMB->t2.Reserved2 = 0;
3041 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3042 Fid) - 4);
3043 pSMB->t2.DataCount = 0;
3044 pSMB->t2.DataOffset = 0;
3045 pSMB->t2.SetupCount = 1;
3046 pSMB->t2.Reserved3 = 0;
3047 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3048 byte_count = params + 1 /* pad */ ;
3049 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3050 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3051 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3052 pSMB->Pad = 0;
3053 pSMB->Fid = netfid;
3054 pSMB->hdr.smb_buf_length += byte_count;
3055 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3057 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3058 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3059 if (rc) {
3060 cFYI(1, ("error %d in GetExtAttr", rc));
3061 } else {
3062 /* decode response */
3063 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3064 if (rc || (pSMBr->ByteCount < 2))
3065 /* BB also check enough total bytes returned */
3066 /* If rc should we check for EOPNOSUPP and
3067 disable the srvino flag? or in caller? */
3068 rc = -EIO; /* bad smb */
3069 else {
3070 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3071 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3072 struct file_chattr_info *pfinfo;
3073 /* BB Do we need a cast or hash here ? */
3074 if (count != 16) {
3075 cFYI(1, ("Illegal size ret in GetExtAttr"));
3076 rc = -EIO;
3077 goto GetExtAttrOut;
3079 pfinfo = (struct file_chattr_info *)
3080 (data_offset + (char *) &pSMBr->hdr.Protocol);
3081 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3082 *pMask = le64_to_cpu(pfinfo->mask);
3085 GetExtAttrOut:
3086 cifs_buf_release(pSMB);
3087 if (rc == -EAGAIN)
3088 goto GetExtAttrRetry;
3089 return rc;
3092 #endif /* CONFIG_POSIX */
3094 #ifdef CONFIG_CIFS_EXPERIMENTAL
3095 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3097 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3098 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3100 int rc = 0;
3101 int buf_type = 0;
3102 QUERY_SEC_DESC_REQ *pSMB;
3103 struct kvec iov[1];
3105 cFYI(1, ("GetCifsACL"));
3107 *pbuflen = 0;
3108 *acl_inf = NULL;
3110 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3111 8 /* parm len */, tcon, (void **) &pSMB);
3112 if (rc)
3113 return rc;
3115 pSMB->MaxParameterCount = cpu_to_le32(4);
3116 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3117 pSMB->MaxSetupCount = 0;
3118 pSMB->Fid = fid; /* file handle always le */
3119 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3120 CIFS_ACL_DACL);
3121 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3122 pSMB->hdr.smb_buf_length += 11;
3123 iov[0].iov_base = (char *)pSMB;
3124 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3126 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3127 CIFS_STD_OP);
3128 cifs_stats_inc(&tcon->num_acl_get);
3129 if (rc) {
3130 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3131 } else { /* decode response */
3132 __le32 *parm;
3133 __u32 parm_len;
3134 __u32 acl_len;
3135 struct smb_com_ntransact_rsp *pSMBr;
3136 char *pdata;
3138 /* validate_nttransact */
3139 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3140 &pdata, &parm_len, pbuflen);
3141 if (rc)
3142 goto qsec_out;
3143 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3145 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3147 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3148 rc = -EIO; /* bad smb */
3149 *pbuflen = 0;
3150 goto qsec_out;
3153 /* BB check that data area is minimum length and as big as acl_len */
3155 acl_len = le32_to_cpu(*parm);
3156 if (acl_len != *pbuflen) {
3157 cERROR(1, ("acl length %d does not match %d",
3158 acl_len, *pbuflen));
3159 if (*pbuflen > acl_len)
3160 *pbuflen = acl_len;
3163 /* check if buffer is big enough for the acl
3164 header followed by the smallest SID */
3165 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3166 (*pbuflen >= 64 * 1024)) {
3167 cERROR(1, ("bad acl length %d", *pbuflen));
3168 rc = -EINVAL;
3169 *pbuflen = 0;
3170 } else {
3171 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3172 if (*acl_inf == NULL) {
3173 *pbuflen = 0;
3174 rc = -ENOMEM;
3176 memcpy(*acl_inf, pdata, *pbuflen);
3179 qsec_out:
3180 if (buf_type == CIFS_SMALL_BUFFER)
3181 cifs_small_buf_release(iov[0].iov_base);
3182 else if (buf_type == CIFS_LARGE_BUFFER)
3183 cifs_buf_release(iov[0].iov_base);
3184 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3185 return rc;
3189 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3190 struct cifs_ntsd *pntsd, __u32 acllen)
3192 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3193 int rc = 0;
3194 int bytes_returned = 0;
3195 SET_SEC_DESC_REQ *pSMB = NULL;
3196 NTRANSACT_RSP *pSMBr = NULL;
3198 setCifsAclRetry:
3199 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3200 (void **) &pSMBr);
3201 if (rc)
3202 return (rc);
3204 pSMB->MaxSetupCount = 0;
3205 pSMB->Reserved = 0;
3207 param_count = 8;
3208 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3209 data_count = acllen;
3210 data_offset = param_offset + param_count;
3211 byte_count = 3 /* pad */ + param_count;
3213 pSMB->DataCount = cpu_to_le32(data_count);
3214 pSMB->TotalDataCount = pSMB->DataCount;
3215 pSMB->MaxParameterCount = cpu_to_le32(4);
3216 pSMB->MaxDataCount = cpu_to_le32(16384);
3217 pSMB->ParameterCount = cpu_to_le32(param_count);
3218 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3219 pSMB->TotalParameterCount = pSMB->ParameterCount;
3220 pSMB->DataOffset = cpu_to_le32(data_offset);
3221 pSMB->SetupCount = 0;
3222 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3223 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3225 pSMB->Fid = fid; /* file handle always le */
3226 pSMB->Reserved2 = 0;
3227 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3229 if (pntsd && acllen) {
3230 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3231 (char *) pntsd,
3232 acllen);
3233 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3235 } else
3236 pSMB->hdr.smb_buf_length += byte_count;
3238 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3239 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3241 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3242 if (rc)
3243 cFYI(1, ("Set CIFS ACL returned %d", rc));
3244 cifs_buf_release(pSMB);
3246 if (rc == -EAGAIN)
3247 goto setCifsAclRetry;
3249 return (rc);
3252 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3254 /* Legacy Query Path Information call for lookup to old servers such
3255 as Win9x/WinME */
3256 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3257 const unsigned char *searchName,
3258 FILE_ALL_INFO *pFinfo,
3259 const struct nls_table *nls_codepage, int remap)
3261 QUERY_INFORMATION_REQ *pSMB;
3262 QUERY_INFORMATION_RSP *pSMBr;
3263 int rc = 0;
3264 int bytes_returned;
3265 int name_len;
3267 cFYI(1, ("In SMBQPath path %s", searchName));
3268 QInfRetry:
3269 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3270 (void **) &pSMBr);
3271 if (rc)
3272 return rc;
3274 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3275 name_len =
3276 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3277 PATH_MAX, nls_codepage, remap);
3278 name_len++; /* trailing null */
3279 name_len *= 2;
3280 } else {
3281 name_len = strnlen(searchName, PATH_MAX);
3282 name_len++; /* trailing null */
3283 strncpy(pSMB->FileName, searchName, name_len);
3285 pSMB->BufferFormat = 0x04;
3286 name_len++; /* account for buffer type byte */
3287 pSMB->hdr.smb_buf_length += (__u16) name_len;
3288 pSMB->ByteCount = cpu_to_le16(name_len);
3290 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3291 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3292 if (rc) {
3293 cFYI(1, ("Send error in QueryInfo = %d", rc));
3294 } else if (pFinfo) {
3295 struct timespec ts;
3296 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3298 /* decode response */
3299 /* BB FIXME - add time zone adjustment BB */
3300 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3301 ts.tv_nsec = 0;
3302 ts.tv_sec = time;
3303 /* decode time fields */
3304 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3305 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3306 pFinfo->LastAccessTime = 0;
3307 pFinfo->AllocationSize =
3308 cpu_to_le64(le32_to_cpu(pSMBr->size));
3309 pFinfo->EndOfFile = pFinfo->AllocationSize;
3310 pFinfo->Attributes =
3311 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3312 } else
3313 rc = -EIO; /* bad buffer passed in */
3315 cifs_buf_release(pSMB);
3317 if (rc == -EAGAIN)
3318 goto QInfRetry;
3320 return rc;
3327 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3328 const unsigned char *searchName,
3329 FILE_ALL_INFO *pFindData,
3330 int legacy /* old style infolevel */,
3331 const struct nls_table *nls_codepage, int remap)
3333 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3334 TRANSACTION2_QPI_REQ *pSMB = NULL;
3335 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3336 int rc = 0;
3337 int bytes_returned;
3338 int name_len;
3339 __u16 params, byte_count;
3341 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3342 QPathInfoRetry:
3343 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3344 (void **) &pSMBr);
3345 if (rc)
3346 return rc;
3348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3349 name_len =
3350 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3351 PATH_MAX, nls_codepage, remap);
3352 name_len++; /* trailing null */
3353 name_len *= 2;
3354 } else { /* BB improve the check for buffer overruns BB */
3355 name_len = strnlen(searchName, PATH_MAX);
3356 name_len++; /* trailing null */
3357 strncpy(pSMB->FileName, searchName, name_len);
3360 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3361 pSMB->TotalDataCount = 0;
3362 pSMB->MaxParameterCount = cpu_to_le16(2);
3363 /* BB find exact max SMB PDU from sess structure BB */
3364 pSMB->MaxDataCount = cpu_to_le16(4000);
3365 pSMB->MaxSetupCount = 0;
3366 pSMB->Reserved = 0;
3367 pSMB->Flags = 0;
3368 pSMB->Timeout = 0;
3369 pSMB->Reserved2 = 0;
3370 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3371 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3372 pSMB->DataCount = 0;
3373 pSMB->DataOffset = 0;
3374 pSMB->SetupCount = 1;
3375 pSMB->Reserved3 = 0;
3376 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3377 byte_count = params + 1 /* pad */ ;
3378 pSMB->TotalParameterCount = cpu_to_le16(params);
3379 pSMB->ParameterCount = pSMB->TotalParameterCount;
3380 if (legacy)
3381 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3382 else
3383 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3384 pSMB->Reserved4 = 0;
3385 pSMB->hdr.smb_buf_length += byte_count;
3386 pSMB->ByteCount = cpu_to_le16(byte_count);
3388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3389 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3390 if (rc) {
3391 cFYI(1, ("Send error in QPathInfo = %d", rc));
3392 } else { /* decode response */
3393 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3395 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3396 rc = -EIO;
3397 else if (!legacy && (pSMBr->ByteCount < 40))
3398 rc = -EIO; /* bad smb */
3399 else if (legacy && (pSMBr->ByteCount < 24))
3400 rc = -EIO; /* 24 or 26 expected but we do not read
3401 last field */
3402 else if (pFindData) {
3403 int size;
3404 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3406 /* On legacy responses we do not read the last field,
3407 EAsize, fortunately since it varies by subdialect and
3408 also note it differs on Set vs. Get, ie two bytes or 4
3409 bytes depending but we don't care here */
3410 if (legacy)
3411 size = sizeof(FILE_INFO_STANDARD);
3412 else
3413 size = sizeof(FILE_ALL_INFO);
3414 memcpy((char *) pFindData,
3415 (char *) &pSMBr->hdr.Protocol +
3416 data_offset, size);
3417 } else
3418 rc = -ENOMEM;
3420 cifs_buf_release(pSMB);
3421 if (rc == -EAGAIN)
3422 goto QPathInfoRetry;
3424 return rc;
3428 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3429 const unsigned char *searchName,
3430 FILE_UNIX_BASIC_INFO *pFindData,
3431 const struct nls_table *nls_codepage, int remap)
3433 /* SMB_QUERY_FILE_UNIX_BASIC */
3434 TRANSACTION2_QPI_REQ *pSMB = NULL;
3435 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3436 int rc = 0;
3437 int bytes_returned = 0;
3438 int name_len;
3439 __u16 params, byte_count;
3441 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3442 UnixQPathInfoRetry:
3443 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3444 (void **) &pSMBr);
3445 if (rc)
3446 return rc;
3448 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3449 name_len =
3450 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3451 PATH_MAX, nls_codepage, remap);
3452 name_len++; /* trailing null */
3453 name_len *= 2;
3454 } else { /* BB improve the check for buffer overruns BB */
3455 name_len = strnlen(searchName, PATH_MAX);
3456 name_len++; /* trailing null */
3457 strncpy(pSMB->FileName, searchName, name_len);
3460 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3461 pSMB->TotalDataCount = 0;
3462 pSMB->MaxParameterCount = cpu_to_le16(2);
3463 /* BB find exact max SMB PDU from sess structure BB */
3464 pSMB->MaxDataCount = cpu_to_le16(4000);
3465 pSMB->MaxSetupCount = 0;
3466 pSMB->Reserved = 0;
3467 pSMB->Flags = 0;
3468 pSMB->Timeout = 0;
3469 pSMB->Reserved2 = 0;
3470 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3471 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3472 pSMB->DataCount = 0;
3473 pSMB->DataOffset = 0;
3474 pSMB->SetupCount = 1;
3475 pSMB->Reserved3 = 0;
3476 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3477 byte_count = params + 1 /* pad */ ;
3478 pSMB->TotalParameterCount = cpu_to_le16(params);
3479 pSMB->ParameterCount = pSMB->TotalParameterCount;
3480 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3481 pSMB->Reserved4 = 0;
3482 pSMB->hdr.smb_buf_length += byte_count;
3483 pSMB->ByteCount = cpu_to_le16(byte_count);
3485 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3486 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3487 if (rc) {
3488 cFYI(1, ("Send error in QPathInfo = %d", rc));
3489 } else { /* decode response */
3490 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3492 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3493 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3494 "Unix Extensions can be disabled on mount "
3495 "by specifying the nosfu mount option."));
3496 rc = -EIO; /* bad smb */
3497 } else {
3498 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3499 memcpy((char *) pFindData,
3500 (char *) &pSMBr->hdr.Protocol +
3501 data_offset,
3502 sizeof(FILE_UNIX_BASIC_INFO));
3505 cifs_buf_release(pSMB);
3506 if (rc == -EAGAIN)
3507 goto UnixQPathInfoRetry;
3509 return rc;
3512 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3514 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3515 const char *searchName,
3516 const struct nls_table *nls_codepage,
3517 __u16 *pnetfid,
3518 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3520 /* level 257 SMB_ */
3521 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3522 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3523 T2_FFIRST_RSP_PARMS *parms;
3524 int rc = 0;
3525 int bytes_returned = 0;
3526 int name_len;
3527 __u16 params, byte_count;
3529 cFYI(1, ("In FindFirst for %s", searchName));
3531 findFirstRetry:
3532 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3533 (void **) &pSMBr);
3534 if (rc)
3535 return rc;
3537 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3538 name_len =
3539 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3540 PATH_MAX, nls_codepage, remap);
3541 /* We can not add the asterik earlier in case
3542 it got remapped to 0xF03A as if it were part of the
3543 directory name instead of a wildcard */
3544 name_len *= 2;
3545 pSMB->FileName[name_len] = dirsep;
3546 pSMB->FileName[name_len+1] = 0;
3547 pSMB->FileName[name_len+2] = '*';
3548 pSMB->FileName[name_len+3] = 0;
3549 name_len += 4; /* now the trailing null */
3550 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3551 pSMB->FileName[name_len+1] = 0;
3552 name_len += 2;
3553 } else { /* BB add check for overrun of SMB buf BB */
3554 name_len = strnlen(searchName, PATH_MAX);
3555 /* BB fix here and in unicode clause above ie
3556 if (name_len > buffersize-header)
3557 free buffer exit; BB */
3558 strncpy(pSMB->FileName, searchName, name_len);
3559 pSMB->FileName[name_len] = dirsep;
3560 pSMB->FileName[name_len+1] = '*';
3561 pSMB->FileName[name_len+2] = 0;
3562 name_len += 3;
3565 params = 12 + name_len /* includes null */ ;
3566 pSMB->TotalDataCount = 0; /* no EAs */
3567 pSMB->MaxParameterCount = cpu_to_le16(10);
3568 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3569 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3570 pSMB->MaxSetupCount = 0;
3571 pSMB->Reserved = 0;
3572 pSMB->Flags = 0;
3573 pSMB->Timeout = 0;
3574 pSMB->Reserved2 = 0;
3575 byte_count = params + 1 /* pad */ ;
3576 pSMB->TotalParameterCount = cpu_to_le16(params);
3577 pSMB->ParameterCount = pSMB->TotalParameterCount;
3578 pSMB->ParameterOffset = cpu_to_le16(
3579 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3580 - 4);
3581 pSMB->DataCount = 0;
3582 pSMB->DataOffset = 0;
3583 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3584 pSMB->Reserved3 = 0;
3585 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3586 pSMB->SearchAttributes =
3587 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3588 ATTR_DIRECTORY);
3589 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3590 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3591 CIFS_SEARCH_RETURN_RESUME);
3592 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3594 /* BB what should we set StorageType to? Does it matter? BB */
3595 pSMB->SearchStorageType = 0;
3596 pSMB->hdr.smb_buf_length += byte_count;
3597 pSMB->ByteCount = cpu_to_le16(byte_count);
3599 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3600 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3601 cifs_stats_inc(&tcon->num_ffirst);
3603 if (rc) {/* BB add logic to retry regular search if Unix search
3604 rejected unexpectedly by server */
3605 /* BB Add code to handle unsupported level rc */
3606 cFYI(1, ("Error in FindFirst = %d", rc));
3608 cifs_buf_release(pSMB);
3610 /* BB eventually could optimize out free and realloc of buf */
3611 /* for this case */
3612 if (rc == -EAGAIN)
3613 goto findFirstRetry;
3614 } else { /* decode response */
3615 /* BB remember to free buffer if error BB */
3616 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3617 if (rc == 0) {
3618 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3619 psrch_inf->unicode = true;
3620 else
3621 psrch_inf->unicode = false;
3623 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3624 psrch_inf->smallBuf = 0;
3625 psrch_inf->srch_entries_start =
3626 (char *) &pSMBr->hdr.Protocol +
3627 le16_to_cpu(pSMBr->t2.DataOffset);
3628 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3629 le16_to_cpu(pSMBr->t2.ParameterOffset));
3631 if (parms->EndofSearch)
3632 psrch_inf->endOfSearch = true;
3633 else
3634 psrch_inf->endOfSearch = false;
3636 psrch_inf->entries_in_buffer =
3637 le16_to_cpu(parms->SearchCount);
3638 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3639 psrch_inf->entries_in_buffer;
3640 *pnetfid = parms->SearchHandle;
3641 } else {
3642 cifs_buf_release(pSMB);
3646 return rc;
3649 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3650 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3652 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3653 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3654 T2_FNEXT_RSP_PARMS *parms;
3655 char *response_data;
3656 int rc = 0;
3657 int bytes_returned, name_len;
3658 __u16 params, byte_count;
3660 cFYI(1, ("In FindNext"));
3662 if (psrch_inf->endOfSearch)
3663 return -ENOENT;
3665 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3666 (void **) &pSMBr);
3667 if (rc)
3668 return rc;
3670 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3671 byte_count = 0;
3672 pSMB->TotalDataCount = 0; /* no EAs */
3673 pSMB->MaxParameterCount = cpu_to_le16(8);
3674 pSMB->MaxDataCount =
3675 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3676 0xFFFFFF00);
3677 pSMB->MaxSetupCount = 0;
3678 pSMB->Reserved = 0;
3679 pSMB->Flags = 0;
3680 pSMB->Timeout = 0;
3681 pSMB->Reserved2 = 0;
3682 pSMB->ParameterOffset = cpu_to_le16(
3683 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3684 pSMB->DataCount = 0;
3685 pSMB->DataOffset = 0;
3686 pSMB->SetupCount = 1;
3687 pSMB->Reserved3 = 0;
3688 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3689 pSMB->SearchHandle = searchHandle; /* always kept as le */
3690 pSMB->SearchCount =
3691 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3692 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3693 pSMB->ResumeKey = psrch_inf->resume_key;
3694 pSMB->SearchFlags =
3695 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3697 name_len = psrch_inf->resume_name_len;
3698 params += name_len;
3699 if (name_len < PATH_MAX) {
3700 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3701 byte_count += name_len;
3702 /* 14 byte parm len above enough for 2 byte null terminator */
3703 pSMB->ResumeFileName[name_len] = 0;
3704 pSMB->ResumeFileName[name_len+1] = 0;
3705 } else {
3706 rc = -EINVAL;
3707 goto FNext2_err_exit;
3709 byte_count = params + 1 /* pad */ ;
3710 pSMB->TotalParameterCount = cpu_to_le16(params);
3711 pSMB->ParameterCount = pSMB->TotalParameterCount;
3712 pSMB->hdr.smb_buf_length += byte_count;
3713 pSMB->ByteCount = cpu_to_le16(byte_count);
3715 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3716 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3717 cifs_stats_inc(&tcon->num_fnext);
3718 if (rc) {
3719 if (rc == -EBADF) {
3720 psrch_inf->endOfSearch = true;
3721 cifs_buf_release(pSMB);
3722 rc = 0; /* search probably was closed at end of search*/
3723 } else
3724 cFYI(1, ("FindNext returned = %d", rc));
3725 } else { /* decode response */
3726 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3728 if (rc == 0) {
3729 /* BB fixme add lock for file (srch_info) struct here */
3730 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3731 psrch_inf->unicode = true;
3732 else
3733 psrch_inf->unicode = false;
3734 response_data = (char *) &pSMBr->hdr.Protocol +
3735 le16_to_cpu(pSMBr->t2.ParameterOffset);
3736 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3737 response_data = (char *)&pSMBr->hdr.Protocol +
3738 le16_to_cpu(pSMBr->t2.DataOffset);
3739 if (psrch_inf->smallBuf)
3740 cifs_small_buf_release(
3741 psrch_inf->ntwrk_buf_start);
3742 else
3743 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3744 psrch_inf->srch_entries_start = response_data;
3745 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3746 psrch_inf->smallBuf = 0;
3747 if (parms->EndofSearch)
3748 psrch_inf->endOfSearch = true;
3749 else
3750 psrch_inf->endOfSearch = false;
3751 psrch_inf->entries_in_buffer =
3752 le16_to_cpu(parms->SearchCount);
3753 psrch_inf->index_of_last_entry +=
3754 psrch_inf->entries_in_buffer;
3755 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3756 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3758 /* BB fixme add unlock here */
3763 /* BB On error, should we leave previous search buf (and count and
3764 last entry fields) intact or free the previous one? */
3766 /* Note: On -EAGAIN error only caller can retry on handle based calls
3767 since file handle passed in no longer valid */
3768 FNext2_err_exit:
3769 if (rc != 0)
3770 cifs_buf_release(pSMB);
3771 return rc;
3775 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3776 const __u16 searchHandle)
3778 int rc = 0;
3779 FINDCLOSE_REQ *pSMB = NULL;
3781 cFYI(1, ("In CIFSSMBFindClose"));
3782 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3784 /* no sense returning error if session restarted
3785 as file handle has been closed */
3786 if (rc == -EAGAIN)
3787 return 0;
3788 if (rc)
3789 return rc;
3791 pSMB->FileID = searchHandle;
3792 pSMB->ByteCount = 0;
3793 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3794 if (rc)
3795 cERROR(1, ("Send error in FindClose = %d", rc));
3797 cifs_stats_inc(&tcon->num_fclose);
3799 /* Since session is dead, search handle closed on server already */
3800 if (rc == -EAGAIN)
3801 rc = 0;
3803 return rc;
3807 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3808 const unsigned char *searchName,
3809 __u64 *inode_number,
3810 const struct nls_table *nls_codepage, int remap)
3812 int rc = 0;
3813 TRANSACTION2_QPI_REQ *pSMB = NULL;
3814 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3815 int name_len, bytes_returned;
3816 __u16 params, byte_count;
3818 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3819 if (tcon == NULL)
3820 return -ENODEV;
3822 GetInodeNumberRetry:
3823 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3824 (void **) &pSMBr);
3825 if (rc)
3826 return rc;
3828 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3829 name_len =
3830 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3831 PATH_MAX, nls_codepage, remap);
3832 name_len++; /* trailing null */
3833 name_len *= 2;
3834 } else { /* BB improve the check for buffer overruns BB */
3835 name_len = strnlen(searchName, PATH_MAX);
3836 name_len++; /* trailing null */
3837 strncpy(pSMB->FileName, searchName, name_len);
3840 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3841 pSMB->TotalDataCount = 0;
3842 pSMB->MaxParameterCount = cpu_to_le16(2);
3843 /* BB find exact max data count below from sess structure BB */
3844 pSMB->MaxDataCount = cpu_to_le16(4000);
3845 pSMB->MaxSetupCount = 0;
3846 pSMB->Reserved = 0;
3847 pSMB->Flags = 0;
3848 pSMB->Timeout = 0;
3849 pSMB->Reserved2 = 0;
3850 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3851 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3852 pSMB->DataCount = 0;
3853 pSMB->DataOffset = 0;
3854 pSMB->SetupCount = 1;
3855 pSMB->Reserved3 = 0;
3856 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3857 byte_count = params + 1 /* pad */ ;
3858 pSMB->TotalParameterCount = cpu_to_le16(params);
3859 pSMB->ParameterCount = pSMB->TotalParameterCount;
3860 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3861 pSMB->Reserved4 = 0;
3862 pSMB->hdr.smb_buf_length += byte_count;
3863 pSMB->ByteCount = cpu_to_le16(byte_count);
3865 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3866 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3867 if (rc) {
3868 cFYI(1, ("error %d in QueryInternalInfo", rc));
3869 } else {
3870 /* decode response */
3871 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3872 if (rc || (pSMBr->ByteCount < 2))
3873 /* BB also check enough total bytes returned */
3874 /* If rc should we check for EOPNOSUPP and
3875 disable the srvino flag? or in caller? */
3876 rc = -EIO; /* bad smb */
3877 else {
3878 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3879 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3880 struct file_internal_info *pfinfo;
3881 /* BB Do we need a cast or hash here ? */
3882 if (count < 8) {
3883 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3884 rc = -EIO;
3885 goto GetInodeNumOut;
3887 pfinfo = (struct file_internal_info *)
3888 (data_offset + (char *) &pSMBr->hdr.Protocol);
3889 *inode_number = pfinfo->UniqueId;
3892 GetInodeNumOut:
3893 cifs_buf_release(pSMB);
3894 if (rc == -EAGAIN)
3895 goto GetInodeNumberRetry;
3896 return rc;
3899 /* parses DFS refferal V3 structure
3900 * caller is responsible for freeing target_nodes
3901 * returns:
3902 * on success - 0
3903 * on failure - errno
3905 static int
3906 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3907 unsigned int *num_of_nodes,
3908 struct dfs_info3_param **target_nodes,
3909 const struct nls_table *nls_codepage)
3911 int i, rc = 0;
3912 char *data_end;
3913 bool is_unicode;
3914 struct dfs_referral_level_3 *ref;
3916 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3917 is_unicode = true;
3918 else
3919 is_unicode = false;
3920 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3922 if (*num_of_nodes < 1) {
3923 cERROR(1, ("num_referrals: must be at least > 0,"
3924 "but we get num_referrals = %d\n", *num_of_nodes));
3925 rc = -EINVAL;
3926 goto parse_DFS_referrals_exit;
3929 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3930 if (ref->VersionNumber != cpu_to_le16(3)) {
3931 cERROR(1, ("Referrals of V%d version are not supported,"
3932 "should be V3", le16_to_cpu(ref->VersionNumber)));
3933 rc = -EINVAL;
3934 goto parse_DFS_referrals_exit;
3937 /* get the upper boundary of the resp buffer */
3938 data_end = (char *)(&(pSMBr->PathConsumed)) +
3939 le16_to_cpu(pSMBr->t2.DataCount);
3941 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3942 *num_of_nodes,
3943 le16_to_cpu(pSMBr->DFSFlags)));
3945 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3946 *num_of_nodes, GFP_KERNEL);
3947 if (*target_nodes == NULL) {
3948 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3949 rc = -ENOMEM;
3950 goto parse_DFS_referrals_exit;
3953 /* collect neccessary data from referrals */
3954 for (i = 0; i < *num_of_nodes; i++) {
3955 char *temp;
3956 int max_len;
3957 struct dfs_info3_param *node = (*target_nodes)+i;
3959 node->flags = le16_to_cpu(pSMBr->DFSFlags);
3960 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3961 node->server_type = le16_to_cpu(ref->ServerType);
3962 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3964 /* copy DfsPath */
3965 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3966 max_len = data_end - temp;
3967 rc = cifs_strncpy_to_host(&(node->path_name), temp,
3968 max_len, is_unicode, nls_codepage);
3969 if (rc)
3970 goto parse_DFS_referrals_exit;
3972 /* copy link target UNC */
3973 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3974 max_len = data_end - temp;
3975 rc = cifs_strncpy_to_host(&(node->node_name), temp,
3976 max_len, is_unicode, nls_codepage);
3977 if (rc)
3978 goto parse_DFS_referrals_exit;
3980 ref += le16_to_cpu(ref->Size);
3983 parse_DFS_referrals_exit:
3984 if (rc) {
3985 free_dfs_info_array(*target_nodes, *num_of_nodes);
3986 *target_nodes = NULL;
3987 *num_of_nodes = 0;
3989 return rc;
3993 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3994 const unsigned char *searchName,
3995 struct dfs_info3_param **target_nodes,
3996 unsigned int *num_of_nodes,
3997 const struct nls_table *nls_codepage, int remap)
3999 /* TRANS2_GET_DFS_REFERRAL */
4000 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4001 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4002 int rc = 0;
4003 int bytes_returned;
4004 int name_len;
4005 __u16 params, byte_count;
4006 *num_of_nodes = 0;
4007 *target_nodes = NULL;
4009 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4010 if (ses == NULL)
4011 return -ENODEV;
4012 getDFSRetry:
4013 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4014 (void **) &pSMBr);
4015 if (rc)
4016 return rc;
4018 /* server pointer checked in called function,
4019 but should never be null here anyway */
4020 pSMB->hdr.Mid = GetNextMid(ses->server);
4021 pSMB->hdr.Tid = ses->ipc_tid;
4022 pSMB->hdr.Uid = ses->Suid;
4023 if (ses->capabilities & CAP_STATUS32)
4024 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4025 if (ses->capabilities & CAP_DFS)
4026 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4028 if (ses->capabilities & CAP_UNICODE) {
4029 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4030 name_len =
4031 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4032 searchName, PATH_MAX, nls_codepage, remap);
4033 name_len++; /* trailing null */
4034 name_len *= 2;
4035 } else { /* BB improve the check for buffer overruns BB */
4036 name_len = strnlen(searchName, PATH_MAX);
4037 name_len++; /* trailing null */
4038 strncpy(pSMB->RequestFileName, searchName, name_len);
4041 if (ses->server) {
4042 if (ses->server->secMode &
4043 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4044 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4047 pSMB->hdr.Uid = ses->Suid;
4049 params = 2 /* level */ + name_len /*includes null */ ;
4050 pSMB->TotalDataCount = 0;
4051 pSMB->DataCount = 0;
4052 pSMB->DataOffset = 0;
4053 pSMB->MaxParameterCount = 0;
4054 /* BB find exact max SMB PDU from sess structure BB */
4055 pSMB->MaxDataCount = cpu_to_le16(4000);
4056 pSMB->MaxSetupCount = 0;
4057 pSMB->Reserved = 0;
4058 pSMB->Flags = 0;
4059 pSMB->Timeout = 0;
4060 pSMB->Reserved2 = 0;
4061 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4062 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4063 pSMB->SetupCount = 1;
4064 pSMB->Reserved3 = 0;
4065 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4066 byte_count = params + 3 /* pad */ ;
4067 pSMB->ParameterCount = cpu_to_le16(params);
4068 pSMB->TotalParameterCount = pSMB->ParameterCount;
4069 pSMB->MaxReferralLevel = cpu_to_le16(3);
4070 pSMB->hdr.smb_buf_length += byte_count;
4071 pSMB->ByteCount = cpu_to_le16(byte_count);
4073 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4075 if (rc) {
4076 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4077 goto GetDFSRefExit;
4079 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4081 /* BB Also check if enough total bytes returned? */
4082 if (rc || (pSMBr->ByteCount < 17)) {
4083 rc = -EIO; /* bad smb */
4084 goto GetDFSRefExit;
4087 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4088 pSMBr->ByteCount,
4089 le16_to_cpu(pSMBr->t2.DataOffset)));
4091 /* parse returned result into more usable form */
4092 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4093 target_nodes, nls_codepage);
4095 GetDFSRefExit:
4096 cifs_buf_release(pSMB);
4098 if (rc == -EAGAIN)
4099 goto getDFSRetry;
4101 return rc;
4104 /* Query File System Info such as free space to old servers such as Win 9x */
4106 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4108 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4109 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4110 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4111 FILE_SYSTEM_ALLOC_INFO *response_data;
4112 int rc = 0;
4113 int bytes_returned = 0;
4114 __u16 params, byte_count;
4116 cFYI(1, ("OldQFSInfo"));
4117 oldQFSInfoRetry:
4118 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4119 (void **) &pSMBr);
4120 if (rc)
4121 return rc;
4123 params = 2; /* level */
4124 pSMB->TotalDataCount = 0;
4125 pSMB->MaxParameterCount = cpu_to_le16(2);
4126 pSMB->MaxDataCount = cpu_to_le16(1000);
4127 pSMB->MaxSetupCount = 0;
4128 pSMB->Reserved = 0;
4129 pSMB->Flags = 0;
4130 pSMB->Timeout = 0;
4131 pSMB->Reserved2 = 0;
4132 byte_count = params + 1 /* pad */ ;
4133 pSMB->TotalParameterCount = cpu_to_le16(params);
4134 pSMB->ParameterCount = pSMB->TotalParameterCount;
4135 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4136 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4137 pSMB->DataCount = 0;
4138 pSMB->DataOffset = 0;
4139 pSMB->SetupCount = 1;
4140 pSMB->Reserved3 = 0;
4141 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4142 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4143 pSMB->hdr.smb_buf_length += byte_count;
4144 pSMB->ByteCount = cpu_to_le16(byte_count);
4146 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4147 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4148 if (rc) {
4149 cFYI(1, ("Send error in QFSInfo = %d", rc));
4150 } else { /* decode response */
4151 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4153 if (rc || (pSMBr->ByteCount < 18))
4154 rc = -EIO; /* bad smb */
4155 else {
4156 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4157 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4158 pSMBr->ByteCount, data_offset));
4160 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4161 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4162 FSData->f_bsize =
4163 le16_to_cpu(response_data->BytesPerSector) *
4164 le32_to_cpu(response_data->
4165 SectorsPerAllocationUnit);
4166 FSData->f_blocks =
4167 le32_to_cpu(response_data->TotalAllocationUnits);
4168 FSData->f_bfree = FSData->f_bavail =
4169 le32_to_cpu(response_data->FreeAllocationUnits);
4170 cFYI(1,
4171 ("Blocks: %lld Free: %lld Block size %ld",
4172 (unsigned long long)FSData->f_blocks,
4173 (unsigned long long)FSData->f_bfree,
4174 FSData->f_bsize));
4177 cifs_buf_release(pSMB);
4179 if (rc == -EAGAIN)
4180 goto oldQFSInfoRetry;
4182 return rc;
4186 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4188 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4189 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4190 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4191 FILE_SYSTEM_INFO *response_data;
4192 int rc = 0;
4193 int bytes_returned = 0;
4194 __u16 params, byte_count;
4196 cFYI(1, ("In QFSInfo"));
4197 QFSInfoRetry:
4198 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4199 (void **) &pSMBr);
4200 if (rc)
4201 return rc;
4203 params = 2; /* level */
4204 pSMB->TotalDataCount = 0;
4205 pSMB->MaxParameterCount = cpu_to_le16(2);
4206 pSMB->MaxDataCount = cpu_to_le16(1000);
4207 pSMB->MaxSetupCount = 0;
4208 pSMB->Reserved = 0;
4209 pSMB->Flags = 0;
4210 pSMB->Timeout = 0;
4211 pSMB->Reserved2 = 0;
4212 byte_count = params + 1 /* pad */ ;
4213 pSMB->TotalParameterCount = cpu_to_le16(params);
4214 pSMB->ParameterCount = pSMB->TotalParameterCount;
4215 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4216 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4217 pSMB->DataCount = 0;
4218 pSMB->DataOffset = 0;
4219 pSMB->SetupCount = 1;
4220 pSMB->Reserved3 = 0;
4221 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4222 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4223 pSMB->hdr.smb_buf_length += byte_count;
4224 pSMB->ByteCount = cpu_to_le16(byte_count);
4226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4227 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4228 if (rc) {
4229 cFYI(1, ("Send error in QFSInfo = %d", rc));
4230 } else { /* decode response */
4231 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4233 if (rc || (pSMBr->ByteCount < 24))
4234 rc = -EIO; /* bad smb */
4235 else {
4236 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4238 response_data =
4239 (FILE_SYSTEM_INFO
4240 *) (((char *) &pSMBr->hdr.Protocol) +
4241 data_offset);
4242 FSData->f_bsize =
4243 le32_to_cpu(response_data->BytesPerSector) *
4244 le32_to_cpu(response_data->
4245 SectorsPerAllocationUnit);
4246 FSData->f_blocks =
4247 le64_to_cpu(response_data->TotalAllocationUnits);
4248 FSData->f_bfree = FSData->f_bavail =
4249 le64_to_cpu(response_data->FreeAllocationUnits);
4250 cFYI(1,
4251 ("Blocks: %lld Free: %lld Block size %ld",
4252 (unsigned long long)FSData->f_blocks,
4253 (unsigned long long)FSData->f_bfree,
4254 FSData->f_bsize));
4257 cifs_buf_release(pSMB);
4259 if (rc == -EAGAIN)
4260 goto QFSInfoRetry;
4262 return rc;
4266 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4268 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4269 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4270 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4271 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4272 int rc = 0;
4273 int bytes_returned = 0;
4274 __u16 params, byte_count;
4276 cFYI(1, ("In QFSAttributeInfo"));
4277 QFSAttributeRetry:
4278 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4279 (void **) &pSMBr);
4280 if (rc)
4281 return rc;
4283 params = 2; /* level */
4284 pSMB->TotalDataCount = 0;
4285 pSMB->MaxParameterCount = cpu_to_le16(2);
4286 /* BB find exact max SMB PDU from sess structure BB */
4287 pSMB->MaxDataCount = cpu_to_le16(1000);
4288 pSMB->MaxSetupCount = 0;
4289 pSMB->Reserved = 0;
4290 pSMB->Flags = 0;
4291 pSMB->Timeout = 0;
4292 pSMB->Reserved2 = 0;
4293 byte_count = params + 1 /* pad */ ;
4294 pSMB->TotalParameterCount = cpu_to_le16(params);
4295 pSMB->ParameterCount = pSMB->TotalParameterCount;
4296 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4297 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4298 pSMB->DataCount = 0;
4299 pSMB->DataOffset = 0;
4300 pSMB->SetupCount = 1;
4301 pSMB->Reserved3 = 0;
4302 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4303 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4304 pSMB->hdr.smb_buf_length += byte_count;
4305 pSMB->ByteCount = cpu_to_le16(byte_count);
4307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4309 if (rc) {
4310 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4311 } else { /* decode response */
4312 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4314 if (rc || (pSMBr->ByteCount < 13)) {
4315 /* BB also check if enough bytes returned */
4316 rc = -EIO; /* bad smb */
4317 } else {
4318 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4319 response_data =
4320 (FILE_SYSTEM_ATTRIBUTE_INFO
4321 *) (((char *) &pSMBr->hdr.Protocol) +
4322 data_offset);
4323 memcpy(&tcon->fsAttrInfo, response_data,
4324 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4327 cifs_buf_release(pSMB);
4329 if (rc == -EAGAIN)
4330 goto QFSAttributeRetry;
4332 return rc;
4336 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4338 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4339 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4340 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4341 FILE_SYSTEM_DEVICE_INFO *response_data;
4342 int rc = 0;
4343 int bytes_returned = 0;
4344 __u16 params, byte_count;
4346 cFYI(1, ("In QFSDeviceInfo"));
4347 QFSDeviceRetry:
4348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4349 (void **) &pSMBr);
4350 if (rc)
4351 return rc;
4353 params = 2; /* level */
4354 pSMB->TotalDataCount = 0;
4355 pSMB->MaxParameterCount = cpu_to_le16(2);
4356 /* BB find exact max SMB PDU from sess structure BB */
4357 pSMB->MaxDataCount = cpu_to_le16(1000);
4358 pSMB->MaxSetupCount = 0;
4359 pSMB->Reserved = 0;
4360 pSMB->Flags = 0;
4361 pSMB->Timeout = 0;
4362 pSMB->Reserved2 = 0;
4363 byte_count = params + 1 /* pad */ ;
4364 pSMB->TotalParameterCount = cpu_to_le16(params);
4365 pSMB->ParameterCount = pSMB->TotalParameterCount;
4366 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4367 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4369 pSMB->DataCount = 0;
4370 pSMB->DataOffset = 0;
4371 pSMB->SetupCount = 1;
4372 pSMB->Reserved3 = 0;
4373 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4374 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4375 pSMB->hdr.smb_buf_length += byte_count;
4376 pSMB->ByteCount = cpu_to_le16(byte_count);
4378 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4379 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4380 if (rc) {
4381 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4382 } else { /* decode response */
4383 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4385 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4386 rc = -EIO; /* bad smb */
4387 else {
4388 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4389 response_data =
4390 (FILE_SYSTEM_DEVICE_INFO *)
4391 (((char *) &pSMBr->hdr.Protocol) +
4392 data_offset);
4393 memcpy(&tcon->fsDevInfo, response_data,
4394 sizeof(FILE_SYSTEM_DEVICE_INFO));
4397 cifs_buf_release(pSMB);
4399 if (rc == -EAGAIN)
4400 goto QFSDeviceRetry;
4402 return rc;
4406 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4408 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4409 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4410 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4411 FILE_SYSTEM_UNIX_INFO *response_data;
4412 int rc = 0;
4413 int bytes_returned = 0;
4414 __u16 params, byte_count;
4416 cFYI(1, ("In QFSUnixInfo"));
4417 QFSUnixRetry:
4418 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4419 (void **) &pSMBr);
4420 if (rc)
4421 return rc;
4423 params = 2; /* level */
4424 pSMB->TotalDataCount = 0;
4425 pSMB->DataCount = 0;
4426 pSMB->DataOffset = 0;
4427 pSMB->MaxParameterCount = cpu_to_le16(2);
4428 /* BB find exact max SMB PDU from sess structure BB */
4429 pSMB->MaxDataCount = cpu_to_le16(100);
4430 pSMB->MaxSetupCount = 0;
4431 pSMB->Reserved = 0;
4432 pSMB->Flags = 0;
4433 pSMB->Timeout = 0;
4434 pSMB->Reserved2 = 0;
4435 byte_count = params + 1 /* pad */ ;
4436 pSMB->ParameterCount = cpu_to_le16(params);
4437 pSMB->TotalParameterCount = pSMB->ParameterCount;
4438 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4439 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4440 pSMB->SetupCount = 1;
4441 pSMB->Reserved3 = 0;
4442 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4443 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4444 pSMB->hdr.smb_buf_length += byte_count;
4445 pSMB->ByteCount = cpu_to_le16(byte_count);
4447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4449 if (rc) {
4450 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4451 } else { /* decode response */
4452 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4454 if (rc || (pSMBr->ByteCount < 13)) {
4455 rc = -EIO; /* bad smb */
4456 } else {
4457 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4458 response_data =
4459 (FILE_SYSTEM_UNIX_INFO
4460 *) (((char *) &pSMBr->hdr.Protocol) +
4461 data_offset);
4462 memcpy(&tcon->fsUnixInfo, response_data,
4463 sizeof(FILE_SYSTEM_UNIX_INFO));
4466 cifs_buf_release(pSMB);
4468 if (rc == -EAGAIN)
4469 goto QFSUnixRetry;
4472 return rc;
4476 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4478 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4479 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4480 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4481 int rc = 0;
4482 int bytes_returned = 0;
4483 __u16 params, param_offset, offset, byte_count;
4485 cFYI(1, ("In SETFSUnixInfo"));
4486 SETFSUnixRetry:
4487 /* BB switch to small buf init to save memory */
4488 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4489 (void **) &pSMBr);
4490 if (rc)
4491 return rc;
4493 params = 4; /* 2 bytes zero followed by info level. */
4494 pSMB->MaxSetupCount = 0;
4495 pSMB->Reserved = 0;
4496 pSMB->Flags = 0;
4497 pSMB->Timeout = 0;
4498 pSMB->Reserved2 = 0;
4499 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4500 - 4;
4501 offset = param_offset + params;
4503 pSMB->MaxParameterCount = cpu_to_le16(4);
4504 /* BB find exact max SMB PDU from sess structure BB */
4505 pSMB->MaxDataCount = cpu_to_le16(100);
4506 pSMB->SetupCount = 1;
4507 pSMB->Reserved3 = 0;
4508 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4509 byte_count = 1 /* pad */ + params + 12;
4511 pSMB->DataCount = cpu_to_le16(12);
4512 pSMB->ParameterCount = cpu_to_le16(params);
4513 pSMB->TotalDataCount = pSMB->DataCount;
4514 pSMB->TotalParameterCount = pSMB->ParameterCount;
4515 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4516 pSMB->DataOffset = cpu_to_le16(offset);
4518 /* Params. */
4519 pSMB->FileNum = 0;
4520 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4522 /* Data. */
4523 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4524 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4525 pSMB->ClientUnixCap = cpu_to_le64(cap);
4527 pSMB->hdr.smb_buf_length += byte_count;
4528 pSMB->ByteCount = cpu_to_le16(byte_count);
4530 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4531 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4532 if (rc) {
4533 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4534 } else { /* decode response */
4535 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4536 if (rc)
4537 rc = -EIO; /* bad smb */
4539 cifs_buf_release(pSMB);
4541 if (rc == -EAGAIN)
4542 goto SETFSUnixRetry;
4544 return rc;
4550 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4551 struct kstatfs *FSData)
4553 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4554 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4555 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4556 FILE_SYSTEM_POSIX_INFO *response_data;
4557 int rc = 0;
4558 int bytes_returned = 0;
4559 __u16 params, byte_count;
4561 cFYI(1, ("In QFSPosixInfo"));
4562 QFSPosixRetry:
4563 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4564 (void **) &pSMBr);
4565 if (rc)
4566 return rc;
4568 params = 2; /* level */
4569 pSMB->TotalDataCount = 0;
4570 pSMB->DataCount = 0;
4571 pSMB->DataOffset = 0;
4572 pSMB->MaxParameterCount = cpu_to_le16(2);
4573 /* BB find exact max SMB PDU from sess structure BB */
4574 pSMB->MaxDataCount = cpu_to_le16(100);
4575 pSMB->MaxSetupCount = 0;
4576 pSMB->Reserved = 0;
4577 pSMB->Flags = 0;
4578 pSMB->Timeout = 0;
4579 pSMB->Reserved2 = 0;
4580 byte_count = params + 1 /* pad */ ;
4581 pSMB->ParameterCount = cpu_to_le16(params);
4582 pSMB->TotalParameterCount = pSMB->ParameterCount;
4583 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4584 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4585 pSMB->SetupCount = 1;
4586 pSMB->Reserved3 = 0;
4587 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4588 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4589 pSMB->hdr.smb_buf_length += byte_count;
4590 pSMB->ByteCount = cpu_to_le16(byte_count);
4592 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4593 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4594 if (rc) {
4595 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4596 } else { /* decode response */
4597 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4599 if (rc || (pSMBr->ByteCount < 13)) {
4600 rc = -EIO; /* bad smb */
4601 } else {
4602 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4603 response_data =
4604 (FILE_SYSTEM_POSIX_INFO
4605 *) (((char *) &pSMBr->hdr.Protocol) +
4606 data_offset);
4607 FSData->f_bsize =
4608 le32_to_cpu(response_data->BlockSize);
4609 FSData->f_blocks =
4610 le64_to_cpu(response_data->TotalBlocks);
4611 FSData->f_bfree =
4612 le64_to_cpu(response_data->BlocksAvail);
4613 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4614 FSData->f_bavail = FSData->f_bfree;
4615 } else {
4616 FSData->f_bavail =
4617 le64_to_cpu(response_data->UserBlocksAvail);
4619 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4620 FSData->f_files =
4621 le64_to_cpu(response_data->TotalFileNodes);
4622 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4623 FSData->f_ffree =
4624 le64_to_cpu(response_data->FreeFileNodes);
4627 cifs_buf_release(pSMB);
4629 if (rc == -EAGAIN)
4630 goto QFSPosixRetry;
4632 return rc;
4636 /* We can not use write of zero bytes trick to
4637 set file size due to need for large file support. Also note that
4638 this SetPathInfo is preferred to SetFileInfo based method in next
4639 routine which is only needed to work around a sharing violation bug
4640 in Samba which this routine can run into */
4643 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4644 __u64 size, bool SetAllocation,
4645 const struct nls_table *nls_codepage, int remap)
4647 struct smb_com_transaction2_spi_req *pSMB = NULL;
4648 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4649 struct file_end_of_file_info *parm_data;
4650 int name_len;
4651 int rc = 0;
4652 int bytes_returned = 0;
4653 __u16 params, byte_count, data_count, param_offset, offset;
4655 cFYI(1, ("In SetEOF"));
4656 SetEOFRetry:
4657 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4658 (void **) &pSMBr);
4659 if (rc)
4660 return rc;
4662 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4663 name_len =
4664 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4665 PATH_MAX, nls_codepage, remap);
4666 name_len++; /* trailing null */
4667 name_len *= 2;
4668 } else { /* BB improve the check for buffer overruns BB */
4669 name_len = strnlen(fileName, PATH_MAX);
4670 name_len++; /* trailing null */
4671 strncpy(pSMB->FileName, fileName, name_len);
4673 params = 6 + name_len;
4674 data_count = sizeof(struct file_end_of_file_info);
4675 pSMB->MaxParameterCount = cpu_to_le16(2);
4676 pSMB->MaxDataCount = cpu_to_le16(4100);
4677 pSMB->MaxSetupCount = 0;
4678 pSMB->Reserved = 0;
4679 pSMB->Flags = 0;
4680 pSMB->Timeout = 0;
4681 pSMB->Reserved2 = 0;
4682 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4683 InformationLevel) - 4;
4684 offset = param_offset + params;
4685 if (SetAllocation) {
4686 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4687 pSMB->InformationLevel =
4688 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4689 else
4690 pSMB->InformationLevel =
4691 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4692 } else /* Set File Size */ {
4693 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4694 pSMB->InformationLevel =
4695 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4696 else
4697 pSMB->InformationLevel =
4698 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4701 parm_data =
4702 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4703 offset);
4704 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4705 pSMB->DataOffset = cpu_to_le16(offset);
4706 pSMB->SetupCount = 1;
4707 pSMB->Reserved3 = 0;
4708 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4709 byte_count = 3 /* pad */ + params + data_count;
4710 pSMB->DataCount = cpu_to_le16(data_count);
4711 pSMB->TotalDataCount = pSMB->DataCount;
4712 pSMB->ParameterCount = cpu_to_le16(params);
4713 pSMB->TotalParameterCount = pSMB->ParameterCount;
4714 pSMB->Reserved4 = 0;
4715 pSMB->hdr.smb_buf_length += byte_count;
4716 parm_data->FileSize = cpu_to_le64(size);
4717 pSMB->ByteCount = cpu_to_le16(byte_count);
4718 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4719 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4720 if (rc)
4721 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4723 cifs_buf_release(pSMB);
4725 if (rc == -EAGAIN)
4726 goto SetEOFRetry;
4728 return rc;
4732 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4733 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4735 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4736 char *data_offset;
4737 struct file_end_of_file_info *parm_data;
4738 int rc = 0;
4739 __u16 params, param_offset, offset, byte_count, count;
4741 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4742 (long long)size));
4743 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4745 if (rc)
4746 return rc;
4748 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4749 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4751 params = 6;
4752 pSMB->MaxSetupCount = 0;
4753 pSMB->Reserved = 0;
4754 pSMB->Flags = 0;
4755 pSMB->Timeout = 0;
4756 pSMB->Reserved2 = 0;
4757 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4758 offset = param_offset + params;
4760 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4762 count = sizeof(struct file_end_of_file_info);
4763 pSMB->MaxParameterCount = cpu_to_le16(2);
4764 /* BB find exact max SMB PDU from sess structure BB */
4765 pSMB->MaxDataCount = cpu_to_le16(1000);
4766 pSMB->SetupCount = 1;
4767 pSMB->Reserved3 = 0;
4768 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4769 byte_count = 3 /* pad */ + params + count;
4770 pSMB->DataCount = cpu_to_le16(count);
4771 pSMB->ParameterCount = cpu_to_le16(params);
4772 pSMB->TotalDataCount = pSMB->DataCount;
4773 pSMB->TotalParameterCount = pSMB->ParameterCount;
4774 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4775 parm_data =
4776 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4777 + offset);
4778 pSMB->DataOffset = cpu_to_le16(offset);
4779 parm_data->FileSize = cpu_to_le64(size);
4780 pSMB->Fid = fid;
4781 if (SetAllocation) {
4782 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4783 pSMB->InformationLevel =
4784 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4785 else
4786 pSMB->InformationLevel =
4787 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4788 } else /* Set File Size */ {
4789 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4790 pSMB->InformationLevel =
4791 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4792 else
4793 pSMB->InformationLevel =
4794 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4796 pSMB->Reserved4 = 0;
4797 pSMB->hdr.smb_buf_length += byte_count;
4798 pSMB->ByteCount = cpu_to_le16(byte_count);
4799 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4800 if (rc) {
4801 cFYI(1,
4802 ("Send error in SetFileInfo (SetFileSize) = %d",
4803 rc));
4806 /* Note: On -EAGAIN error only caller can retry on handle based calls
4807 since file handle passed in no longer valid */
4809 return rc;
4812 /* Some legacy servers such as NT4 require that the file times be set on
4813 an open handle, rather than by pathname - this is awkward due to
4814 potential access conflicts on the open, but it is unavoidable for these
4815 old servers since the only other choice is to go from 100 nanosecond DCE
4816 time and resort to the original setpathinfo level which takes the ancient
4817 DOS time format with 2 second granularity */
4819 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4820 const FILE_BASIC_INFO *data, __u16 fid)
4822 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4823 char *data_offset;
4824 int rc = 0;
4825 __u16 params, param_offset, offset, byte_count, count;
4827 cFYI(1, ("Set Times (via SetFileInfo)"));
4828 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4830 if (rc)
4831 return rc;
4833 /* At this point there is no need to override the current pid
4834 with the pid of the opener, but that could change if we someday
4835 use an existing handle (rather than opening one on the fly) */
4836 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4837 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4839 params = 6;
4840 pSMB->MaxSetupCount = 0;
4841 pSMB->Reserved = 0;
4842 pSMB->Flags = 0;
4843 pSMB->Timeout = 0;
4844 pSMB->Reserved2 = 0;
4845 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4846 offset = param_offset + params;
4848 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4850 count = sizeof(FILE_BASIC_INFO);
4851 pSMB->MaxParameterCount = cpu_to_le16(2);
4852 /* BB find max SMB PDU from sess */
4853 pSMB->MaxDataCount = cpu_to_le16(1000);
4854 pSMB->SetupCount = 1;
4855 pSMB->Reserved3 = 0;
4856 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4857 byte_count = 3 /* pad */ + params + count;
4858 pSMB->DataCount = cpu_to_le16(count);
4859 pSMB->ParameterCount = cpu_to_le16(params);
4860 pSMB->TotalDataCount = pSMB->DataCount;
4861 pSMB->TotalParameterCount = pSMB->ParameterCount;
4862 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4863 pSMB->DataOffset = cpu_to_le16(offset);
4864 pSMB->Fid = fid;
4865 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4866 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4867 else
4868 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4869 pSMB->Reserved4 = 0;
4870 pSMB->hdr.smb_buf_length += byte_count;
4871 pSMB->ByteCount = cpu_to_le16(byte_count);
4872 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4873 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4874 if (rc)
4875 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4877 /* Note: On -EAGAIN error only caller can retry on handle based calls
4878 since file handle passed in no longer valid */
4880 return rc;
4885 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4886 const FILE_BASIC_INFO *data,
4887 const struct nls_table *nls_codepage, int remap)
4889 TRANSACTION2_SPI_REQ *pSMB = NULL;
4890 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4891 int name_len;
4892 int rc = 0;
4893 int bytes_returned = 0;
4894 char *data_offset;
4895 __u16 params, param_offset, offset, byte_count, count;
4897 cFYI(1, ("In SetTimes"));
4899 SetTimesRetry:
4900 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4901 (void **) &pSMBr);
4902 if (rc)
4903 return rc;
4905 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4906 name_len =
4907 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4908 PATH_MAX, nls_codepage, remap);
4909 name_len++; /* trailing null */
4910 name_len *= 2;
4911 } else { /* BB improve the check for buffer overruns BB */
4912 name_len = strnlen(fileName, PATH_MAX);
4913 name_len++; /* trailing null */
4914 strncpy(pSMB->FileName, fileName, name_len);
4917 params = 6 + name_len;
4918 count = sizeof(FILE_BASIC_INFO);
4919 pSMB->MaxParameterCount = cpu_to_le16(2);
4920 /* BB find max SMB PDU from sess structure BB */
4921 pSMB->MaxDataCount = cpu_to_le16(1000);
4922 pSMB->MaxSetupCount = 0;
4923 pSMB->Reserved = 0;
4924 pSMB->Flags = 0;
4925 pSMB->Timeout = 0;
4926 pSMB->Reserved2 = 0;
4927 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4928 InformationLevel) - 4;
4929 offset = param_offset + params;
4930 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4931 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4932 pSMB->DataOffset = cpu_to_le16(offset);
4933 pSMB->SetupCount = 1;
4934 pSMB->Reserved3 = 0;
4935 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4936 byte_count = 3 /* pad */ + params + count;
4938 pSMB->DataCount = cpu_to_le16(count);
4939 pSMB->ParameterCount = cpu_to_le16(params);
4940 pSMB->TotalDataCount = pSMB->DataCount;
4941 pSMB->TotalParameterCount = pSMB->ParameterCount;
4942 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4943 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4944 else
4945 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4946 pSMB->Reserved4 = 0;
4947 pSMB->hdr.smb_buf_length += byte_count;
4948 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4949 pSMB->ByteCount = cpu_to_le16(byte_count);
4950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4952 if (rc)
4953 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4955 cifs_buf_release(pSMB);
4957 if (rc == -EAGAIN)
4958 goto SetTimesRetry;
4960 return rc;
4963 /* Can not be used to set time stamps yet (due to old DOS time format) */
4964 /* Can be used to set attributes */
4965 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4966 handling it anyway and NT4 was what we thought it would be needed for
4967 Do not delete it until we prove whether needed for Win9x though */
4969 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4970 __u16 dos_attrs, const struct nls_table *nls_codepage)
4972 SETATTR_REQ *pSMB = NULL;
4973 SETATTR_RSP *pSMBr = NULL;
4974 int rc = 0;
4975 int bytes_returned;
4976 int name_len;
4978 cFYI(1, ("In SetAttrLegacy"));
4980 SetAttrLgcyRetry:
4981 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4982 (void **) &pSMBr);
4983 if (rc)
4984 return rc;
4986 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4987 name_len =
4988 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4989 PATH_MAX, nls_codepage);
4990 name_len++; /* trailing null */
4991 name_len *= 2;
4992 } else { /* BB improve the check for buffer overruns BB */
4993 name_len = strnlen(fileName, PATH_MAX);
4994 name_len++; /* trailing null */
4995 strncpy(pSMB->fileName, fileName, name_len);
4997 pSMB->attr = cpu_to_le16(dos_attrs);
4998 pSMB->BufferFormat = 0x04;
4999 pSMB->hdr.smb_buf_length += name_len + 1;
5000 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5001 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5002 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5003 if (rc)
5004 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5006 cifs_buf_release(pSMB);
5008 if (rc == -EAGAIN)
5009 goto SetAttrLgcyRetry;
5011 return rc;
5013 #endif /* temporarily unneeded SetAttr legacy function */
5016 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
5017 char *fileName, __u64 mode, __u64 uid, __u64 gid,
5018 dev_t device, const struct nls_table *nls_codepage,
5019 int remap)
5021 TRANSACTION2_SPI_REQ *pSMB = NULL;
5022 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5023 int name_len;
5024 int rc = 0;
5025 int bytes_returned = 0;
5026 FILE_UNIX_BASIC_INFO *data_offset;
5027 __u16 params, param_offset, offset, count, byte_count;
5029 cFYI(1, ("In SetUID/GID/Mode"));
5030 setPermsRetry:
5031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5032 (void **) &pSMBr);
5033 if (rc)
5034 return rc;
5036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5037 name_len =
5038 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5039 PATH_MAX, nls_codepage, remap);
5040 name_len++; /* trailing null */
5041 name_len *= 2;
5042 } else { /* BB improve the check for buffer overruns BB */
5043 name_len = strnlen(fileName, PATH_MAX);
5044 name_len++; /* trailing null */
5045 strncpy(pSMB->FileName, fileName, name_len);
5048 params = 6 + name_len;
5049 count = sizeof(FILE_UNIX_BASIC_INFO);
5050 pSMB->MaxParameterCount = cpu_to_le16(2);
5051 /* BB find max SMB PDU from sess structure BB */
5052 pSMB->MaxDataCount = cpu_to_le16(1000);
5053 pSMB->MaxSetupCount = 0;
5054 pSMB->Reserved = 0;
5055 pSMB->Flags = 0;
5056 pSMB->Timeout = 0;
5057 pSMB->Reserved2 = 0;
5058 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5059 InformationLevel) - 4;
5060 offset = param_offset + params;
5061 data_offset =
5062 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5063 offset);
5064 memset(data_offset, 0, count);
5065 pSMB->DataOffset = cpu_to_le16(offset);
5066 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5067 pSMB->SetupCount = 1;
5068 pSMB->Reserved3 = 0;
5069 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5070 byte_count = 3 /* pad */ + params + count;
5071 pSMB->ParameterCount = cpu_to_le16(params);
5072 pSMB->DataCount = cpu_to_le16(count);
5073 pSMB->TotalParameterCount = pSMB->ParameterCount;
5074 pSMB->TotalDataCount = pSMB->DataCount;
5075 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5076 pSMB->Reserved4 = 0;
5077 pSMB->hdr.smb_buf_length += byte_count;
5078 /* Samba server ignores set of file size to zero due to bugs in some
5079 older clients, but we should be precise - we use SetFileSize to
5080 set file size and do not want to truncate file size to zero
5081 accidently as happened on one Samba server beta by putting
5082 zero instead of -1 here */
5083 data_offset->EndOfFile = NO_CHANGE_64;
5084 data_offset->NumOfBytes = NO_CHANGE_64;
5085 data_offset->LastStatusChange = NO_CHANGE_64;
5086 data_offset->LastAccessTime = NO_CHANGE_64;
5087 data_offset->LastModificationTime = NO_CHANGE_64;
5088 data_offset->Uid = cpu_to_le64(uid);
5089 data_offset->Gid = cpu_to_le64(gid);
5090 /* better to leave device as zero when it is */
5091 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5092 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5093 data_offset->Permissions = cpu_to_le64(mode);
5095 if (S_ISREG(mode))
5096 data_offset->Type = cpu_to_le32(UNIX_FILE);
5097 else if (S_ISDIR(mode))
5098 data_offset->Type = cpu_to_le32(UNIX_DIR);
5099 else if (S_ISLNK(mode))
5100 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5101 else if (S_ISCHR(mode))
5102 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5103 else if (S_ISBLK(mode))
5104 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5105 else if (S_ISFIFO(mode))
5106 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5107 else if (S_ISSOCK(mode))
5108 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5111 pSMB->ByteCount = cpu_to_le16(byte_count);
5112 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5113 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5114 if (rc)
5115 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5117 cifs_buf_release(pSMB);
5118 if (rc == -EAGAIN)
5119 goto setPermsRetry;
5120 return rc;
5123 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5124 const int notify_subdirs, const __u16 netfid,
5125 __u32 filter, struct file *pfile, int multishot,
5126 const struct nls_table *nls_codepage)
5128 int rc = 0;
5129 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5130 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5131 struct dir_notify_req *dnotify_req;
5132 int bytes_returned;
5134 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5135 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5136 (void **) &pSMBr);
5137 if (rc)
5138 return rc;
5140 pSMB->TotalParameterCount = 0 ;
5141 pSMB->TotalDataCount = 0;
5142 pSMB->MaxParameterCount = cpu_to_le32(2);
5143 /* BB find exact data count max from sess structure BB */
5144 pSMB->MaxDataCount = 0; /* same in little endian or be */
5145 /* BB VERIFY verify which is correct for above BB */
5146 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5147 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5149 pSMB->MaxSetupCount = 4;
5150 pSMB->Reserved = 0;
5151 pSMB->ParameterOffset = 0;
5152 pSMB->DataCount = 0;
5153 pSMB->DataOffset = 0;
5154 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5155 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5156 pSMB->ParameterCount = pSMB->TotalParameterCount;
5157 if (notify_subdirs)
5158 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5159 pSMB->Reserved2 = 0;
5160 pSMB->CompletionFilter = cpu_to_le32(filter);
5161 pSMB->Fid = netfid; /* file handle always le */
5162 pSMB->ByteCount = 0;
5164 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5165 (struct smb_hdr *)pSMBr, &bytes_returned,
5166 CIFS_ASYNC_OP);
5167 if (rc) {
5168 cFYI(1, ("Error in Notify = %d", rc));
5169 } else {
5170 /* Add file to outstanding requests */
5171 /* BB change to kmem cache alloc */
5172 dnotify_req = kmalloc(
5173 sizeof(struct dir_notify_req),
5174 GFP_KERNEL);
5175 if (dnotify_req) {
5176 dnotify_req->Pid = pSMB->hdr.Pid;
5177 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5178 dnotify_req->Mid = pSMB->hdr.Mid;
5179 dnotify_req->Tid = pSMB->hdr.Tid;
5180 dnotify_req->Uid = pSMB->hdr.Uid;
5181 dnotify_req->netfid = netfid;
5182 dnotify_req->pfile = pfile;
5183 dnotify_req->filter = filter;
5184 dnotify_req->multishot = multishot;
5185 spin_lock(&GlobalMid_Lock);
5186 list_add_tail(&dnotify_req->lhead,
5187 &GlobalDnotifyReqList);
5188 spin_unlock(&GlobalMid_Lock);
5189 } else
5190 rc = -ENOMEM;
5192 cifs_buf_release(pSMB);
5193 return rc;
5195 #ifdef CONFIG_CIFS_XATTR
5196 ssize_t
5197 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5198 const unsigned char *searchName,
5199 char *EAData, size_t buf_size,
5200 const struct nls_table *nls_codepage, int remap)
5202 /* BB assumes one setup word */
5203 TRANSACTION2_QPI_REQ *pSMB = NULL;
5204 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5205 int rc = 0;
5206 int bytes_returned;
5207 int name_len;
5208 struct fea *temp_fea;
5209 char *temp_ptr;
5210 __u16 params, byte_count;
5212 cFYI(1, ("In Query All EAs path %s", searchName));
5213 QAllEAsRetry:
5214 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5215 (void **) &pSMBr);
5216 if (rc)
5217 return rc;
5219 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5220 name_len =
5221 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5222 PATH_MAX, nls_codepage, remap);
5223 name_len++; /* trailing null */
5224 name_len *= 2;
5225 } else { /* BB improve the check for buffer overruns BB */
5226 name_len = strnlen(searchName, PATH_MAX);
5227 name_len++; /* trailing null */
5228 strncpy(pSMB->FileName, searchName, name_len);
5231 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5232 pSMB->TotalDataCount = 0;
5233 pSMB->MaxParameterCount = cpu_to_le16(2);
5234 /* BB find exact max SMB PDU from sess structure BB */
5235 pSMB->MaxDataCount = cpu_to_le16(4000);
5236 pSMB->MaxSetupCount = 0;
5237 pSMB->Reserved = 0;
5238 pSMB->Flags = 0;
5239 pSMB->Timeout = 0;
5240 pSMB->Reserved2 = 0;
5241 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5242 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5243 pSMB->DataCount = 0;
5244 pSMB->DataOffset = 0;
5245 pSMB->SetupCount = 1;
5246 pSMB->Reserved3 = 0;
5247 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5248 byte_count = params + 1 /* pad */ ;
5249 pSMB->TotalParameterCount = cpu_to_le16(params);
5250 pSMB->ParameterCount = pSMB->TotalParameterCount;
5251 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5252 pSMB->Reserved4 = 0;
5253 pSMB->hdr.smb_buf_length += byte_count;
5254 pSMB->ByteCount = cpu_to_le16(byte_count);
5256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5258 if (rc) {
5259 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5260 } else { /* decode response */
5261 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5263 /* BB also check enough total bytes returned */
5264 /* BB we need to improve the validity checking
5265 of these trans2 responses */
5266 if (rc || (pSMBr->ByteCount < 4))
5267 rc = -EIO; /* bad smb */
5268 /* else if (pFindData){
5269 memcpy((char *) pFindData,
5270 (char *) &pSMBr->hdr.Protocol +
5271 data_offset, kl);
5272 }*/ else {
5273 /* check that length of list is not more than bcc */
5274 /* check that each entry does not go beyond length
5275 of list */
5276 /* check that each element of each entry does not
5277 go beyond end of list */
5278 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5279 struct fealist *ea_response_data;
5280 rc = 0;
5281 /* validate_trans2_offsets() */
5282 /* BB check if start of smb + data_offset > &bcc+ bcc */
5283 ea_response_data = (struct fealist *)
5284 (((char *) &pSMBr->hdr.Protocol) +
5285 data_offset);
5286 name_len = le32_to_cpu(ea_response_data->list_len);
5287 cFYI(1, ("ea length %d", name_len));
5288 if (name_len <= 8) {
5289 /* returned EA size zeroed at top of function */
5290 cFYI(1, ("empty EA list returned from server"));
5291 } else {
5292 /* account for ea list len */
5293 name_len -= 4;
5294 temp_fea = ea_response_data->list;
5295 temp_ptr = (char *)temp_fea;
5296 while (name_len > 0) {
5297 __u16 value_len;
5298 name_len -= 4;
5299 temp_ptr += 4;
5300 rc += temp_fea->name_len;
5301 /* account for prefix user. and trailing null */
5302 rc = rc + 5 + 1;
5303 if (rc < (int)buf_size) {
5304 memcpy(EAData, "user.", 5);
5305 EAData += 5;
5306 memcpy(EAData, temp_ptr,
5307 temp_fea->name_len);
5308 EAData += temp_fea->name_len;
5309 /* null terminate name */
5310 *EAData = 0;
5311 EAData = EAData + 1;
5312 } else if (buf_size == 0) {
5313 /* skip copy - calc size only */
5314 } else {
5315 /* stop before overrun buffer */
5316 rc = -ERANGE;
5317 break;
5319 name_len -= temp_fea->name_len;
5320 temp_ptr += temp_fea->name_len;
5321 /* account for trailing null */
5322 name_len--;
5323 temp_ptr++;
5324 value_len =
5325 le16_to_cpu(temp_fea->value_len);
5326 name_len -= value_len;
5327 temp_ptr += value_len;
5328 /* BB check that temp_ptr is still
5329 within the SMB BB*/
5331 /* no trailing null to account for
5332 in value len */
5333 /* go on to next EA */
5334 temp_fea = (struct fea *)temp_ptr;
5339 cifs_buf_release(pSMB);
5340 if (rc == -EAGAIN)
5341 goto QAllEAsRetry;
5343 return (ssize_t)rc;
5346 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5347 const unsigned char *searchName, const unsigned char *ea_name,
5348 unsigned char *ea_value, size_t buf_size,
5349 const struct nls_table *nls_codepage, int remap)
5351 TRANSACTION2_QPI_REQ *pSMB = NULL;
5352 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5353 int rc = 0;
5354 int bytes_returned;
5355 int name_len;
5356 struct fea *temp_fea;
5357 char *temp_ptr;
5358 __u16 params, byte_count;
5360 cFYI(1, ("In Query EA path %s", searchName));
5361 QEARetry:
5362 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5363 (void **) &pSMBr);
5364 if (rc)
5365 return rc;
5367 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5368 name_len =
5369 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5370 PATH_MAX, nls_codepage, remap);
5371 name_len++; /* trailing null */
5372 name_len *= 2;
5373 } else { /* BB improve the check for buffer overruns BB */
5374 name_len = strnlen(searchName, PATH_MAX);
5375 name_len++; /* trailing null */
5376 strncpy(pSMB->FileName, searchName, name_len);
5379 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5380 pSMB->TotalDataCount = 0;
5381 pSMB->MaxParameterCount = cpu_to_le16(2);
5382 /* BB find exact max SMB PDU from sess structure BB */
5383 pSMB->MaxDataCount = cpu_to_le16(4000);
5384 pSMB->MaxSetupCount = 0;
5385 pSMB->Reserved = 0;
5386 pSMB->Flags = 0;
5387 pSMB->Timeout = 0;
5388 pSMB->Reserved2 = 0;
5389 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5390 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5391 pSMB->DataCount = 0;
5392 pSMB->DataOffset = 0;
5393 pSMB->SetupCount = 1;
5394 pSMB->Reserved3 = 0;
5395 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5396 byte_count = params + 1 /* pad */ ;
5397 pSMB->TotalParameterCount = cpu_to_le16(params);
5398 pSMB->ParameterCount = pSMB->TotalParameterCount;
5399 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5400 pSMB->Reserved4 = 0;
5401 pSMB->hdr.smb_buf_length += byte_count;
5402 pSMB->ByteCount = cpu_to_le16(byte_count);
5404 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5405 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5406 if (rc) {
5407 cFYI(1, ("Send error in Query EA = %d", rc));
5408 } else { /* decode response */
5409 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5411 /* BB also check enough total bytes returned */
5412 /* BB we need to improve the validity checking
5413 of these trans2 responses */
5414 if (rc || (pSMBr->ByteCount < 4))
5415 rc = -EIO; /* bad smb */
5416 /* else if (pFindData){
5417 memcpy((char *) pFindData,
5418 (char *) &pSMBr->hdr.Protocol +
5419 data_offset, kl);
5420 }*/ else {
5421 /* check that length of list is not more than bcc */
5422 /* check that each entry does not go beyond length
5423 of list */
5424 /* check that each element of each entry does not
5425 go beyond end of list */
5426 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5427 struct fealist *ea_response_data;
5428 rc = -ENODATA;
5429 /* validate_trans2_offsets() */
5430 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5431 ea_response_data = (struct fealist *)
5432 (((char *) &pSMBr->hdr.Protocol) +
5433 data_offset);
5434 name_len = le32_to_cpu(ea_response_data->list_len);
5435 cFYI(1, ("ea length %d", name_len));
5436 if (name_len <= 8) {
5437 /* returned EA size zeroed at top of function */
5438 cFYI(1, ("empty EA list returned from server"));
5439 } else {
5440 /* account for ea list len */
5441 name_len -= 4;
5442 temp_fea = ea_response_data->list;
5443 temp_ptr = (char *)temp_fea;
5444 /* loop through checking if we have a matching
5445 name and then return the associated value */
5446 while (name_len > 0) {
5447 __u16 value_len;
5448 name_len -= 4;
5449 temp_ptr += 4;
5450 value_len =
5451 le16_to_cpu(temp_fea->value_len);
5452 /* BB validate that value_len falls within SMB,
5453 even though maximum for name_len is 255 */
5454 if (memcmp(temp_fea->name, ea_name,
5455 temp_fea->name_len) == 0) {
5456 /* found a match */
5457 rc = value_len;
5458 /* account for prefix user. and trailing null */
5459 if (rc <= (int)buf_size) {
5460 memcpy(ea_value,
5461 temp_fea->name+temp_fea->name_len+1,
5462 rc);
5463 /* ea values, unlike ea
5464 names, are not null
5465 terminated */
5466 } else if (buf_size == 0) {
5467 /* skip copy - calc size only */
5468 } else {
5469 /* stop before overrun buffer */
5470 rc = -ERANGE;
5472 break;
5474 name_len -= temp_fea->name_len;
5475 temp_ptr += temp_fea->name_len;
5476 /* account for trailing null */
5477 name_len--;
5478 temp_ptr++;
5479 name_len -= value_len;
5480 temp_ptr += value_len;
5481 /* No trailing null to account for in
5482 value_len. Go on to next EA */
5483 temp_fea = (struct fea *)temp_ptr;
5488 cifs_buf_release(pSMB);
5489 if (rc == -EAGAIN)
5490 goto QEARetry;
5492 return (ssize_t)rc;
5496 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5497 const char *ea_name, const void *ea_value,
5498 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5499 int remap)
5501 struct smb_com_transaction2_spi_req *pSMB = NULL;
5502 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5503 struct fealist *parm_data;
5504 int name_len;
5505 int rc = 0;
5506 int bytes_returned = 0;
5507 __u16 params, param_offset, byte_count, offset, count;
5509 cFYI(1, ("In SetEA"));
5510 SetEARetry:
5511 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5512 (void **) &pSMBr);
5513 if (rc)
5514 return rc;
5516 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5517 name_len =
5518 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5519 PATH_MAX, nls_codepage, remap);
5520 name_len++; /* trailing null */
5521 name_len *= 2;
5522 } else { /* BB improve the check for buffer overruns BB */
5523 name_len = strnlen(fileName, PATH_MAX);
5524 name_len++; /* trailing null */
5525 strncpy(pSMB->FileName, fileName, name_len);
5528 params = 6 + name_len;
5530 /* done calculating parms using name_len of file name,
5531 now use name_len to calculate length of ea name
5532 we are going to create in the inode xattrs */
5533 if (ea_name == NULL)
5534 name_len = 0;
5535 else
5536 name_len = strnlen(ea_name, 255);
5538 count = sizeof(*parm_data) + ea_value_len + name_len;
5539 pSMB->MaxParameterCount = cpu_to_le16(2);
5540 /* BB find max SMB PDU from sess */
5541 pSMB->MaxDataCount = cpu_to_le16(1000);
5542 pSMB->MaxSetupCount = 0;
5543 pSMB->Reserved = 0;
5544 pSMB->Flags = 0;
5545 pSMB->Timeout = 0;
5546 pSMB->Reserved2 = 0;
5547 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5548 InformationLevel) - 4;
5549 offset = param_offset + params;
5550 pSMB->InformationLevel =
5551 cpu_to_le16(SMB_SET_FILE_EA);
5553 parm_data =
5554 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5555 offset);
5556 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5557 pSMB->DataOffset = cpu_to_le16(offset);
5558 pSMB->SetupCount = 1;
5559 pSMB->Reserved3 = 0;
5560 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5561 byte_count = 3 /* pad */ + params + count;
5562 pSMB->DataCount = cpu_to_le16(count);
5563 parm_data->list_len = cpu_to_le32(count);
5564 parm_data->list[0].EA_flags = 0;
5565 /* we checked above that name len is less than 255 */
5566 parm_data->list[0].name_len = (__u8)name_len;
5567 /* EA names are always ASCII */
5568 if (ea_name)
5569 strncpy(parm_data->list[0].name, ea_name, name_len);
5570 parm_data->list[0].name[name_len] = 0;
5571 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5572 /* caller ensures that ea_value_len is less than 64K but
5573 we need to ensure that it fits within the smb */
5575 /*BB add length check to see if it would fit in
5576 negotiated SMB buffer size BB */
5577 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5578 if (ea_value_len)
5579 memcpy(parm_data->list[0].name+name_len+1,
5580 ea_value, ea_value_len);
5582 pSMB->TotalDataCount = pSMB->DataCount;
5583 pSMB->ParameterCount = cpu_to_le16(params);
5584 pSMB->TotalParameterCount = pSMB->ParameterCount;
5585 pSMB->Reserved4 = 0;
5586 pSMB->hdr.smb_buf_length += byte_count;
5587 pSMB->ByteCount = cpu_to_le16(byte_count);
5588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5590 if (rc)
5591 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5593 cifs_buf_release(pSMB);
5595 if (rc == -EAGAIN)
5596 goto SetEARetry;
5598 return rc;
5601 #endif