Initial commit
[cbs-scheduler.git] / fs / cifs / cifssmb.c
blob552ef88999368faef05a0ac4ce92f087105bc218
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 src_len, dst_len;
96 if (is_unicode) {
97 src_len = UniStrnlen((wchar_t *)src, maxlen);
98 *dst = kmalloc((4 * src_len) + 2, GFP_KERNEL);
99 if (!*dst)
100 goto cifs_strncpy_to_host_ErrExit;
101 dst_len = cifs_strfromUCS_le(*dst, (__le16 *)src, src_len, nls_codepage);
102 (*dst)[dst_len + 1] = 0;
103 } else {
104 src_len = strnlen(src, maxlen);
105 *dst = kmalloc(src_len + 1, GFP_KERNEL);
106 if (!*dst)
107 goto cifs_strncpy_to_host_ErrExit;
108 strlcpy(*dst, src, src_len + 1);
110 return 0;
112 cifs_strncpy_to_host_ErrExit:
113 cERROR(1, ("Failed to allocate buffer for string\n"));
114 return -ENOMEM;
118 /* Mark as invalid, all open files on tree connections since they
119 were closed when session to server was lost */
120 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
122 struct cifsFileInfo *open_file = NULL;
123 struct list_head *tmp;
124 struct list_head *tmp1;
126 /* list all files open on tree connection and mark them invalid */
127 write_lock(&GlobalSMBSeslock);
128 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
129 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
130 open_file->invalidHandle = true;
132 write_unlock(&GlobalSMBSeslock);
133 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
134 to this tcon */
137 /* Allocate and return pointer to an SMB request buffer, and set basic
138 SMB information in the SMB header. If the return code is zero, this
139 function must have filled in request_buf pointer */
140 static int
141 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
142 void **request_buf)
144 int rc = 0;
146 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
147 check for tcp and smb session status done differently
148 for those three - in the calling routine */
149 if (tcon) {
150 if (tcon->tidStatus == CifsExiting) {
151 /* only tree disconnect, open, and write,
152 (and ulogoff which does not have tcon)
153 are allowed as we start force umount */
154 if ((smb_command != SMB_COM_WRITE_ANDX) &&
155 (smb_command != SMB_COM_OPEN_ANDX) &&
156 (smb_command != SMB_COM_TREE_DISCONNECT)) {
157 cFYI(1, ("can not send cmd %d while umounting",
158 smb_command));
159 return -ENODEV;
162 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
163 (tcon->ses->server)) {
164 struct nls_table *nls_codepage;
165 /* Give Demultiplex thread up to 10 seconds to
166 reconnect, should be greater than cifs socket
167 timeout which is 7 seconds */
168 while (tcon->ses->server->tcpStatus ==
169 CifsNeedReconnect) {
170 wait_event_interruptible_timeout(tcon->ses->server->response_q,
171 (tcon->ses->server->tcpStatus ==
172 CifsGood), 10 * HZ);
173 if (tcon->ses->server->tcpStatus ==
174 CifsNeedReconnect) {
175 /* on "soft" mounts we wait once */
176 if (!tcon->retry ||
177 (tcon->ses->status == CifsExiting)) {
178 cFYI(1, ("gave up waiting on "
179 "reconnect in smb_init"));
180 return -EHOSTDOWN;
181 } /* else "hard" mount - keep retrying
182 until process is killed or server
183 comes back on-line */
184 } else /* TCP session is reestablished now */
185 break;
188 nls_codepage = load_nls_default();
189 /* need to prevent multiple threads trying to
190 simultaneously reconnect the same SMB session */
191 down(&tcon->ses->sesSem);
192 if (tcon->ses->need_reconnect)
193 rc = cifs_setup_session(0, tcon->ses,
194 nls_codepage);
195 if (!rc && (tcon->need_reconnect)) {
196 mark_open_files_invalid(tcon);
197 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
198 tcon, nls_codepage);
199 up(&tcon->ses->sesSem);
200 /* BB FIXME add code to check if wsize needs
201 update due to negotiated smb buffer size
202 shrinking */
203 if (rc == 0) {
204 atomic_inc(&tconInfoReconnectCount);
205 /* tell server Unix caps we support */
206 if (tcon->ses->capabilities & CAP_UNIX)
207 reset_cifs_unix_caps(
208 0 /* no xid */,
209 tcon,
210 NULL /* we do not know sb */,
211 NULL /* no vol info */);
214 cFYI(1, ("reconnect tcon rc = %d", rc));
215 /* Removed call to reopen open files here.
216 It is safer (and faster) to reopen files
217 one at a time as needed in read and write */
219 /* Check if handle based operation so we
220 know whether we can continue or not without
221 returning to caller to reset file handle */
222 switch (smb_command) {
223 case SMB_COM_READ_ANDX:
224 case SMB_COM_WRITE_ANDX:
225 case SMB_COM_CLOSE:
226 case SMB_COM_FIND_CLOSE2:
227 case SMB_COM_LOCKING_ANDX: {
228 unload_nls(nls_codepage);
229 return -EAGAIN;
232 } else {
233 up(&tcon->ses->sesSem);
235 unload_nls(nls_codepage);
237 } else {
238 return -EIO;
241 if (rc)
242 return rc;
244 *request_buf = cifs_small_buf_get();
245 if (*request_buf == NULL) {
246 /* BB should we add a retry in here if not a writepage? */
247 return -ENOMEM;
250 header_assemble((struct smb_hdr *) *request_buf, smb_command,
251 tcon, wct);
253 if (tcon != NULL)
254 cifs_stats_inc(&tcon->num_smbs_sent);
256 return rc;
260 small_smb_init_no_tc(const int smb_command, const int wct,
261 struct cifsSesInfo *ses, void **request_buf)
263 int rc;
264 struct smb_hdr *buffer;
266 rc = small_smb_init(smb_command, wct, NULL, request_buf);
267 if (rc)
268 return rc;
270 buffer = (struct smb_hdr *)*request_buf;
271 buffer->Mid = GetNextMid(ses->server);
272 if (ses->capabilities & CAP_UNICODE)
273 buffer->Flags2 |= SMBFLG2_UNICODE;
274 if (ses->capabilities & CAP_STATUS32)
275 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
277 /* uid, tid can stay at zero as set in header assemble */
279 /* BB add support for turning on the signing when
280 this function is used after 1st of session setup requests */
282 return rc;
285 /* If the return code is zero, this function must fill in request_buf pointer */
286 static int
287 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
288 void **request_buf /* returned */ ,
289 void **response_buf /* returned */ )
291 int rc = 0;
293 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
294 check for tcp and smb session status done differently
295 for those three - in the calling routine */
296 if (tcon) {
297 if (tcon->tidStatus == CifsExiting) {
298 /* only tree disconnect, open, and write,
299 (and ulogoff which does not have tcon)
300 are allowed as we start force umount */
301 if ((smb_command != SMB_COM_WRITE_ANDX) &&
302 (smb_command != SMB_COM_OPEN_ANDX) &&
303 (smb_command != SMB_COM_TREE_DISCONNECT)) {
304 cFYI(1, ("can not send cmd %d while umounting",
305 smb_command));
306 return -ENODEV;
310 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
311 (tcon->ses->server)) {
312 struct nls_table *nls_codepage;
313 /* Give Demultiplex thread up to 10 seconds to
314 reconnect, should be greater than cifs socket
315 timeout which is 7 seconds */
316 while (tcon->ses->server->tcpStatus ==
317 CifsNeedReconnect) {
318 wait_event_interruptible_timeout(tcon->ses->server->response_q,
319 (tcon->ses->server->tcpStatus ==
320 CifsGood), 10 * HZ);
321 if (tcon->ses->server->tcpStatus ==
322 CifsNeedReconnect) {
323 /* on "soft" mounts we wait once */
324 if (!tcon->retry ||
325 (tcon->ses->status == CifsExiting)) {
326 cFYI(1, ("gave up waiting on "
327 "reconnect in smb_init"));
328 return -EHOSTDOWN;
329 } /* else "hard" mount - keep retrying
330 until process is killed or server
331 comes on-line */
332 } else /* TCP session is reestablished now */
333 break;
335 nls_codepage = load_nls_default();
336 /* need to prevent multiple threads trying to
337 simultaneously reconnect the same SMB session */
338 down(&tcon->ses->sesSem);
339 if (tcon->ses->need_reconnect)
340 rc = cifs_setup_session(0, tcon->ses,
341 nls_codepage);
342 if (!rc && (tcon->need_reconnect)) {
343 mark_open_files_invalid(tcon);
344 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
345 tcon, nls_codepage);
346 up(&tcon->ses->sesSem);
347 /* BB FIXME add code to check if wsize needs
348 update due to negotiated smb buffer size
349 shrinking */
350 if (rc == 0) {
351 atomic_inc(&tconInfoReconnectCount);
352 /* tell server Unix caps we support */
353 if (tcon->ses->capabilities & CAP_UNIX)
354 reset_cifs_unix_caps(
355 0 /* no xid */,
356 tcon,
357 NULL /* do not know sb */,
358 NULL /* no vol info */);
361 cFYI(1, ("reconnect tcon rc = %d", rc));
362 /* Removed call to reopen open files here.
363 It is safer (and faster) to reopen files
364 one at a time as needed in read and write */
366 /* Check if handle based operation so we
367 know whether we can continue or not without
368 returning to caller to reset file handle */
369 switch (smb_command) {
370 case SMB_COM_READ_ANDX:
371 case SMB_COM_WRITE_ANDX:
372 case SMB_COM_CLOSE:
373 case SMB_COM_FIND_CLOSE2:
374 case SMB_COM_LOCKING_ANDX: {
375 unload_nls(nls_codepage);
376 return -EAGAIN;
379 } else {
380 up(&tcon->ses->sesSem);
382 unload_nls(nls_codepage);
384 } else {
385 return -EIO;
388 if (rc)
389 return rc;
391 *request_buf = cifs_buf_get();
392 if (*request_buf == NULL) {
393 /* BB should we add a retry in here if not a writepage? */
394 return -ENOMEM;
396 /* Although the original thought was we needed the response buf for */
397 /* potential retries of smb operations it turns out we can determine */
398 /* from the mid flags when the request buffer can be resent without */
399 /* having to use a second distinct buffer for the response */
400 if (response_buf)
401 *response_buf = *request_buf;
403 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
404 wct);
406 if (tcon != NULL)
407 cifs_stats_inc(&tcon->num_smbs_sent);
409 return rc;
412 static int validate_t2(struct smb_t2_rsp *pSMB)
414 int rc = -EINVAL;
415 int total_size;
416 char *pBCC;
418 /* check for plausible wct, bcc and t2 data and parm sizes */
419 /* check for parm and data offset going beyond end of smb */
420 if (pSMB->hdr.WordCount >= 10) {
421 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
422 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
423 /* check that bcc is at least as big as parms + data */
424 /* check that bcc is less than negotiated smb buffer */
425 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
426 if (total_size < 512) {
427 total_size +=
428 le16_to_cpu(pSMB->t2_rsp.DataCount);
429 /* BCC le converted in SendReceive */
430 pBCC = (pSMB->hdr.WordCount * 2) +
431 sizeof(struct smb_hdr) +
432 (char *)pSMB;
433 if ((total_size <= (*(u16 *)pBCC)) &&
434 (total_size <
435 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
436 return 0;
441 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
442 sizeof(struct smb_t2_rsp) + 16);
443 return rc;
446 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
448 NEGOTIATE_REQ *pSMB;
449 NEGOTIATE_RSP *pSMBr;
450 int rc = 0;
451 int bytes_returned;
452 int i;
453 struct TCP_Server_Info *server;
454 u16 count;
455 unsigned int secFlags;
456 u16 dialect;
458 if (ses->server)
459 server = ses->server;
460 else {
461 rc = -EIO;
462 return rc;
464 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
465 (void **) &pSMB, (void **) &pSMBr);
466 if (rc)
467 return rc;
469 /* if any of auth flags (ie not sign or seal) are overriden use them */
470 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
471 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
472 else /* if override flags set only sign/seal OR them with global auth */
473 secFlags = extended_security | ses->overrideSecFlg;
475 cFYI(1, ("secFlags 0x%x", secFlags));
477 pSMB->hdr.Mid = GetNextMid(server);
478 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
480 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
481 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
482 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
483 cFYI(1, ("Kerberos only mechanism, enable extended security"));
484 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
487 count = 0;
488 for (i = 0; i < CIFS_NUM_PROT; i++) {
489 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
490 count += strlen(protocols[i].name) + 1;
491 /* null at end of source and target buffers anyway */
493 pSMB->hdr.smb_buf_length += count;
494 pSMB->ByteCount = cpu_to_le16(count);
496 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
497 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
498 if (rc != 0)
499 goto neg_err_exit;
501 dialect = le16_to_cpu(pSMBr->DialectIndex);
502 cFYI(1, ("Dialect: %d", dialect));
503 /* Check wct = 1 error case */
504 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
505 /* core returns wct = 1, but we do not ask for core - otherwise
506 small wct just comes when dialect index is -1 indicating we
507 could not negotiate a common dialect */
508 rc = -EOPNOTSUPP;
509 goto neg_err_exit;
510 #ifdef CONFIG_CIFS_WEAK_PW_HASH
511 } else if ((pSMBr->hdr.WordCount == 13)
512 && ((dialect == LANMAN_PROT)
513 || (dialect == LANMAN2_PROT))) {
514 __s16 tmp;
515 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
517 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
518 (secFlags & CIFSSEC_MAY_PLNTXT))
519 server->secType = LANMAN;
520 else {
521 cERROR(1, ("mount failed weak security disabled"
522 " in /proc/fs/cifs/SecurityFlags"));
523 rc = -EOPNOTSUPP;
524 goto neg_err_exit;
526 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
527 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
528 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
529 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
530 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
531 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
532 /* even though we do not use raw we might as well set this
533 accurately, in case we ever find a need for it */
534 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
535 server->max_rw = 0xFF00;
536 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
537 } else {
538 server->max_rw = 0;/* do not need to use raw anyway */
539 server->capabilities = CAP_MPX_MODE;
541 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
542 if (tmp == -1) {
543 /* OS/2 often does not set timezone therefore
544 * we must use server time to calc time zone.
545 * Could deviate slightly from the right zone.
546 * Smallest defined timezone difference is 15 minutes
547 * (i.e. Nepal). Rounding up/down is done to match
548 * this requirement.
550 int val, seconds, remain, result;
551 struct timespec ts, utc;
552 utc = CURRENT_TIME;
553 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
554 le16_to_cpu(rsp->SrvTime.Time));
555 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
556 (int)ts.tv_sec, (int)utc.tv_sec,
557 (int)(utc.tv_sec - ts.tv_sec)));
558 val = (int)(utc.tv_sec - ts.tv_sec);
559 seconds = abs(val);
560 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
561 remain = seconds % MIN_TZ_ADJ;
562 if (remain >= (MIN_TZ_ADJ / 2))
563 result += MIN_TZ_ADJ;
564 if (val < 0)
565 result = -result;
566 server->timeAdj = result;
567 } else {
568 server->timeAdj = (int)tmp;
569 server->timeAdj *= 60; /* also in seconds */
571 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
574 /* BB get server time for time conversions and add
575 code to use it and timezone since this is not UTC */
577 if (rsp->EncryptionKeyLength ==
578 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
579 memcpy(server->cryptKey, rsp->EncryptionKey,
580 CIFS_CRYPTO_KEY_SIZE);
581 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
582 rc = -EIO; /* need cryptkey unless plain text */
583 goto neg_err_exit;
586 cFYI(1, ("LANMAN negotiated"));
587 /* we will not end up setting signing flags - as no signing
588 was in LANMAN and server did not return the flags on */
589 goto signing_check;
590 #else /* weak security disabled */
591 } else if (pSMBr->hdr.WordCount == 13) {
592 cERROR(1, ("mount failed, cifs module not built "
593 "with CIFS_WEAK_PW_HASH support"));
594 rc = -EOPNOTSUPP;
595 #endif /* WEAK_PW_HASH */
596 goto neg_err_exit;
597 } else if (pSMBr->hdr.WordCount != 17) {
598 /* unknown wct */
599 rc = -EOPNOTSUPP;
600 goto neg_err_exit;
602 /* else wct == 17 NTLM */
603 server->secMode = pSMBr->SecurityMode;
604 if ((server->secMode & SECMODE_USER) == 0)
605 cFYI(1, ("share mode security"));
607 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
608 #ifdef CONFIG_CIFS_WEAK_PW_HASH
609 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
610 #endif /* CIFS_WEAK_PW_HASH */
611 cERROR(1, ("Server requests plain text password"
612 " but client support disabled"));
614 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
615 server->secType = NTLMv2;
616 else if (secFlags & CIFSSEC_MAY_NTLM)
617 server->secType = NTLM;
618 else if (secFlags & CIFSSEC_MAY_NTLMV2)
619 server->secType = NTLMv2;
620 else if (secFlags & CIFSSEC_MAY_KRB5)
621 server->secType = Kerberos;
622 else if (secFlags & CIFSSEC_MAY_LANMAN)
623 server->secType = LANMAN;
624 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
625 else if (secFlags & CIFSSEC_MAY_PLNTXT)
626 server->secType = ??
627 #endif */
628 else {
629 rc = -EOPNOTSUPP;
630 cERROR(1, ("Invalid security type"));
631 goto neg_err_exit;
633 /* else ... any others ...? */
635 /* one byte, so no need to convert this or EncryptionKeyLen from
636 little endian */
637 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
638 /* probably no need to store and check maxvcs */
639 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
640 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
641 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
642 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
643 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
644 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
645 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
646 server->timeAdj *= 60;
647 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
648 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
649 CIFS_CRYPTO_KEY_SIZE);
650 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
651 && (pSMBr->EncryptionKeyLength == 0)) {
652 /* decode security blob */
653 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
654 rc = -EIO; /* no crypt key only if plain text pwd */
655 goto neg_err_exit;
658 /* BB might be helpful to save off the domain of server here */
660 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
661 (server->capabilities & CAP_EXTENDED_SECURITY)) {
662 count = pSMBr->ByteCount;
663 if (count < 16) {
664 rc = -EIO;
665 goto neg_err_exit;
667 read_lock(&cifs_tcp_ses_lock);
668 if (server->srv_count > 1) {
669 read_unlock(&cifs_tcp_ses_lock);
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 read_unlock(&cifs_tcp_ses_lock);
680 memcpy(server->server_GUID,
681 pSMBr->u.extended_response.GUID, 16);
684 if (count == 16) {
685 server->secType = RawNTLMSSP;
686 } else {
687 rc = decode_negTokenInit(pSMBr->u.extended_response.
688 SecurityBlob,
689 count - 16,
690 &server->secType);
691 if (rc == 1)
692 rc = 0;
693 else
694 rc = -EINVAL;
696 } else
697 server->capabilities &= ~CAP_EXTENDED_SECURITY;
699 #ifdef CONFIG_CIFS_WEAK_PW_HASH
700 signing_check:
701 #endif
702 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
703 /* MUST_SIGN already includes the MAY_SIGN FLAG
704 so if this is zero it means that signing is disabled */
705 cFYI(1, ("Signing disabled"));
706 if (server->secMode & SECMODE_SIGN_REQUIRED) {
707 cERROR(1, ("Server requires "
708 "packet signing to be enabled in "
709 "/proc/fs/cifs/SecurityFlags."));
710 rc = -EOPNOTSUPP;
712 server->secMode &=
713 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
714 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
715 /* signing required */
716 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
717 if ((server->secMode &
718 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
719 cERROR(1,
720 ("signing required but server lacks support"));
721 rc = -EOPNOTSUPP;
722 } else
723 server->secMode |= SECMODE_SIGN_REQUIRED;
724 } else {
725 /* signing optional ie CIFSSEC_MAY_SIGN */
726 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
727 server->secMode &=
728 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
731 neg_err_exit:
732 cifs_buf_release(pSMB);
734 cFYI(1, ("negprot rc %d", rc));
735 return rc;
739 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
741 struct smb_hdr *smb_buffer;
742 int rc = 0;
744 cFYI(1, ("In tree disconnect"));
746 /* BB: do we need to check this? These should never be NULL. */
747 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
748 return -EIO;
751 * No need to return error on this operation if tid invalidated and
752 * closed on server already e.g. due to tcp session crashing. Also,
753 * the tcon is no longer on the list, so no need to take lock before
754 * checking this.
756 if (tcon->need_reconnect)
757 return 0;
759 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
760 (void **)&smb_buffer);
761 if (rc)
762 return rc;
764 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
765 if (rc)
766 cFYI(1, ("Tree disconnect failed %d", rc));
768 /* No need to return error on this operation if tid invalidated and
769 closed on server already e.g. due to tcp session crashing */
770 if (rc == -EAGAIN)
771 rc = 0;
773 return rc;
777 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
779 LOGOFF_ANDX_REQ *pSMB;
780 int rc = 0;
782 cFYI(1, ("In SMBLogoff for session disconnect"));
785 * BB: do we need to check validity of ses and server? They should
786 * always be valid since we have an active reference. If not, that
787 * should probably be a BUG()
789 if (!ses || !ses->server)
790 return -EIO;
792 down(&ses->sesSem);
793 if (ses->need_reconnect)
794 goto session_already_dead; /* no need to send SMBlogoff if uid
795 already closed due to reconnect */
796 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
797 if (rc) {
798 up(&ses->sesSem);
799 return rc;
802 pSMB->hdr.Mid = GetNextMid(ses->server);
804 if (ses->server->secMode &
805 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
806 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
808 pSMB->hdr.Uid = ses->Suid;
810 pSMB->AndXCommand = 0xFF;
811 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
812 session_already_dead:
813 up(&ses->sesSem);
815 /* if session dead then we do not need to do ulogoff,
816 since server closed smb session, no sense reporting
817 error */
818 if (rc == -EAGAIN)
819 rc = 0;
820 return rc;
824 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
825 __u16 type, const struct nls_table *nls_codepage, int remap)
827 TRANSACTION2_SPI_REQ *pSMB = NULL;
828 TRANSACTION2_SPI_RSP *pSMBr = NULL;
829 struct unlink_psx_rq *pRqD;
830 int name_len;
831 int rc = 0;
832 int bytes_returned = 0;
833 __u16 params, param_offset, offset, byte_count;
835 cFYI(1, ("In POSIX delete"));
836 PsxDelete:
837 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
838 (void **) &pSMBr);
839 if (rc)
840 return rc;
842 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
843 name_len =
844 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
845 PATH_MAX, nls_codepage, remap);
846 name_len++; /* trailing null */
847 name_len *= 2;
848 } else { /* BB add path length overrun check */
849 name_len = strnlen(fileName, PATH_MAX);
850 name_len++; /* trailing null */
851 strncpy(pSMB->FileName, fileName, name_len);
854 params = 6 + name_len;
855 pSMB->MaxParameterCount = cpu_to_le16(2);
856 pSMB->MaxDataCount = 0; /* BB double check this with jra */
857 pSMB->MaxSetupCount = 0;
858 pSMB->Reserved = 0;
859 pSMB->Flags = 0;
860 pSMB->Timeout = 0;
861 pSMB->Reserved2 = 0;
862 param_offset = offsetof(struct smb_com_transaction2_spi_req,
863 InformationLevel) - 4;
864 offset = param_offset + params;
866 /* Setup pointer to Request Data (inode type) */
867 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
868 pRqD->type = cpu_to_le16(type);
869 pSMB->ParameterOffset = cpu_to_le16(param_offset);
870 pSMB->DataOffset = cpu_to_le16(offset);
871 pSMB->SetupCount = 1;
872 pSMB->Reserved3 = 0;
873 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
874 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
876 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
877 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
878 pSMB->ParameterCount = cpu_to_le16(params);
879 pSMB->TotalParameterCount = pSMB->ParameterCount;
880 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
881 pSMB->Reserved4 = 0;
882 pSMB->hdr.smb_buf_length += byte_count;
883 pSMB->ByteCount = cpu_to_le16(byte_count);
884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
886 if (rc)
887 cFYI(1, ("Posix delete returned %d", rc));
888 cifs_buf_release(pSMB);
890 cifs_stats_inc(&tcon->num_deletes);
892 if (rc == -EAGAIN)
893 goto PsxDelete;
895 return rc;
899 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
900 const struct nls_table *nls_codepage, int remap)
902 DELETE_FILE_REQ *pSMB = NULL;
903 DELETE_FILE_RSP *pSMBr = NULL;
904 int rc = 0;
905 int bytes_returned;
906 int name_len;
908 DelFileRetry:
909 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
910 (void **) &pSMBr);
911 if (rc)
912 return rc;
914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
915 name_len =
916 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
917 PATH_MAX, nls_codepage, remap);
918 name_len++; /* trailing null */
919 name_len *= 2;
920 } else { /* BB improve check for buffer overruns BB */
921 name_len = strnlen(fileName, PATH_MAX);
922 name_len++; /* trailing null */
923 strncpy(pSMB->fileName, fileName, name_len);
925 pSMB->SearchAttributes =
926 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
927 pSMB->BufferFormat = 0x04;
928 pSMB->hdr.smb_buf_length += name_len + 1;
929 pSMB->ByteCount = cpu_to_le16(name_len + 1);
930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
932 cifs_stats_inc(&tcon->num_deletes);
933 if (rc)
934 cFYI(1, ("Error in RMFile = %d", rc));
936 cifs_buf_release(pSMB);
937 if (rc == -EAGAIN)
938 goto DelFileRetry;
940 return rc;
944 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
945 const struct nls_table *nls_codepage, int remap)
947 DELETE_DIRECTORY_REQ *pSMB = NULL;
948 DELETE_DIRECTORY_RSP *pSMBr = NULL;
949 int rc = 0;
950 int bytes_returned;
951 int name_len;
953 cFYI(1, ("In CIFSSMBRmDir"));
954 RmDirRetry:
955 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
956 (void **) &pSMBr);
957 if (rc)
958 return rc;
960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
961 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
962 PATH_MAX, nls_codepage, remap);
963 name_len++; /* trailing null */
964 name_len *= 2;
965 } else { /* BB improve check for buffer overruns BB */
966 name_len = strnlen(dirName, PATH_MAX);
967 name_len++; /* trailing null */
968 strncpy(pSMB->DirName, dirName, name_len);
971 pSMB->BufferFormat = 0x04;
972 pSMB->hdr.smb_buf_length += name_len + 1;
973 pSMB->ByteCount = cpu_to_le16(name_len + 1);
974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
976 cifs_stats_inc(&tcon->num_rmdirs);
977 if (rc)
978 cFYI(1, ("Error in RMDir = %d", rc));
980 cifs_buf_release(pSMB);
981 if (rc == -EAGAIN)
982 goto RmDirRetry;
983 return rc;
987 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
988 const char *name, const struct nls_table *nls_codepage, int remap)
990 int rc = 0;
991 CREATE_DIRECTORY_REQ *pSMB = NULL;
992 CREATE_DIRECTORY_RSP *pSMBr = NULL;
993 int bytes_returned;
994 int name_len;
996 cFYI(1, ("In CIFSSMBMkDir"));
997 MkDirRetry:
998 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
999 (void **) &pSMBr);
1000 if (rc)
1001 return rc;
1003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1004 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
1005 PATH_MAX, nls_codepage, remap);
1006 name_len++; /* trailing null */
1007 name_len *= 2;
1008 } else { /* BB improve check for buffer overruns BB */
1009 name_len = strnlen(name, PATH_MAX);
1010 name_len++; /* trailing null */
1011 strncpy(pSMB->DirName, name, name_len);
1014 pSMB->BufferFormat = 0x04;
1015 pSMB->hdr.smb_buf_length += name_len + 1;
1016 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1017 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1018 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1019 cifs_stats_inc(&tcon->num_mkdirs);
1020 if (rc)
1021 cFYI(1, ("Error in Mkdir = %d", rc));
1023 cifs_buf_release(pSMB);
1024 if (rc == -EAGAIN)
1025 goto MkDirRetry;
1026 return rc;
1030 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1031 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1032 __u32 *pOplock, const char *name,
1033 const struct nls_table *nls_codepage, int remap)
1035 TRANSACTION2_SPI_REQ *pSMB = NULL;
1036 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1037 int name_len;
1038 int rc = 0;
1039 int bytes_returned = 0;
1040 __u16 params, param_offset, offset, byte_count, count;
1041 OPEN_PSX_REQ *pdata;
1042 OPEN_PSX_RSP *psx_rsp;
1044 cFYI(1, ("In POSIX Create"));
1045 PsxCreat:
1046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1047 (void **) &pSMBr);
1048 if (rc)
1049 return rc;
1051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1052 name_len =
1053 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1054 PATH_MAX, nls_codepage, remap);
1055 name_len++; /* trailing null */
1056 name_len *= 2;
1057 } else { /* BB improve the check for buffer overruns BB */
1058 name_len = strnlen(name, PATH_MAX);
1059 name_len++; /* trailing null */
1060 strncpy(pSMB->FileName, name, name_len);
1063 params = 6 + name_len;
1064 count = sizeof(OPEN_PSX_REQ);
1065 pSMB->MaxParameterCount = cpu_to_le16(2);
1066 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1067 pSMB->MaxSetupCount = 0;
1068 pSMB->Reserved = 0;
1069 pSMB->Flags = 0;
1070 pSMB->Timeout = 0;
1071 pSMB->Reserved2 = 0;
1072 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1073 InformationLevel) - 4;
1074 offset = param_offset + params;
1075 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1076 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1077 pdata->Permissions = cpu_to_le64(mode);
1078 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1079 pdata->OpenFlags = cpu_to_le32(*pOplock);
1080 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1081 pSMB->DataOffset = cpu_to_le16(offset);
1082 pSMB->SetupCount = 1;
1083 pSMB->Reserved3 = 0;
1084 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1085 byte_count = 3 /* pad */ + params + count;
1087 pSMB->DataCount = cpu_to_le16(count);
1088 pSMB->ParameterCount = cpu_to_le16(params);
1089 pSMB->TotalDataCount = pSMB->DataCount;
1090 pSMB->TotalParameterCount = pSMB->ParameterCount;
1091 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1092 pSMB->Reserved4 = 0;
1093 pSMB->hdr.smb_buf_length += byte_count;
1094 pSMB->ByteCount = cpu_to_le16(byte_count);
1095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1097 if (rc) {
1098 cFYI(1, ("Posix create returned %d", rc));
1099 goto psx_create_err;
1102 cFYI(1, ("copying inode info"));
1103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1105 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1106 rc = -EIO; /* bad smb */
1107 goto psx_create_err;
1110 /* copy return information to pRetData */
1111 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1112 + le16_to_cpu(pSMBr->t2.DataOffset));
1114 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1115 if (netfid)
1116 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1117 /* Let caller know file was created so we can set the mode. */
1118 /* Do we care about the CreateAction in any other cases? */
1119 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1120 *pOplock |= CIFS_CREATE_ACTION;
1121 /* check to make sure response data is there */
1122 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1123 pRetData->Type = cpu_to_le32(-1); /* unknown */
1124 cFYI(DBG2, ("unknown type"));
1125 } else {
1126 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1127 + sizeof(FILE_UNIX_BASIC_INFO)) {
1128 cERROR(1, ("Open response data too small"));
1129 pRetData->Type = cpu_to_le32(-1);
1130 goto psx_create_err;
1132 memcpy((char *) pRetData,
1133 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1134 sizeof(FILE_UNIX_BASIC_INFO));
1137 psx_create_err:
1138 cifs_buf_release(pSMB);
1140 cifs_stats_inc(&tcon->num_mkdirs);
1142 if (rc == -EAGAIN)
1143 goto PsxCreat;
1145 return rc;
1148 static __u16 convert_disposition(int disposition)
1150 __u16 ofun = 0;
1152 switch (disposition) {
1153 case FILE_SUPERSEDE:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1155 break;
1156 case FILE_OPEN:
1157 ofun = SMBOPEN_OAPPEND;
1158 break;
1159 case FILE_CREATE:
1160 ofun = SMBOPEN_OCREATE;
1161 break;
1162 case FILE_OPEN_IF:
1163 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1164 break;
1165 case FILE_OVERWRITE:
1166 ofun = SMBOPEN_OTRUNC;
1167 break;
1168 case FILE_OVERWRITE_IF:
1169 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1170 break;
1171 default:
1172 cFYI(1, ("unknown disposition %d", disposition));
1173 ofun = SMBOPEN_OAPPEND; /* regular open */
1175 return ofun;
1178 static int
1179 access_flags_to_smbopen_mode(const int access_flags)
1181 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1183 if (masked_flags == GENERIC_READ)
1184 return SMBOPEN_READ;
1185 else if (masked_flags == GENERIC_WRITE)
1186 return SMBOPEN_WRITE;
1188 /* just go for read/write */
1189 return SMBOPEN_READWRITE;
1193 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1194 const char *fileName, const int openDisposition,
1195 const int access_flags, const int create_options, __u16 *netfid,
1196 int *pOplock, FILE_ALL_INFO *pfile_info,
1197 const struct nls_table *nls_codepage, int remap)
1199 int rc = -EACCES;
1200 OPENX_REQ *pSMB = NULL;
1201 OPENX_RSP *pSMBr = NULL;
1202 int bytes_returned;
1203 int name_len;
1204 __u16 count;
1206 OldOpenRetry:
1207 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1208 (void **) &pSMBr);
1209 if (rc)
1210 return rc;
1212 pSMB->AndXCommand = 0xFF; /* none */
1214 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1215 count = 1; /* account for one byte pad to word boundary */
1216 name_len =
1217 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1218 fileName, PATH_MAX, nls_codepage, remap);
1219 name_len++; /* trailing null */
1220 name_len *= 2;
1221 } else { /* BB improve check for buffer overruns BB */
1222 count = 0; /* no pad */
1223 name_len = strnlen(fileName, PATH_MAX);
1224 name_len++; /* trailing null */
1225 strncpy(pSMB->fileName, fileName, name_len);
1227 if (*pOplock & REQ_OPLOCK)
1228 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1229 else if (*pOplock & REQ_BATCHOPLOCK)
1230 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1232 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1233 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1234 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1235 /* set file as system file if special file such
1236 as fifo and server expecting SFU style and
1237 no Unix extensions */
1239 if (create_options & CREATE_OPTION_SPECIAL)
1240 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1241 else /* BB FIXME BB */
1242 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1244 if (create_options & CREATE_OPTION_READONLY)
1245 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1247 /* BB FIXME BB */
1248 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1249 CREATE_OPTIONS_MASK); */
1250 /* BB FIXME END BB */
1252 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1253 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1254 count += name_len;
1255 pSMB->hdr.smb_buf_length += count;
1257 pSMB->ByteCount = cpu_to_le16(count);
1258 /* long_op set to 1 to allow for oplock break timeouts */
1259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1260 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1261 cifs_stats_inc(&tcon->num_opens);
1262 if (rc) {
1263 cFYI(1, ("Error in Open = %d", rc));
1264 } else {
1265 /* BB verify if wct == 15 */
1267 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1269 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1270 /* Let caller know file was created so we can set the mode. */
1271 /* Do we care about the CreateAction in any other cases? */
1272 /* BB FIXME BB */
1273 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1274 *pOplock |= CIFS_CREATE_ACTION; */
1275 /* BB FIXME END */
1277 if (pfile_info) {
1278 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1279 pfile_info->LastAccessTime = 0; /* BB fixme */
1280 pfile_info->LastWriteTime = 0; /* BB fixme */
1281 pfile_info->ChangeTime = 0; /* BB fixme */
1282 pfile_info->Attributes =
1283 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1284 /* the file_info buf is endian converted by caller */
1285 pfile_info->AllocationSize =
1286 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1287 pfile_info->EndOfFile = pfile_info->AllocationSize;
1288 pfile_info->NumberOfLinks = cpu_to_le32(1);
1289 pfile_info->DeletePending = 0;
1293 cifs_buf_release(pSMB);
1294 if (rc == -EAGAIN)
1295 goto OldOpenRetry;
1296 return rc;
1300 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1301 const char *fileName, const int openDisposition,
1302 const int access_flags, const int create_options, __u16 *netfid,
1303 int *pOplock, FILE_ALL_INFO *pfile_info,
1304 const struct nls_table *nls_codepage, int remap)
1306 int rc = -EACCES;
1307 OPEN_REQ *pSMB = NULL;
1308 OPEN_RSP *pSMBr = NULL;
1309 int bytes_returned;
1310 int name_len;
1311 __u16 count;
1313 openRetry:
1314 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1315 (void **) &pSMBr);
1316 if (rc)
1317 return rc;
1319 pSMB->AndXCommand = 0xFF; /* none */
1321 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1322 count = 1; /* account for one byte pad to word boundary */
1323 name_len =
1324 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1325 fileName, PATH_MAX, nls_codepage, remap);
1326 name_len++; /* trailing null */
1327 name_len *= 2;
1328 pSMB->NameLength = cpu_to_le16(name_len);
1329 } else { /* BB improve check for buffer overruns BB */
1330 count = 0; /* no pad */
1331 name_len = strnlen(fileName, PATH_MAX);
1332 name_len++; /* trailing null */
1333 pSMB->NameLength = cpu_to_le16(name_len);
1334 strncpy(pSMB->fileName, fileName, name_len);
1336 if (*pOplock & REQ_OPLOCK)
1337 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1338 else if (*pOplock & REQ_BATCHOPLOCK)
1339 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1340 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1341 pSMB->AllocationSize = 0;
1342 /* set file as system file if special file such
1343 as fifo and server expecting SFU style and
1344 no Unix extensions */
1345 if (create_options & CREATE_OPTION_SPECIAL)
1346 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1347 else
1348 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1350 /* XP does not handle ATTR_POSIX_SEMANTICS */
1351 /* but it helps speed up case sensitive checks for other
1352 servers such as Samba */
1353 if (tcon->ses->capabilities & CAP_UNIX)
1354 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1356 if (create_options & CREATE_OPTION_READONLY)
1357 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1359 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1360 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1361 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1362 /* BB Expirement with various impersonation levels and verify */
1363 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1364 pSMB->SecurityFlags =
1365 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1367 count += name_len;
1368 pSMB->hdr.smb_buf_length += count;
1370 pSMB->ByteCount = cpu_to_le16(count);
1371 /* long_op set to 1 to allow for oplock break timeouts */
1372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1373 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1374 cifs_stats_inc(&tcon->num_opens);
1375 if (rc) {
1376 cFYI(1, ("Error in Open = %d", rc));
1377 } else {
1378 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1379 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1380 /* Let caller know file was created so we can set the mode. */
1381 /* Do we care about the CreateAction in any other cases? */
1382 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1383 *pOplock |= CIFS_CREATE_ACTION;
1384 if (pfile_info) {
1385 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1386 36 /* CreationTime to Attributes */);
1387 /* the file_info buf is endian converted by caller */
1388 pfile_info->AllocationSize = pSMBr->AllocationSize;
1389 pfile_info->EndOfFile = pSMBr->EndOfFile;
1390 pfile_info->NumberOfLinks = cpu_to_le32(1);
1391 pfile_info->DeletePending = 0;
1395 cifs_buf_release(pSMB);
1396 if (rc == -EAGAIN)
1397 goto openRetry;
1398 return rc;
1402 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1403 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1404 char **buf, int *pbuf_type)
1406 int rc = -EACCES;
1407 READ_REQ *pSMB = NULL;
1408 READ_RSP *pSMBr = NULL;
1409 char *pReadData = NULL;
1410 int wct;
1411 int resp_buf_type = 0;
1412 struct kvec iov[1];
1414 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1415 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1416 wct = 12;
1417 else {
1418 wct = 10; /* old style read */
1419 if ((lseek >> 32) > 0) {
1420 /* can not handle this big offset for old */
1421 return -EIO;
1425 *nbytes = 0;
1426 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1427 if (rc)
1428 return rc;
1430 /* tcon and ses pointer are checked in smb_init */
1431 if (tcon->ses->server == NULL)
1432 return -ECONNABORTED;
1434 pSMB->AndXCommand = 0xFF; /* none */
1435 pSMB->Fid = netfid;
1436 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1437 if (wct == 12)
1438 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1440 pSMB->Remaining = 0;
1441 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1442 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1443 if (wct == 12)
1444 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1445 else {
1446 /* old style read */
1447 struct smb_com_readx_req *pSMBW =
1448 (struct smb_com_readx_req *)pSMB;
1449 pSMBW->ByteCount = 0;
1452 iov[0].iov_base = (char *)pSMB;
1453 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1454 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1455 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1456 cifs_stats_inc(&tcon->num_reads);
1457 pSMBr = (READ_RSP *)iov[0].iov_base;
1458 if (rc) {
1459 cERROR(1, ("Send error in read = %d", rc));
1460 } else {
1461 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1462 data_length = data_length << 16;
1463 data_length += le16_to_cpu(pSMBr->DataLength);
1464 *nbytes = data_length;
1466 /*check that DataLength would not go beyond end of SMB */
1467 if ((data_length > CIFSMaxBufSize)
1468 || (data_length > count)) {
1469 cFYI(1, ("bad length %d for count %d",
1470 data_length, count));
1471 rc = -EIO;
1472 *nbytes = 0;
1473 } else {
1474 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1475 le16_to_cpu(pSMBr->DataOffset);
1476 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1477 cERROR(1,("Faulting on read rc = %d",rc));
1478 rc = -EFAULT;
1479 }*/ /* can not use copy_to_user when using page cache*/
1480 if (*buf)
1481 memcpy(*buf, pReadData, data_length);
1485 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1486 if (*buf) {
1487 if (resp_buf_type == CIFS_SMALL_BUFFER)
1488 cifs_small_buf_release(iov[0].iov_base);
1489 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1490 cifs_buf_release(iov[0].iov_base);
1491 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1492 /* return buffer to caller to free */
1493 *buf = iov[0].iov_base;
1494 if (resp_buf_type == CIFS_SMALL_BUFFER)
1495 *pbuf_type = CIFS_SMALL_BUFFER;
1496 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1497 *pbuf_type = CIFS_LARGE_BUFFER;
1498 } /* else no valid buffer on return - leave as null */
1500 /* Note: On -EAGAIN error only caller can retry on handle based calls
1501 since file handle passed in no longer valid */
1502 return rc;
1507 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1508 const int netfid, const unsigned int count,
1509 const __u64 offset, unsigned int *nbytes, const char *buf,
1510 const char __user *ubuf, const int long_op)
1512 int rc = -EACCES;
1513 WRITE_REQ *pSMB = NULL;
1514 WRITE_RSP *pSMBr = NULL;
1515 int bytes_returned, wct;
1516 __u32 bytes_sent;
1517 __u16 byte_count;
1519 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1520 if (tcon->ses == NULL)
1521 return -ECONNABORTED;
1523 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1524 wct = 14;
1525 else {
1526 wct = 12;
1527 if ((offset >> 32) > 0) {
1528 /* can not handle big offset for old srv */
1529 return -EIO;
1533 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1534 (void **) &pSMBr);
1535 if (rc)
1536 return rc;
1537 /* tcon and ses pointer are checked in smb_init */
1538 if (tcon->ses->server == NULL)
1539 return -ECONNABORTED;
1541 pSMB->AndXCommand = 0xFF; /* none */
1542 pSMB->Fid = netfid;
1543 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1544 if (wct == 14)
1545 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1547 pSMB->Reserved = 0xFFFFFFFF;
1548 pSMB->WriteMode = 0;
1549 pSMB->Remaining = 0;
1551 /* Can increase buffer size if buffer is big enough in some cases ie we
1552 can send more if LARGE_WRITE_X capability returned by the server and if
1553 our buffer is big enough or if we convert to iovecs on socket writes
1554 and eliminate the copy to the CIFS buffer */
1555 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1556 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1557 } else {
1558 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1559 & ~0xFF;
1562 if (bytes_sent > count)
1563 bytes_sent = count;
1564 pSMB->DataOffset =
1565 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1566 if (buf)
1567 memcpy(pSMB->Data, buf, bytes_sent);
1568 else if (ubuf) {
1569 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1570 cifs_buf_release(pSMB);
1571 return -EFAULT;
1573 } else if (count != 0) {
1574 /* No buffer */
1575 cifs_buf_release(pSMB);
1576 return -EINVAL;
1577 } /* else setting file size with write of zero bytes */
1578 if (wct == 14)
1579 byte_count = bytes_sent + 1; /* pad */
1580 else /* wct == 12 */
1581 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1583 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1584 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1585 pSMB->hdr.smb_buf_length += byte_count;
1587 if (wct == 14)
1588 pSMB->ByteCount = cpu_to_le16(byte_count);
1589 else { /* old style write has byte count 4 bytes earlier
1590 so 4 bytes pad */
1591 struct smb_com_writex_req *pSMBW =
1592 (struct smb_com_writex_req *)pSMB;
1593 pSMBW->ByteCount = cpu_to_le16(byte_count);
1596 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1597 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1598 cifs_stats_inc(&tcon->num_writes);
1599 if (rc) {
1600 cFYI(1, ("Send error in write = %d", rc));
1601 *nbytes = 0;
1602 } else {
1603 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1604 *nbytes = (*nbytes) << 16;
1605 *nbytes += le16_to_cpu(pSMBr->Count);
1608 cifs_buf_release(pSMB);
1610 /* Note: On -EAGAIN error only caller can retry on handle based calls
1611 since file handle passed in no longer valid */
1613 return rc;
1617 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1618 const int netfid, const unsigned int count,
1619 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1620 int n_vec, const int long_op)
1622 int rc = -EACCES;
1623 WRITE_REQ *pSMB = NULL;
1624 int wct;
1625 int smb_hdr_len;
1626 int resp_buf_type = 0;
1628 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1630 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1631 wct = 14;
1632 } else {
1633 wct = 12;
1634 if ((offset >> 32) > 0) {
1635 /* can not handle big offset for old srv */
1636 return -EIO;
1639 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1640 if (rc)
1641 return rc;
1642 /* tcon and ses pointer are checked in smb_init */
1643 if (tcon->ses->server == NULL)
1644 return -ECONNABORTED;
1646 pSMB->AndXCommand = 0xFF; /* none */
1647 pSMB->Fid = netfid;
1648 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1649 if (wct == 14)
1650 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1651 pSMB->Reserved = 0xFFFFFFFF;
1652 pSMB->WriteMode = 0;
1653 pSMB->Remaining = 0;
1655 pSMB->DataOffset =
1656 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1658 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1659 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1660 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1661 if (wct == 14)
1662 pSMB->hdr.smb_buf_length += count+1;
1663 else /* wct == 12 */
1664 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1665 if (wct == 14)
1666 pSMB->ByteCount = cpu_to_le16(count + 1);
1667 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1668 struct smb_com_writex_req *pSMBW =
1669 (struct smb_com_writex_req *)pSMB;
1670 pSMBW->ByteCount = cpu_to_le16(count + 5);
1672 iov[0].iov_base = pSMB;
1673 if (wct == 14)
1674 iov[0].iov_len = smb_hdr_len + 4;
1675 else /* wct == 12 pad bigger by four bytes */
1676 iov[0].iov_len = smb_hdr_len + 8;
1679 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1680 long_op);
1681 cifs_stats_inc(&tcon->num_writes);
1682 if (rc) {
1683 cFYI(1, ("Send error Write2 = %d", rc));
1684 *nbytes = 0;
1685 } else if (resp_buf_type == 0) {
1686 /* presumably this can not happen, but best to be safe */
1687 rc = -EIO;
1688 *nbytes = 0;
1689 } else {
1690 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1691 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1692 *nbytes = (*nbytes) << 16;
1693 *nbytes += le16_to_cpu(pSMBr->Count);
1696 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1697 if (resp_buf_type == CIFS_SMALL_BUFFER)
1698 cifs_small_buf_release(iov[0].iov_base);
1699 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1700 cifs_buf_release(iov[0].iov_base);
1702 /* Note: On -EAGAIN error only caller can retry on handle based calls
1703 since file handle passed in no longer valid */
1705 return rc;
1710 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1711 const __u16 smb_file_id, const __u64 len,
1712 const __u64 offset, const __u32 numUnlock,
1713 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1715 int rc = 0;
1716 LOCK_REQ *pSMB = NULL;
1717 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1718 int bytes_returned;
1719 int timeout = 0;
1720 __u16 count;
1722 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1723 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1725 if (rc)
1726 return rc;
1728 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1729 timeout = CIFS_ASYNC_OP; /* no response expected */
1730 pSMB->Timeout = 0;
1731 } else if (waitFlag) {
1732 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1733 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1734 } else {
1735 pSMB->Timeout = 0;
1738 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1739 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1740 pSMB->LockType = lockType;
1741 pSMB->AndXCommand = 0xFF; /* none */
1742 pSMB->Fid = smb_file_id; /* netfid stays le */
1744 if ((numLock != 0) || (numUnlock != 0)) {
1745 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1746 /* BB where to store pid high? */
1747 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1748 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1749 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1750 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1751 count = sizeof(LOCKING_ANDX_RANGE);
1752 } else {
1753 /* oplock break */
1754 count = 0;
1756 pSMB->hdr.smb_buf_length += count;
1757 pSMB->ByteCount = cpu_to_le16(count);
1759 if (waitFlag) {
1760 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1761 (struct smb_hdr *) pSMB, &bytes_returned);
1762 cifs_small_buf_release(pSMB);
1763 } else {
1764 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1765 timeout);
1766 /* SMB buffer freed by function above */
1768 cifs_stats_inc(&tcon->num_locks);
1769 if (rc)
1770 cFYI(1, ("Send error in Lock = %d", rc));
1772 /* Note: On -EAGAIN error only caller can retry on handle based calls
1773 since file handle passed in no longer valid */
1774 return rc;
1778 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1779 const __u16 smb_file_id, const int get_flag, const __u64 len,
1780 struct file_lock *pLockData, const __u16 lock_type,
1781 const bool waitFlag)
1783 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1784 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1785 struct cifs_posix_lock *parm_data;
1786 int rc = 0;
1787 int timeout = 0;
1788 int bytes_returned = 0;
1789 int resp_buf_type = 0;
1790 __u16 params, param_offset, offset, byte_count, count;
1791 struct kvec iov[1];
1793 cFYI(1, ("Posix Lock"));
1795 if (pLockData == NULL)
1796 return -EINVAL;
1798 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1800 if (rc)
1801 return rc;
1803 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1805 params = 6;
1806 pSMB->MaxSetupCount = 0;
1807 pSMB->Reserved = 0;
1808 pSMB->Flags = 0;
1809 pSMB->Reserved2 = 0;
1810 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1811 offset = param_offset + params;
1813 count = sizeof(struct cifs_posix_lock);
1814 pSMB->MaxParameterCount = cpu_to_le16(2);
1815 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1816 pSMB->SetupCount = 1;
1817 pSMB->Reserved3 = 0;
1818 if (get_flag)
1819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1820 else
1821 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1822 byte_count = 3 /* pad */ + params + count;
1823 pSMB->DataCount = cpu_to_le16(count);
1824 pSMB->ParameterCount = cpu_to_le16(params);
1825 pSMB->TotalDataCount = pSMB->DataCount;
1826 pSMB->TotalParameterCount = pSMB->ParameterCount;
1827 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1828 parm_data = (struct cifs_posix_lock *)
1829 (((char *) &pSMB->hdr.Protocol) + offset);
1831 parm_data->lock_type = cpu_to_le16(lock_type);
1832 if (waitFlag) {
1833 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1834 parm_data->lock_flags = cpu_to_le16(1);
1835 pSMB->Timeout = cpu_to_le32(-1);
1836 } else
1837 pSMB->Timeout = 0;
1839 parm_data->pid = cpu_to_le32(current->tgid);
1840 parm_data->start = cpu_to_le64(pLockData->fl_start);
1841 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1843 pSMB->DataOffset = cpu_to_le16(offset);
1844 pSMB->Fid = smb_file_id;
1845 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1846 pSMB->Reserved4 = 0;
1847 pSMB->hdr.smb_buf_length += byte_count;
1848 pSMB->ByteCount = cpu_to_le16(byte_count);
1849 if (waitFlag) {
1850 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1851 (struct smb_hdr *) pSMBr, &bytes_returned);
1852 } else {
1853 iov[0].iov_base = (char *)pSMB;
1854 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1855 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1856 &resp_buf_type, timeout);
1857 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1858 not try to free it twice below on exit */
1859 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1862 if (rc) {
1863 cFYI(1, ("Send error in Posix Lock = %d", rc));
1864 } else if (get_flag) {
1865 /* lock structure can be returned on get */
1866 __u16 data_offset;
1867 __u16 data_count;
1868 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1870 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1871 rc = -EIO; /* bad smb */
1872 goto plk_err_exit;
1874 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1875 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1876 if (data_count < sizeof(struct cifs_posix_lock)) {
1877 rc = -EIO;
1878 goto plk_err_exit;
1880 parm_data = (struct cifs_posix_lock *)
1881 ((char *)&pSMBr->hdr.Protocol + data_offset);
1882 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1883 pLockData->fl_type = F_UNLCK;
1886 plk_err_exit:
1887 if (pSMB)
1888 cifs_small_buf_release(pSMB);
1890 if (resp_buf_type == CIFS_SMALL_BUFFER)
1891 cifs_small_buf_release(iov[0].iov_base);
1892 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1893 cifs_buf_release(iov[0].iov_base);
1895 /* Note: On -EAGAIN error only caller can retry on handle based calls
1896 since file handle passed in no longer valid */
1898 return rc;
1903 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1905 int rc = 0;
1906 CLOSE_REQ *pSMB = NULL;
1907 cFYI(1, ("In CIFSSMBClose"));
1909 /* do not retry on dead session on close */
1910 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1911 if (rc == -EAGAIN)
1912 return 0;
1913 if (rc)
1914 return rc;
1916 pSMB->FileID = (__u16) smb_file_id;
1917 pSMB->LastWriteTime = 0xFFFFFFFF;
1918 pSMB->ByteCount = 0;
1919 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1920 cifs_stats_inc(&tcon->num_closes);
1921 if (rc) {
1922 if (rc != -EINTR) {
1923 /* EINTR is expected when user ctl-c to kill app */
1924 cERROR(1, ("Send error in Close = %d", rc));
1928 /* Since session is dead, file will be closed on server already */
1929 if (rc == -EAGAIN)
1930 rc = 0;
1932 return rc;
1936 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1937 const char *fromName, const char *toName,
1938 const struct nls_table *nls_codepage, int remap)
1940 int rc = 0;
1941 RENAME_REQ *pSMB = NULL;
1942 RENAME_RSP *pSMBr = NULL;
1943 int bytes_returned;
1944 int name_len, name_len2;
1945 __u16 count;
1947 cFYI(1, ("In CIFSSMBRename"));
1948 renameRetry:
1949 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1950 (void **) &pSMBr);
1951 if (rc)
1952 return rc;
1954 pSMB->BufferFormat = 0x04;
1955 pSMB->SearchAttributes =
1956 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1957 ATTR_DIRECTORY);
1959 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1960 name_len =
1961 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1962 PATH_MAX, nls_codepage, remap);
1963 name_len++; /* trailing null */
1964 name_len *= 2;
1965 pSMB->OldFileName[name_len] = 0x04; /* pad */
1966 /* protocol requires ASCII signature byte on Unicode string */
1967 pSMB->OldFileName[name_len + 1] = 0x00;
1968 name_len2 =
1969 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1970 toName, PATH_MAX, nls_codepage, remap);
1971 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1972 name_len2 *= 2; /* convert to bytes */
1973 } else { /* BB improve the check for buffer overruns BB */
1974 name_len = strnlen(fromName, PATH_MAX);
1975 name_len++; /* trailing null */
1976 strncpy(pSMB->OldFileName, fromName, name_len);
1977 name_len2 = strnlen(toName, PATH_MAX);
1978 name_len2++; /* trailing null */
1979 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1980 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1981 name_len2++; /* trailing null */
1982 name_len2++; /* signature byte */
1985 count = 1 /* 1st signature byte */ + name_len + name_len2;
1986 pSMB->hdr.smb_buf_length += count;
1987 pSMB->ByteCount = cpu_to_le16(count);
1989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1991 cifs_stats_inc(&tcon->num_renames);
1992 if (rc)
1993 cFYI(1, ("Send error in rename = %d", rc));
1995 cifs_buf_release(pSMB);
1997 if (rc == -EAGAIN)
1998 goto renameRetry;
2000 return rc;
2003 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2004 int netfid, const char *target_name,
2005 const struct nls_table *nls_codepage, int remap)
2007 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2008 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2009 struct set_file_rename *rename_info;
2010 char *data_offset;
2011 char dummy_string[30];
2012 int rc = 0;
2013 int bytes_returned = 0;
2014 int len_of_str;
2015 __u16 params, param_offset, offset, count, byte_count;
2017 cFYI(1, ("Rename to File by handle"));
2018 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2019 (void **) &pSMBr);
2020 if (rc)
2021 return rc;
2023 params = 6;
2024 pSMB->MaxSetupCount = 0;
2025 pSMB->Reserved = 0;
2026 pSMB->Flags = 0;
2027 pSMB->Timeout = 0;
2028 pSMB->Reserved2 = 0;
2029 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2030 offset = param_offset + params;
2032 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2033 rename_info = (struct set_file_rename *) data_offset;
2034 pSMB->MaxParameterCount = cpu_to_le16(2);
2035 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2036 pSMB->SetupCount = 1;
2037 pSMB->Reserved3 = 0;
2038 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2039 byte_count = 3 /* pad */ + params;
2040 pSMB->ParameterCount = cpu_to_le16(params);
2041 pSMB->TotalParameterCount = pSMB->ParameterCount;
2042 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2043 pSMB->DataOffset = cpu_to_le16(offset);
2044 /* construct random name ".cifs_tmp<inodenum><mid>" */
2045 rename_info->overwrite = cpu_to_le32(1);
2046 rename_info->root_fid = 0;
2047 /* unicode only call */
2048 if (target_name == NULL) {
2049 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2050 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2051 dummy_string, 24, nls_codepage, remap);
2052 } else {
2053 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2054 target_name, PATH_MAX, nls_codepage,
2055 remap);
2057 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2058 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2059 byte_count += count;
2060 pSMB->DataCount = cpu_to_le16(count);
2061 pSMB->TotalDataCount = pSMB->DataCount;
2062 pSMB->Fid = netfid;
2063 pSMB->InformationLevel =
2064 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2065 pSMB->Reserved4 = 0;
2066 pSMB->hdr.smb_buf_length += byte_count;
2067 pSMB->ByteCount = cpu_to_le16(byte_count);
2068 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2070 cifs_stats_inc(&pTcon->num_t2renames);
2071 if (rc)
2072 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2074 cifs_buf_release(pSMB);
2076 /* Note: On -EAGAIN error only caller can retry on handle based calls
2077 since file handle passed in no longer valid */
2079 return rc;
2083 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2084 const __u16 target_tid, const char *toName, const int flags,
2085 const struct nls_table *nls_codepage, int remap)
2087 int rc = 0;
2088 COPY_REQ *pSMB = NULL;
2089 COPY_RSP *pSMBr = NULL;
2090 int bytes_returned;
2091 int name_len, name_len2;
2092 __u16 count;
2094 cFYI(1, ("In CIFSSMBCopy"));
2095 copyRetry:
2096 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2097 (void **) &pSMBr);
2098 if (rc)
2099 return rc;
2101 pSMB->BufferFormat = 0x04;
2102 pSMB->Tid2 = target_tid;
2104 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2106 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2107 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2108 fromName, PATH_MAX, nls_codepage,
2109 remap);
2110 name_len++; /* trailing null */
2111 name_len *= 2;
2112 pSMB->OldFileName[name_len] = 0x04; /* pad */
2113 /* protocol requires ASCII signature byte on Unicode string */
2114 pSMB->OldFileName[name_len + 1] = 0x00;
2115 name_len2 =
2116 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2117 toName, PATH_MAX, nls_codepage, remap);
2118 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2119 name_len2 *= 2; /* convert to bytes */
2120 } else { /* BB improve the check for buffer overruns BB */
2121 name_len = strnlen(fromName, PATH_MAX);
2122 name_len++; /* trailing null */
2123 strncpy(pSMB->OldFileName, fromName, name_len);
2124 name_len2 = strnlen(toName, PATH_MAX);
2125 name_len2++; /* trailing null */
2126 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2127 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2128 name_len2++; /* trailing null */
2129 name_len2++; /* signature byte */
2132 count = 1 /* 1st signature byte */ + name_len + name_len2;
2133 pSMB->hdr.smb_buf_length += count;
2134 pSMB->ByteCount = cpu_to_le16(count);
2136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2138 if (rc) {
2139 cFYI(1, ("Send error in copy = %d with %d files copied",
2140 rc, le16_to_cpu(pSMBr->CopyCount)));
2142 cifs_buf_release(pSMB);
2144 if (rc == -EAGAIN)
2145 goto copyRetry;
2147 return rc;
2151 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2152 const char *fromName, const char *toName,
2153 const struct nls_table *nls_codepage)
2155 TRANSACTION2_SPI_REQ *pSMB = NULL;
2156 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2157 char *data_offset;
2158 int name_len;
2159 int name_len_target;
2160 int rc = 0;
2161 int bytes_returned = 0;
2162 __u16 params, param_offset, offset, byte_count;
2164 cFYI(1, ("In Symlink Unix style"));
2165 createSymLinkRetry:
2166 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2167 (void **) &pSMBr);
2168 if (rc)
2169 return rc;
2171 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2172 name_len =
2173 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2174 /* find define for this maxpathcomponent */
2175 , nls_codepage);
2176 name_len++; /* trailing null */
2177 name_len *= 2;
2179 } else { /* BB improve the check for buffer overruns BB */
2180 name_len = strnlen(fromName, PATH_MAX);
2181 name_len++; /* trailing null */
2182 strncpy(pSMB->FileName, fromName, name_len);
2184 params = 6 + name_len;
2185 pSMB->MaxSetupCount = 0;
2186 pSMB->Reserved = 0;
2187 pSMB->Flags = 0;
2188 pSMB->Timeout = 0;
2189 pSMB->Reserved2 = 0;
2190 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2191 InformationLevel) - 4;
2192 offset = param_offset + params;
2194 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2195 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2196 name_len_target =
2197 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2198 /* find define for this maxpathcomponent */
2199 , nls_codepage);
2200 name_len_target++; /* trailing null */
2201 name_len_target *= 2;
2202 } else { /* BB improve the check for buffer overruns BB */
2203 name_len_target = strnlen(toName, PATH_MAX);
2204 name_len_target++; /* trailing null */
2205 strncpy(data_offset, toName, name_len_target);
2208 pSMB->MaxParameterCount = cpu_to_le16(2);
2209 /* BB find exact max on data count below from sess */
2210 pSMB->MaxDataCount = cpu_to_le16(1000);
2211 pSMB->SetupCount = 1;
2212 pSMB->Reserved3 = 0;
2213 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2214 byte_count = 3 /* pad */ + params + name_len_target;
2215 pSMB->DataCount = cpu_to_le16(name_len_target);
2216 pSMB->ParameterCount = cpu_to_le16(params);
2217 pSMB->TotalDataCount = pSMB->DataCount;
2218 pSMB->TotalParameterCount = pSMB->ParameterCount;
2219 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2220 pSMB->DataOffset = cpu_to_le16(offset);
2221 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2222 pSMB->Reserved4 = 0;
2223 pSMB->hdr.smb_buf_length += byte_count;
2224 pSMB->ByteCount = cpu_to_le16(byte_count);
2225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2227 cifs_stats_inc(&tcon->num_symlinks);
2228 if (rc)
2229 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2231 cifs_buf_release(pSMB);
2233 if (rc == -EAGAIN)
2234 goto createSymLinkRetry;
2236 return rc;
2240 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2241 const char *fromName, const char *toName,
2242 const struct nls_table *nls_codepage, int remap)
2244 TRANSACTION2_SPI_REQ *pSMB = NULL;
2245 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2246 char *data_offset;
2247 int name_len;
2248 int name_len_target;
2249 int rc = 0;
2250 int bytes_returned = 0;
2251 __u16 params, param_offset, offset, byte_count;
2253 cFYI(1, ("In Create Hard link Unix style"));
2254 createHardLinkRetry:
2255 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2256 (void **) &pSMBr);
2257 if (rc)
2258 return rc;
2260 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2261 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2262 PATH_MAX, nls_codepage, remap);
2263 name_len++; /* trailing null */
2264 name_len *= 2;
2266 } else { /* BB improve the check for buffer overruns BB */
2267 name_len = strnlen(toName, PATH_MAX);
2268 name_len++; /* trailing null */
2269 strncpy(pSMB->FileName, toName, name_len);
2271 params = 6 + name_len;
2272 pSMB->MaxSetupCount = 0;
2273 pSMB->Reserved = 0;
2274 pSMB->Flags = 0;
2275 pSMB->Timeout = 0;
2276 pSMB->Reserved2 = 0;
2277 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2278 InformationLevel) - 4;
2279 offset = param_offset + params;
2281 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2282 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2283 name_len_target =
2284 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2285 nls_codepage, remap);
2286 name_len_target++; /* trailing null */
2287 name_len_target *= 2;
2288 } else { /* BB improve the check for buffer overruns BB */
2289 name_len_target = strnlen(fromName, PATH_MAX);
2290 name_len_target++; /* trailing null */
2291 strncpy(data_offset, fromName, name_len_target);
2294 pSMB->MaxParameterCount = cpu_to_le16(2);
2295 /* BB find exact max on data count below from sess*/
2296 pSMB->MaxDataCount = cpu_to_le16(1000);
2297 pSMB->SetupCount = 1;
2298 pSMB->Reserved3 = 0;
2299 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2300 byte_count = 3 /* pad */ + params + name_len_target;
2301 pSMB->ParameterCount = cpu_to_le16(params);
2302 pSMB->TotalParameterCount = pSMB->ParameterCount;
2303 pSMB->DataCount = cpu_to_le16(name_len_target);
2304 pSMB->TotalDataCount = pSMB->DataCount;
2305 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2306 pSMB->DataOffset = cpu_to_le16(offset);
2307 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2308 pSMB->Reserved4 = 0;
2309 pSMB->hdr.smb_buf_length += byte_count;
2310 pSMB->ByteCount = cpu_to_le16(byte_count);
2311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2312 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2313 cifs_stats_inc(&tcon->num_hardlinks);
2314 if (rc)
2315 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2317 cifs_buf_release(pSMB);
2318 if (rc == -EAGAIN)
2319 goto createHardLinkRetry;
2321 return rc;
2325 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2326 const char *fromName, const char *toName,
2327 const struct nls_table *nls_codepage, int remap)
2329 int rc = 0;
2330 NT_RENAME_REQ *pSMB = NULL;
2331 RENAME_RSP *pSMBr = NULL;
2332 int bytes_returned;
2333 int name_len, name_len2;
2334 __u16 count;
2336 cFYI(1, ("In CIFSCreateHardLink"));
2337 winCreateHardLinkRetry:
2339 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2340 (void **) &pSMBr);
2341 if (rc)
2342 return rc;
2344 pSMB->SearchAttributes =
2345 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2346 ATTR_DIRECTORY);
2347 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2348 pSMB->ClusterCount = 0;
2350 pSMB->BufferFormat = 0x04;
2352 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2353 name_len =
2354 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2355 PATH_MAX, nls_codepage, remap);
2356 name_len++; /* trailing null */
2357 name_len *= 2;
2359 /* protocol specifies ASCII buffer format (0x04) for unicode */
2360 pSMB->OldFileName[name_len] = 0x04;
2361 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2362 name_len2 =
2363 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2364 toName, PATH_MAX, nls_codepage, remap);
2365 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2366 name_len2 *= 2; /* convert to bytes */
2367 } else { /* BB improve the check for buffer overruns BB */
2368 name_len = strnlen(fromName, PATH_MAX);
2369 name_len++; /* trailing null */
2370 strncpy(pSMB->OldFileName, fromName, name_len);
2371 name_len2 = strnlen(toName, PATH_MAX);
2372 name_len2++; /* trailing null */
2373 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2374 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2375 name_len2++; /* trailing null */
2376 name_len2++; /* signature byte */
2379 count = 1 /* string type byte */ + name_len + name_len2;
2380 pSMB->hdr.smb_buf_length += count;
2381 pSMB->ByteCount = cpu_to_le16(count);
2383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2385 cifs_stats_inc(&tcon->num_hardlinks);
2386 if (rc)
2387 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2389 cifs_buf_release(pSMB);
2390 if (rc == -EAGAIN)
2391 goto winCreateHardLinkRetry;
2393 return rc;
2397 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2398 const unsigned char *searchName,
2399 char *symlinkinfo, const int buflen,
2400 const struct nls_table *nls_codepage)
2402 /* SMB_QUERY_FILE_UNIX_LINK */
2403 TRANSACTION2_QPI_REQ *pSMB = NULL;
2404 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2405 int rc = 0;
2406 int bytes_returned;
2407 int name_len;
2408 __u16 params, byte_count;
2410 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2412 querySymLinkRetry:
2413 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2414 (void **) &pSMBr);
2415 if (rc)
2416 return rc;
2418 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2419 name_len =
2420 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2421 PATH_MAX, nls_codepage);
2422 name_len++; /* trailing null */
2423 name_len *= 2;
2424 } else { /* BB improve the check for buffer overruns BB */
2425 name_len = strnlen(searchName, PATH_MAX);
2426 name_len++; /* trailing null */
2427 strncpy(pSMB->FileName, searchName, name_len);
2430 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2431 pSMB->TotalDataCount = 0;
2432 pSMB->MaxParameterCount = cpu_to_le16(2);
2433 /* BB find exact max data count below from sess structure BB */
2434 pSMB->MaxDataCount = cpu_to_le16(4000);
2435 pSMB->MaxSetupCount = 0;
2436 pSMB->Reserved = 0;
2437 pSMB->Flags = 0;
2438 pSMB->Timeout = 0;
2439 pSMB->Reserved2 = 0;
2440 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2441 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2442 pSMB->DataCount = 0;
2443 pSMB->DataOffset = 0;
2444 pSMB->SetupCount = 1;
2445 pSMB->Reserved3 = 0;
2446 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2447 byte_count = params + 1 /* pad */ ;
2448 pSMB->TotalParameterCount = cpu_to_le16(params);
2449 pSMB->ParameterCount = pSMB->TotalParameterCount;
2450 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2451 pSMB->Reserved4 = 0;
2452 pSMB->hdr.smb_buf_length += byte_count;
2453 pSMB->ByteCount = cpu_to_le16(byte_count);
2455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2456 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2457 if (rc) {
2458 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2459 } else {
2460 /* decode response */
2462 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2463 if (rc || (pSMBr->ByteCount < 2))
2464 /* BB also check enough total bytes returned */
2465 rc = -EIO; /* bad smb */
2466 else {
2467 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2468 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2470 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2471 name_len = UniStrnlen((wchar_t *) ((char *)
2472 &pSMBr->hdr.Protocol + data_offset),
2473 min_t(const int, buflen, count) / 2);
2474 /* BB FIXME investigate remapping reserved chars here */
2475 cifs_strfromUCS_le(symlinkinfo,
2476 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2477 + data_offset),
2478 name_len, nls_codepage);
2479 } else {
2480 strncpy(symlinkinfo,
2481 (char *) &pSMBr->hdr.Protocol +
2482 data_offset,
2483 min_t(const int, buflen, count));
2485 symlinkinfo[buflen] = 0;
2486 /* just in case so calling code does not go off the end of buffer */
2489 cifs_buf_release(pSMB);
2490 if (rc == -EAGAIN)
2491 goto querySymLinkRetry;
2492 return rc;
2495 #ifdef CONFIG_CIFS_EXPERIMENTAL
2496 /* Initialize NT TRANSACT SMB into small smb request buffer.
2497 This assumes that all NT TRANSACTS that we init here have
2498 total parm and data under about 400 bytes (to fit in small cifs
2499 buffer size), which is the case so far, it easily fits. NB:
2500 Setup words themselves and ByteCount
2501 MaxSetupCount (size of returned setup area) and
2502 MaxParameterCount (returned parms size) must be set by caller */
2503 static int
2504 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2505 const int parm_len, struct cifsTconInfo *tcon,
2506 void **ret_buf)
2508 int rc;
2509 __u32 temp_offset;
2510 struct smb_com_ntransact_req *pSMB;
2512 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2513 (void **)&pSMB);
2514 if (rc)
2515 return rc;
2516 *ret_buf = (void *)pSMB;
2517 pSMB->Reserved = 0;
2518 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2519 pSMB->TotalDataCount = 0;
2520 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2521 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2522 pSMB->ParameterCount = pSMB->TotalParameterCount;
2523 pSMB->DataCount = pSMB->TotalDataCount;
2524 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2525 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2526 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2527 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2528 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2529 pSMB->SubCommand = cpu_to_le16(sub_command);
2530 return 0;
2533 static int
2534 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2535 __u32 *pparmlen, __u32 *pdatalen)
2537 char *end_of_smb;
2538 __u32 data_count, data_offset, parm_count, parm_offset;
2539 struct smb_com_ntransact_rsp *pSMBr;
2541 *pdatalen = 0;
2542 *pparmlen = 0;
2544 if (buf == NULL)
2545 return -EINVAL;
2547 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2549 /* ByteCount was converted from little endian in SendReceive */
2550 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2551 (char *)&pSMBr->ByteCount;
2553 data_offset = le32_to_cpu(pSMBr->DataOffset);
2554 data_count = le32_to_cpu(pSMBr->DataCount);
2555 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2556 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2558 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2559 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2561 /* should we also check that parm and data areas do not overlap? */
2562 if (*ppparm > end_of_smb) {
2563 cFYI(1, ("parms start after end of smb"));
2564 return -EINVAL;
2565 } else if (parm_count + *ppparm > end_of_smb) {
2566 cFYI(1, ("parm end after end of smb"));
2567 return -EINVAL;
2568 } else if (*ppdata > end_of_smb) {
2569 cFYI(1, ("data starts after end of smb"));
2570 return -EINVAL;
2571 } else if (data_count + *ppdata > end_of_smb) {
2572 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2573 *ppdata, data_count, (data_count + *ppdata),
2574 end_of_smb, pSMBr));
2575 return -EINVAL;
2576 } else if (parm_count + data_count > pSMBr->ByteCount) {
2577 cFYI(1, ("parm count and data count larger than SMB"));
2578 return -EINVAL;
2580 *pdatalen = data_count;
2581 *pparmlen = parm_count;
2582 return 0;
2584 #endif /* CIFS_EXPERIMENTAL */
2587 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2588 const unsigned char *searchName,
2589 char *symlinkinfo, const int buflen, __u16 fid,
2590 const struct nls_table *nls_codepage)
2592 int rc = 0;
2593 int bytes_returned;
2594 int name_len;
2595 struct smb_com_transaction_ioctl_req *pSMB;
2596 struct smb_com_transaction_ioctl_rsp *pSMBr;
2598 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2599 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2600 (void **) &pSMBr);
2601 if (rc)
2602 return rc;
2604 pSMB->TotalParameterCount = 0 ;
2605 pSMB->TotalDataCount = 0;
2606 pSMB->MaxParameterCount = cpu_to_le32(2);
2607 /* BB find exact data count max from sess structure BB */
2608 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2609 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2610 pSMB->MaxSetupCount = 4;
2611 pSMB->Reserved = 0;
2612 pSMB->ParameterOffset = 0;
2613 pSMB->DataCount = 0;
2614 pSMB->DataOffset = 0;
2615 pSMB->SetupCount = 4;
2616 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2617 pSMB->ParameterCount = pSMB->TotalParameterCount;
2618 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2619 pSMB->IsFsctl = 1; /* FSCTL */
2620 pSMB->IsRootFlag = 0;
2621 pSMB->Fid = fid; /* file handle always le */
2622 pSMB->ByteCount = 0;
2624 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2625 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2626 if (rc) {
2627 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2628 } else { /* decode response */
2629 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2630 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2631 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2632 /* BB also check enough total bytes returned */
2633 rc = -EIO; /* bad smb */
2634 else {
2635 if (data_count && (data_count < 2048)) {
2636 char *end_of_smb = 2 /* sizeof byte count */ +
2637 pSMBr->ByteCount +
2638 (char *)&pSMBr->ByteCount;
2640 struct reparse_data *reparse_buf =
2641 (struct reparse_data *)
2642 ((char *)&pSMBr->hdr.Protocol
2643 + data_offset);
2644 if ((char *)reparse_buf >= end_of_smb) {
2645 rc = -EIO;
2646 goto qreparse_out;
2648 if ((reparse_buf->LinkNamesBuf +
2649 reparse_buf->TargetNameOffset +
2650 reparse_buf->TargetNameLen) >
2651 end_of_smb) {
2652 cFYI(1, ("reparse buf beyond SMB"));
2653 rc = -EIO;
2654 goto qreparse_out;
2657 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2658 name_len = UniStrnlen((wchar_t *)
2659 (reparse_buf->LinkNamesBuf +
2660 reparse_buf->TargetNameOffset),
2661 min(buflen/2,
2662 reparse_buf->TargetNameLen / 2));
2663 cifs_strfromUCS_le(symlinkinfo,
2664 (__le16 *) (reparse_buf->LinkNamesBuf +
2665 reparse_buf->TargetNameOffset),
2666 name_len, nls_codepage);
2667 } else { /* ASCII names */
2668 strncpy(symlinkinfo,
2669 reparse_buf->LinkNamesBuf +
2670 reparse_buf->TargetNameOffset,
2671 min_t(const int, buflen,
2672 reparse_buf->TargetNameLen));
2674 } else {
2675 rc = -EIO;
2676 cFYI(1, ("Invalid return data count on "
2677 "get reparse info ioctl"));
2679 symlinkinfo[buflen] = 0; /* just in case so the caller
2680 does not go off the end of the buffer */
2681 cFYI(1, ("readlink result - %s", symlinkinfo));
2684 qreparse_out:
2685 cifs_buf_release(pSMB);
2687 /* Note: On -EAGAIN error only caller can retry on handle based calls
2688 since file handle passed in no longer valid */
2690 return rc;
2693 #ifdef CONFIG_CIFS_POSIX
2695 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2696 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2697 struct cifs_posix_ace *cifs_ace)
2699 /* u8 cifs fields do not need le conversion */
2700 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2701 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2702 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2703 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2705 return;
2708 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2709 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2710 const int acl_type, const int size_of_data_area)
2712 int size = 0;
2713 int i;
2714 __u16 count;
2715 struct cifs_posix_ace *pACE;
2716 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2717 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2719 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2720 return -EOPNOTSUPP;
2722 if (acl_type & ACL_TYPE_ACCESS) {
2723 count = le16_to_cpu(cifs_acl->access_entry_count);
2724 pACE = &cifs_acl->ace_array[0];
2725 size = sizeof(struct cifs_posix_acl);
2726 size += sizeof(struct cifs_posix_ace) * count;
2727 /* check if we would go beyond end of SMB */
2728 if (size_of_data_area < size) {
2729 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2730 size_of_data_area, size));
2731 return -EINVAL;
2733 } else if (acl_type & ACL_TYPE_DEFAULT) {
2734 count = le16_to_cpu(cifs_acl->access_entry_count);
2735 size = sizeof(struct cifs_posix_acl);
2736 size += sizeof(struct cifs_posix_ace) * count;
2737 /* skip past access ACEs to get to default ACEs */
2738 pACE = &cifs_acl->ace_array[count];
2739 count = le16_to_cpu(cifs_acl->default_entry_count);
2740 size += sizeof(struct cifs_posix_ace) * count;
2741 /* check if we would go beyond end of SMB */
2742 if (size_of_data_area < size)
2743 return -EINVAL;
2744 } else {
2745 /* illegal type */
2746 return -EINVAL;
2749 size = posix_acl_xattr_size(count);
2750 if ((buflen == 0) || (local_acl == NULL)) {
2751 /* used to query ACL EA size */
2752 } else if (size > buflen) {
2753 return -ERANGE;
2754 } else /* buffer big enough */ {
2755 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2756 for (i = 0; i < count ; i++) {
2757 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2758 pACE++;
2761 return size;
2764 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2765 const posix_acl_xattr_entry *local_ace)
2767 __u16 rc = 0; /* 0 = ACL converted ok */
2769 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2770 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2771 /* BB is there a better way to handle the large uid? */
2772 if (local_ace->e_id == cpu_to_le32(-1)) {
2773 /* Probably no need to le convert -1 on any arch but can not hurt */
2774 cifs_ace->cifs_uid = cpu_to_le64(-1);
2775 } else
2776 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2777 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2778 return rc;
2781 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2782 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2783 const int buflen, const int acl_type)
2785 __u16 rc = 0;
2786 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2787 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2788 int count;
2789 int i;
2791 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2792 return 0;
2794 count = posix_acl_xattr_count((size_t)buflen);
2795 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2796 "version of %d",
2797 count, buflen, le32_to_cpu(local_acl->a_version)));
2798 if (le32_to_cpu(local_acl->a_version) != 2) {
2799 cFYI(1, ("unknown POSIX ACL version %d",
2800 le32_to_cpu(local_acl->a_version)));
2801 return 0;
2803 cifs_acl->version = cpu_to_le16(1);
2804 if (acl_type == ACL_TYPE_ACCESS)
2805 cifs_acl->access_entry_count = cpu_to_le16(count);
2806 else if (acl_type == ACL_TYPE_DEFAULT)
2807 cifs_acl->default_entry_count = cpu_to_le16(count);
2808 else {
2809 cFYI(1, ("unknown ACL type %d", acl_type));
2810 return 0;
2812 for (i = 0; i < count; i++) {
2813 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2814 &local_acl->a_entries[i]);
2815 if (rc != 0) {
2816 /* ACE not converted */
2817 break;
2820 if (rc == 0) {
2821 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2822 rc += sizeof(struct cifs_posix_acl);
2823 /* BB add check to make sure ACL does not overflow SMB */
2825 return rc;
2829 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2830 const unsigned char *searchName,
2831 char *acl_inf, const int buflen, const int acl_type,
2832 const struct nls_table *nls_codepage, int remap)
2834 /* SMB_QUERY_POSIX_ACL */
2835 TRANSACTION2_QPI_REQ *pSMB = NULL;
2836 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2837 int rc = 0;
2838 int bytes_returned;
2839 int name_len;
2840 __u16 params, byte_count;
2842 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2844 queryAclRetry:
2845 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2846 (void **) &pSMBr);
2847 if (rc)
2848 return rc;
2850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2851 name_len =
2852 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2853 PATH_MAX, nls_codepage, remap);
2854 name_len++; /* trailing null */
2855 name_len *= 2;
2856 pSMB->FileName[name_len] = 0;
2857 pSMB->FileName[name_len+1] = 0;
2858 } else { /* BB improve the check for buffer overruns BB */
2859 name_len = strnlen(searchName, PATH_MAX);
2860 name_len++; /* trailing null */
2861 strncpy(pSMB->FileName, searchName, name_len);
2864 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2865 pSMB->TotalDataCount = 0;
2866 pSMB->MaxParameterCount = cpu_to_le16(2);
2867 /* BB find exact max data count below from sess structure BB */
2868 pSMB->MaxDataCount = cpu_to_le16(4000);
2869 pSMB->MaxSetupCount = 0;
2870 pSMB->Reserved = 0;
2871 pSMB->Flags = 0;
2872 pSMB->Timeout = 0;
2873 pSMB->Reserved2 = 0;
2874 pSMB->ParameterOffset = cpu_to_le16(
2875 offsetof(struct smb_com_transaction2_qpi_req,
2876 InformationLevel) - 4);
2877 pSMB->DataCount = 0;
2878 pSMB->DataOffset = 0;
2879 pSMB->SetupCount = 1;
2880 pSMB->Reserved3 = 0;
2881 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2882 byte_count = params + 1 /* pad */ ;
2883 pSMB->TotalParameterCount = cpu_to_le16(params);
2884 pSMB->ParameterCount = pSMB->TotalParameterCount;
2885 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2886 pSMB->Reserved4 = 0;
2887 pSMB->hdr.smb_buf_length += byte_count;
2888 pSMB->ByteCount = cpu_to_le16(byte_count);
2890 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2891 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2892 cifs_stats_inc(&tcon->num_acl_get);
2893 if (rc) {
2894 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2895 } else {
2896 /* decode response */
2898 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2899 if (rc || (pSMBr->ByteCount < 2))
2900 /* BB also check enough total bytes returned */
2901 rc = -EIO; /* bad smb */
2902 else {
2903 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2904 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2905 rc = cifs_copy_posix_acl(acl_inf,
2906 (char *)&pSMBr->hdr.Protocol+data_offset,
2907 buflen, acl_type, count);
2910 cifs_buf_release(pSMB);
2911 if (rc == -EAGAIN)
2912 goto queryAclRetry;
2913 return rc;
2917 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2918 const unsigned char *fileName,
2919 const char *local_acl, const int buflen,
2920 const int acl_type,
2921 const struct nls_table *nls_codepage, int remap)
2923 struct smb_com_transaction2_spi_req *pSMB = NULL;
2924 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2925 char *parm_data;
2926 int name_len;
2927 int rc = 0;
2928 int bytes_returned = 0;
2929 __u16 params, byte_count, data_count, param_offset, offset;
2931 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2932 setAclRetry:
2933 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2934 (void **) &pSMBr);
2935 if (rc)
2936 return rc;
2937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2938 name_len =
2939 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2940 PATH_MAX, nls_codepage, remap);
2941 name_len++; /* trailing null */
2942 name_len *= 2;
2943 } else { /* BB improve the check for buffer overruns BB */
2944 name_len = strnlen(fileName, PATH_MAX);
2945 name_len++; /* trailing null */
2946 strncpy(pSMB->FileName, fileName, name_len);
2948 params = 6 + name_len;
2949 pSMB->MaxParameterCount = cpu_to_le16(2);
2950 /* BB find max SMB size from sess */
2951 pSMB->MaxDataCount = cpu_to_le16(1000);
2952 pSMB->MaxSetupCount = 0;
2953 pSMB->Reserved = 0;
2954 pSMB->Flags = 0;
2955 pSMB->Timeout = 0;
2956 pSMB->Reserved2 = 0;
2957 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2958 InformationLevel) - 4;
2959 offset = param_offset + params;
2960 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2961 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2963 /* convert to on the wire format for POSIX ACL */
2964 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2966 if (data_count == 0) {
2967 rc = -EOPNOTSUPP;
2968 goto setACLerrorExit;
2970 pSMB->DataOffset = cpu_to_le16(offset);
2971 pSMB->SetupCount = 1;
2972 pSMB->Reserved3 = 0;
2973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2974 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2975 byte_count = 3 /* pad */ + params + data_count;
2976 pSMB->DataCount = cpu_to_le16(data_count);
2977 pSMB->TotalDataCount = pSMB->DataCount;
2978 pSMB->ParameterCount = cpu_to_le16(params);
2979 pSMB->TotalParameterCount = pSMB->ParameterCount;
2980 pSMB->Reserved4 = 0;
2981 pSMB->hdr.smb_buf_length += byte_count;
2982 pSMB->ByteCount = cpu_to_le16(byte_count);
2983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2985 if (rc)
2986 cFYI(1, ("Set POSIX ACL returned %d", rc));
2988 setACLerrorExit:
2989 cifs_buf_release(pSMB);
2990 if (rc == -EAGAIN)
2991 goto setAclRetry;
2992 return rc;
2995 /* BB fix tabs in this function FIXME BB */
2997 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2998 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3000 int rc = 0;
3001 struct smb_t2_qfi_req *pSMB = NULL;
3002 struct smb_t2_qfi_rsp *pSMBr = NULL;
3003 int bytes_returned;
3004 __u16 params, byte_count;
3006 cFYI(1, ("In GetExtAttr"));
3007 if (tcon == NULL)
3008 return -ENODEV;
3010 GetExtAttrRetry:
3011 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3012 (void **) &pSMBr);
3013 if (rc)
3014 return rc;
3016 params = 2 /* level */ + 2 /* fid */;
3017 pSMB->t2.TotalDataCount = 0;
3018 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3019 /* BB find exact max data count below from sess structure BB */
3020 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3021 pSMB->t2.MaxSetupCount = 0;
3022 pSMB->t2.Reserved = 0;
3023 pSMB->t2.Flags = 0;
3024 pSMB->t2.Timeout = 0;
3025 pSMB->t2.Reserved2 = 0;
3026 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3027 Fid) - 4);
3028 pSMB->t2.DataCount = 0;
3029 pSMB->t2.DataOffset = 0;
3030 pSMB->t2.SetupCount = 1;
3031 pSMB->t2.Reserved3 = 0;
3032 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3033 byte_count = params + 1 /* pad */ ;
3034 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3035 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3036 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3037 pSMB->Pad = 0;
3038 pSMB->Fid = netfid;
3039 pSMB->hdr.smb_buf_length += byte_count;
3040 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3044 if (rc) {
3045 cFYI(1, ("error %d in GetExtAttr", rc));
3046 } else {
3047 /* decode response */
3048 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3049 if (rc || (pSMBr->ByteCount < 2))
3050 /* BB also check enough total bytes returned */
3051 /* If rc should we check for EOPNOSUPP and
3052 disable the srvino flag? or in caller? */
3053 rc = -EIO; /* bad smb */
3054 else {
3055 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3056 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3057 struct file_chattr_info *pfinfo;
3058 /* BB Do we need a cast or hash here ? */
3059 if (count != 16) {
3060 cFYI(1, ("Illegal size ret in GetExtAttr"));
3061 rc = -EIO;
3062 goto GetExtAttrOut;
3064 pfinfo = (struct file_chattr_info *)
3065 (data_offset + (char *) &pSMBr->hdr.Protocol);
3066 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3067 *pMask = le64_to_cpu(pfinfo->mask);
3070 GetExtAttrOut:
3071 cifs_buf_release(pSMB);
3072 if (rc == -EAGAIN)
3073 goto GetExtAttrRetry;
3074 return rc;
3077 #endif /* CONFIG_POSIX */
3079 #ifdef CONFIG_CIFS_EXPERIMENTAL
3080 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3082 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3083 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3085 int rc = 0;
3086 int buf_type = 0;
3087 QUERY_SEC_DESC_REQ *pSMB;
3088 struct kvec iov[1];
3090 cFYI(1, ("GetCifsACL"));
3092 *pbuflen = 0;
3093 *acl_inf = NULL;
3095 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3096 8 /* parm len */, tcon, (void **) &pSMB);
3097 if (rc)
3098 return rc;
3100 pSMB->MaxParameterCount = cpu_to_le32(4);
3101 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3102 pSMB->MaxSetupCount = 0;
3103 pSMB->Fid = fid; /* file handle always le */
3104 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3105 CIFS_ACL_DACL);
3106 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3107 pSMB->hdr.smb_buf_length += 11;
3108 iov[0].iov_base = (char *)pSMB;
3109 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3111 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3112 CIFS_STD_OP);
3113 cifs_stats_inc(&tcon->num_acl_get);
3114 if (rc) {
3115 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3116 } else { /* decode response */
3117 __le32 *parm;
3118 __u32 parm_len;
3119 __u32 acl_len;
3120 struct smb_com_ntransact_rsp *pSMBr;
3121 char *uninitialized_var(pdata);
3123 /* validate_nttransact */
3124 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3125 &pdata, &parm_len, pbuflen);
3126 if (rc)
3127 goto qsec_out;
3128 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3130 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3132 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3133 rc = -EIO; /* bad smb */
3134 *pbuflen = 0;
3135 goto qsec_out;
3138 /* BB check that data area is minimum length and as big as acl_len */
3140 acl_len = le32_to_cpu(*parm);
3141 if (acl_len != *pbuflen) {
3142 cERROR(1, ("acl length %d does not match %d",
3143 acl_len, *pbuflen));
3144 if (*pbuflen > acl_len)
3145 *pbuflen = acl_len;
3148 /* check if buffer is big enough for the acl
3149 header followed by the smallest SID */
3150 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3151 (*pbuflen >= 64 * 1024)) {
3152 cERROR(1, ("bad acl length %d", *pbuflen));
3153 rc = -EINVAL;
3154 *pbuflen = 0;
3155 } else {
3156 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3157 if (*acl_inf == NULL) {
3158 *pbuflen = 0;
3159 rc = -ENOMEM;
3161 memcpy(*acl_inf, pdata, *pbuflen);
3164 qsec_out:
3165 if (buf_type == CIFS_SMALL_BUFFER)
3166 cifs_small_buf_release(iov[0].iov_base);
3167 else if (buf_type == CIFS_LARGE_BUFFER)
3168 cifs_buf_release(iov[0].iov_base);
3169 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3170 return rc;
3174 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3175 struct cifs_ntsd *pntsd, __u32 acllen)
3177 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3178 int rc = 0;
3179 int bytes_returned = 0;
3180 SET_SEC_DESC_REQ *pSMB = NULL;
3181 NTRANSACT_RSP *pSMBr = NULL;
3183 setCifsAclRetry:
3184 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3185 (void **) &pSMBr);
3186 if (rc)
3187 return (rc);
3189 pSMB->MaxSetupCount = 0;
3190 pSMB->Reserved = 0;
3192 param_count = 8;
3193 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3194 data_count = acllen;
3195 data_offset = param_offset + param_count;
3196 byte_count = 3 /* pad */ + param_count;
3198 pSMB->DataCount = cpu_to_le32(data_count);
3199 pSMB->TotalDataCount = pSMB->DataCount;
3200 pSMB->MaxParameterCount = cpu_to_le32(4);
3201 pSMB->MaxDataCount = cpu_to_le32(16384);
3202 pSMB->ParameterCount = cpu_to_le32(param_count);
3203 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3204 pSMB->TotalParameterCount = pSMB->ParameterCount;
3205 pSMB->DataOffset = cpu_to_le32(data_offset);
3206 pSMB->SetupCount = 0;
3207 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3208 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3210 pSMB->Fid = fid; /* file handle always le */
3211 pSMB->Reserved2 = 0;
3212 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3214 if (pntsd && acllen) {
3215 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3216 (char *) pntsd,
3217 acllen);
3218 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3220 } else
3221 pSMB->hdr.smb_buf_length += byte_count;
3223 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3224 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3226 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3227 if (rc)
3228 cFYI(1, ("Set CIFS ACL returned %d", rc));
3229 cifs_buf_release(pSMB);
3231 if (rc == -EAGAIN)
3232 goto setCifsAclRetry;
3234 return (rc);
3237 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3239 /* Legacy Query Path Information call for lookup to old servers such
3240 as Win9x/WinME */
3241 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3242 const unsigned char *searchName,
3243 FILE_ALL_INFO *pFinfo,
3244 const struct nls_table *nls_codepage, int remap)
3246 QUERY_INFORMATION_REQ *pSMB;
3247 QUERY_INFORMATION_RSP *pSMBr;
3248 int rc = 0;
3249 int bytes_returned;
3250 int name_len;
3252 cFYI(1, ("In SMBQPath path %s", searchName));
3253 QInfRetry:
3254 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3255 (void **) &pSMBr);
3256 if (rc)
3257 return rc;
3259 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3260 name_len =
3261 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3262 PATH_MAX, nls_codepage, remap);
3263 name_len++; /* trailing null */
3264 name_len *= 2;
3265 } else {
3266 name_len = strnlen(searchName, PATH_MAX);
3267 name_len++; /* trailing null */
3268 strncpy(pSMB->FileName, searchName, name_len);
3270 pSMB->BufferFormat = 0x04;
3271 name_len++; /* account for buffer type byte */
3272 pSMB->hdr.smb_buf_length += (__u16) name_len;
3273 pSMB->ByteCount = cpu_to_le16(name_len);
3275 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3276 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3277 if (rc) {
3278 cFYI(1, ("Send error in QueryInfo = %d", rc));
3279 } else if (pFinfo) {
3280 struct timespec ts;
3281 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3283 /* decode response */
3284 /* BB FIXME - add time zone adjustment BB */
3285 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3286 ts.tv_nsec = 0;
3287 ts.tv_sec = time;
3288 /* decode time fields */
3289 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3290 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3291 pFinfo->LastAccessTime = 0;
3292 pFinfo->AllocationSize =
3293 cpu_to_le64(le32_to_cpu(pSMBr->size));
3294 pFinfo->EndOfFile = pFinfo->AllocationSize;
3295 pFinfo->Attributes =
3296 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3297 } else
3298 rc = -EIO; /* bad buffer passed in */
3300 cifs_buf_release(pSMB);
3302 if (rc == -EAGAIN)
3303 goto QInfRetry;
3305 return rc;
3312 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3313 const unsigned char *searchName,
3314 FILE_ALL_INFO *pFindData,
3315 int legacy /* old style infolevel */,
3316 const struct nls_table *nls_codepage, int remap)
3318 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3319 TRANSACTION2_QPI_REQ *pSMB = NULL;
3320 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3321 int rc = 0;
3322 int bytes_returned;
3323 int name_len;
3324 __u16 params, byte_count;
3326 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3327 QPathInfoRetry:
3328 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3329 (void **) &pSMBr);
3330 if (rc)
3331 return rc;
3333 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3334 name_len =
3335 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3336 PATH_MAX, nls_codepage, remap);
3337 name_len++; /* trailing null */
3338 name_len *= 2;
3339 } else { /* BB improve the check for buffer overruns BB */
3340 name_len = strnlen(searchName, PATH_MAX);
3341 name_len++; /* trailing null */
3342 strncpy(pSMB->FileName, searchName, name_len);
3345 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3346 pSMB->TotalDataCount = 0;
3347 pSMB->MaxParameterCount = cpu_to_le16(2);
3348 /* BB find exact max SMB PDU from sess structure BB */
3349 pSMB->MaxDataCount = cpu_to_le16(4000);
3350 pSMB->MaxSetupCount = 0;
3351 pSMB->Reserved = 0;
3352 pSMB->Flags = 0;
3353 pSMB->Timeout = 0;
3354 pSMB->Reserved2 = 0;
3355 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3356 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3357 pSMB->DataCount = 0;
3358 pSMB->DataOffset = 0;
3359 pSMB->SetupCount = 1;
3360 pSMB->Reserved3 = 0;
3361 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3362 byte_count = params + 1 /* pad */ ;
3363 pSMB->TotalParameterCount = cpu_to_le16(params);
3364 pSMB->ParameterCount = pSMB->TotalParameterCount;
3365 if (legacy)
3366 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3367 else
3368 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3369 pSMB->Reserved4 = 0;
3370 pSMB->hdr.smb_buf_length += byte_count;
3371 pSMB->ByteCount = cpu_to_le16(byte_count);
3373 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3374 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3375 if (rc) {
3376 cFYI(1, ("Send error in QPathInfo = %d", rc));
3377 } else { /* decode response */
3378 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3380 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3381 rc = -EIO;
3382 else if (!legacy && (pSMBr->ByteCount < 40))
3383 rc = -EIO; /* bad smb */
3384 else if (legacy && (pSMBr->ByteCount < 24))
3385 rc = -EIO; /* 24 or 26 expected but we do not read
3386 last field */
3387 else if (pFindData) {
3388 int size;
3389 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3391 /* On legacy responses we do not read the last field,
3392 EAsize, fortunately since it varies by subdialect and
3393 also note it differs on Set vs. Get, ie two bytes or 4
3394 bytes depending but we don't care here */
3395 if (legacy)
3396 size = sizeof(FILE_INFO_STANDARD);
3397 else
3398 size = sizeof(FILE_ALL_INFO);
3399 memcpy((char *) pFindData,
3400 (char *) &pSMBr->hdr.Protocol +
3401 data_offset, size);
3402 } else
3403 rc = -ENOMEM;
3405 cifs_buf_release(pSMB);
3406 if (rc == -EAGAIN)
3407 goto QPathInfoRetry;
3409 return rc;
3413 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3414 const unsigned char *searchName,
3415 FILE_UNIX_BASIC_INFO *pFindData,
3416 const struct nls_table *nls_codepage, int remap)
3418 /* SMB_QUERY_FILE_UNIX_BASIC */
3419 TRANSACTION2_QPI_REQ *pSMB = NULL;
3420 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3421 int rc = 0;
3422 int bytes_returned = 0;
3423 int name_len;
3424 __u16 params, byte_count;
3426 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3427 UnixQPathInfoRetry:
3428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3429 (void **) &pSMBr);
3430 if (rc)
3431 return rc;
3433 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3434 name_len =
3435 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3436 PATH_MAX, nls_codepage, remap);
3437 name_len++; /* trailing null */
3438 name_len *= 2;
3439 } else { /* BB improve the check for buffer overruns BB */
3440 name_len = strnlen(searchName, PATH_MAX);
3441 name_len++; /* trailing null */
3442 strncpy(pSMB->FileName, searchName, name_len);
3445 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3446 pSMB->TotalDataCount = 0;
3447 pSMB->MaxParameterCount = cpu_to_le16(2);
3448 /* BB find exact max SMB PDU from sess structure BB */
3449 pSMB->MaxDataCount = cpu_to_le16(4000);
3450 pSMB->MaxSetupCount = 0;
3451 pSMB->Reserved = 0;
3452 pSMB->Flags = 0;
3453 pSMB->Timeout = 0;
3454 pSMB->Reserved2 = 0;
3455 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3456 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3457 pSMB->DataCount = 0;
3458 pSMB->DataOffset = 0;
3459 pSMB->SetupCount = 1;
3460 pSMB->Reserved3 = 0;
3461 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3462 byte_count = params + 1 /* pad */ ;
3463 pSMB->TotalParameterCount = cpu_to_le16(params);
3464 pSMB->ParameterCount = pSMB->TotalParameterCount;
3465 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3466 pSMB->Reserved4 = 0;
3467 pSMB->hdr.smb_buf_length += byte_count;
3468 pSMB->ByteCount = cpu_to_le16(byte_count);
3470 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3472 if (rc) {
3473 cFYI(1, ("Send error in QPathInfo = %d", rc));
3474 } else { /* decode response */
3475 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3477 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3478 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3479 "Unix Extensions can be disabled on mount "
3480 "by specifying the nosfu mount option."));
3481 rc = -EIO; /* bad smb */
3482 } else {
3483 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3484 memcpy((char *) pFindData,
3485 (char *) &pSMBr->hdr.Protocol +
3486 data_offset,
3487 sizeof(FILE_UNIX_BASIC_INFO));
3490 cifs_buf_release(pSMB);
3491 if (rc == -EAGAIN)
3492 goto UnixQPathInfoRetry;
3494 return rc;
3497 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3499 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3500 const char *searchName,
3501 const struct nls_table *nls_codepage,
3502 __u16 *pnetfid,
3503 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3505 /* level 257 SMB_ */
3506 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3507 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3508 T2_FFIRST_RSP_PARMS *parms;
3509 int rc = 0;
3510 int bytes_returned = 0;
3511 int name_len;
3512 __u16 params, byte_count;
3514 cFYI(1, ("In FindFirst for %s", searchName));
3516 findFirstRetry:
3517 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3518 (void **) &pSMBr);
3519 if (rc)
3520 return rc;
3522 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3523 name_len =
3524 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3525 PATH_MAX, nls_codepage, remap);
3526 /* We can not add the asterik earlier in case
3527 it got remapped to 0xF03A as if it were part of the
3528 directory name instead of a wildcard */
3529 name_len *= 2;
3530 pSMB->FileName[name_len] = dirsep;
3531 pSMB->FileName[name_len+1] = 0;
3532 pSMB->FileName[name_len+2] = '*';
3533 pSMB->FileName[name_len+3] = 0;
3534 name_len += 4; /* now the trailing null */
3535 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3536 pSMB->FileName[name_len+1] = 0;
3537 name_len += 2;
3538 } else { /* BB add check for overrun of SMB buf BB */
3539 name_len = strnlen(searchName, PATH_MAX);
3540 /* BB fix here and in unicode clause above ie
3541 if (name_len > buffersize-header)
3542 free buffer exit; BB */
3543 strncpy(pSMB->FileName, searchName, name_len);
3544 pSMB->FileName[name_len] = dirsep;
3545 pSMB->FileName[name_len+1] = '*';
3546 pSMB->FileName[name_len+2] = 0;
3547 name_len += 3;
3550 params = 12 + name_len /* includes null */ ;
3551 pSMB->TotalDataCount = 0; /* no EAs */
3552 pSMB->MaxParameterCount = cpu_to_le16(10);
3553 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3554 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3555 pSMB->MaxSetupCount = 0;
3556 pSMB->Reserved = 0;
3557 pSMB->Flags = 0;
3558 pSMB->Timeout = 0;
3559 pSMB->Reserved2 = 0;
3560 byte_count = params + 1 /* pad */ ;
3561 pSMB->TotalParameterCount = cpu_to_le16(params);
3562 pSMB->ParameterCount = pSMB->TotalParameterCount;
3563 pSMB->ParameterOffset = cpu_to_le16(
3564 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3565 - 4);
3566 pSMB->DataCount = 0;
3567 pSMB->DataOffset = 0;
3568 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3569 pSMB->Reserved3 = 0;
3570 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3571 pSMB->SearchAttributes =
3572 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3573 ATTR_DIRECTORY);
3574 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3575 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3576 CIFS_SEARCH_RETURN_RESUME);
3577 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3579 /* BB what should we set StorageType to? Does it matter? BB */
3580 pSMB->SearchStorageType = 0;
3581 pSMB->hdr.smb_buf_length += byte_count;
3582 pSMB->ByteCount = cpu_to_le16(byte_count);
3584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3586 cifs_stats_inc(&tcon->num_ffirst);
3588 if (rc) {/* BB add logic to retry regular search if Unix search
3589 rejected unexpectedly by server */
3590 /* BB Add code to handle unsupported level rc */
3591 cFYI(1, ("Error in FindFirst = %d", rc));
3593 cifs_buf_release(pSMB);
3595 /* BB eventually could optimize out free and realloc of buf */
3596 /* for this case */
3597 if (rc == -EAGAIN)
3598 goto findFirstRetry;
3599 } else { /* decode response */
3600 /* BB remember to free buffer if error BB */
3601 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3602 if (rc == 0) {
3603 unsigned int lnoff;
3605 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3606 psrch_inf->unicode = true;
3607 else
3608 psrch_inf->unicode = false;
3610 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3611 psrch_inf->smallBuf = 0;
3612 psrch_inf->srch_entries_start =
3613 (char *) &pSMBr->hdr.Protocol +
3614 le16_to_cpu(pSMBr->t2.DataOffset);
3615 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3616 le16_to_cpu(pSMBr->t2.ParameterOffset));
3618 if (parms->EndofSearch)
3619 psrch_inf->endOfSearch = true;
3620 else
3621 psrch_inf->endOfSearch = false;
3623 psrch_inf->entries_in_buffer =
3624 le16_to_cpu(parms->SearchCount);
3625 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3626 psrch_inf->entries_in_buffer;
3627 lnoff = le16_to_cpu(parms->LastNameOffset);
3628 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3629 lnoff) {
3630 cERROR(1, ("ignoring corrupt resume name"));
3631 psrch_inf->last_entry = NULL;
3632 return rc;
3635 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3636 lnoff;
3638 *pnetfid = parms->SearchHandle;
3639 } else {
3640 cifs_buf_release(pSMB);
3644 return rc;
3647 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3648 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3650 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3651 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3652 T2_FNEXT_RSP_PARMS *parms;
3653 char *response_data;
3654 int rc = 0;
3655 int bytes_returned, name_len;
3656 __u16 params, byte_count;
3658 cFYI(1, ("In FindNext"));
3660 if (psrch_inf->endOfSearch)
3661 return -ENOENT;
3663 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3664 (void **) &pSMBr);
3665 if (rc)
3666 return rc;
3668 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3669 byte_count = 0;
3670 pSMB->TotalDataCount = 0; /* no EAs */
3671 pSMB->MaxParameterCount = cpu_to_le16(8);
3672 pSMB->MaxDataCount =
3673 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3674 0xFFFFFF00);
3675 pSMB->MaxSetupCount = 0;
3676 pSMB->Reserved = 0;
3677 pSMB->Flags = 0;
3678 pSMB->Timeout = 0;
3679 pSMB->Reserved2 = 0;
3680 pSMB->ParameterOffset = cpu_to_le16(
3681 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3682 pSMB->DataCount = 0;
3683 pSMB->DataOffset = 0;
3684 pSMB->SetupCount = 1;
3685 pSMB->Reserved3 = 0;
3686 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3687 pSMB->SearchHandle = searchHandle; /* always kept as le */
3688 pSMB->SearchCount =
3689 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3690 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3691 pSMB->ResumeKey = psrch_inf->resume_key;
3692 pSMB->SearchFlags =
3693 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3695 name_len = psrch_inf->resume_name_len;
3696 params += name_len;
3697 if (name_len < PATH_MAX) {
3698 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3699 byte_count += name_len;
3700 /* 14 byte parm len above enough for 2 byte null terminator */
3701 pSMB->ResumeFileName[name_len] = 0;
3702 pSMB->ResumeFileName[name_len+1] = 0;
3703 } else {
3704 rc = -EINVAL;
3705 goto FNext2_err_exit;
3707 byte_count = params + 1 /* pad */ ;
3708 pSMB->TotalParameterCount = cpu_to_le16(params);
3709 pSMB->ParameterCount = pSMB->TotalParameterCount;
3710 pSMB->hdr.smb_buf_length += byte_count;
3711 pSMB->ByteCount = cpu_to_le16(byte_count);
3713 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3714 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3715 cifs_stats_inc(&tcon->num_fnext);
3716 if (rc) {
3717 if (rc == -EBADF) {
3718 psrch_inf->endOfSearch = true;
3719 cifs_buf_release(pSMB);
3720 rc = 0; /* search probably was closed at end of search*/
3721 } else
3722 cFYI(1, ("FindNext returned = %d", rc));
3723 } else { /* decode response */
3724 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3726 if (rc == 0) {
3727 unsigned int lnoff;
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 lnoff = le16_to_cpu(parms->LastNameOffset);
3756 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3757 lnoff) {
3758 cERROR(1, ("ignoring corrupt resume name"));
3759 psrch_inf->last_entry = NULL;
3760 return rc;
3761 } else
3762 psrch_inf->last_entry =
3763 psrch_inf->srch_entries_start + lnoff;
3765 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3766 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3768 /* BB fixme add unlock here */
3773 /* BB On error, should we leave previous search buf (and count and
3774 last entry fields) intact or free the previous one? */
3776 /* Note: On -EAGAIN error only caller can retry on handle based calls
3777 since file handle passed in no longer valid */
3778 FNext2_err_exit:
3779 if (rc != 0)
3780 cifs_buf_release(pSMB);
3781 return rc;
3785 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3786 const __u16 searchHandle)
3788 int rc = 0;
3789 FINDCLOSE_REQ *pSMB = NULL;
3791 cFYI(1, ("In CIFSSMBFindClose"));
3792 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3794 /* no sense returning error if session restarted
3795 as file handle has been closed */
3796 if (rc == -EAGAIN)
3797 return 0;
3798 if (rc)
3799 return rc;
3801 pSMB->FileID = searchHandle;
3802 pSMB->ByteCount = 0;
3803 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3804 if (rc)
3805 cERROR(1, ("Send error in FindClose = %d", rc));
3807 cifs_stats_inc(&tcon->num_fclose);
3809 /* Since session is dead, search handle closed on server already */
3810 if (rc == -EAGAIN)
3811 rc = 0;
3813 return rc;
3817 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3818 const unsigned char *searchName,
3819 __u64 *inode_number,
3820 const struct nls_table *nls_codepage, int remap)
3822 int rc = 0;
3823 TRANSACTION2_QPI_REQ *pSMB = NULL;
3824 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3825 int name_len, bytes_returned;
3826 __u16 params, byte_count;
3828 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3829 if (tcon == NULL)
3830 return -ENODEV;
3832 GetInodeNumberRetry:
3833 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3834 (void **) &pSMBr);
3835 if (rc)
3836 return rc;
3838 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3839 name_len =
3840 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3841 PATH_MAX, nls_codepage, remap);
3842 name_len++; /* trailing null */
3843 name_len *= 2;
3844 } else { /* BB improve the check for buffer overruns BB */
3845 name_len = strnlen(searchName, PATH_MAX);
3846 name_len++; /* trailing null */
3847 strncpy(pSMB->FileName, searchName, name_len);
3850 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3851 pSMB->TotalDataCount = 0;
3852 pSMB->MaxParameterCount = cpu_to_le16(2);
3853 /* BB find exact max data count below from sess structure BB */
3854 pSMB->MaxDataCount = cpu_to_le16(4000);
3855 pSMB->MaxSetupCount = 0;
3856 pSMB->Reserved = 0;
3857 pSMB->Flags = 0;
3858 pSMB->Timeout = 0;
3859 pSMB->Reserved2 = 0;
3860 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3861 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3862 pSMB->DataCount = 0;
3863 pSMB->DataOffset = 0;
3864 pSMB->SetupCount = 1;
3865 pSMB->Reserved3 = 0;
3866 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3867 byte_count = params + 1 /* pad */ ;
3868 pSMB->TotalParameterCount = cpu_to_le16(params);
3869 pSMB->ParameterCount = pSMB->TotalParameterCount;
3870 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3871 pSMB->Reserved4 = 0;
3872 pSMB->hdr.smb_buf_length += byte_count;
3873 pSMB->ByteCount = cpu_to_le16(byte_count);
3875 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3876 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3877 if (rc) {
3878 cFYI(1, ("error %d in QueryInternalInfo", rc));
3879 } else {
3880 /* decode response */
3881 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3882 if (rc || (pSMBr->ByteCount < 2))
3883 /* BB also check enough total bytes returned */
3884 /* If rc should we check for EOPNOSUPP and
3885 disable the srvino flag? or in caller? */
3886 rc = -EIO; /* bad smb */
3887 else {
3888 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3889 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3890 struct file_internal_info *pfinfo;
3891 /* BB Do we need a cast or hash here ? */
3892 if (count < 8) {
3893 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3894 rc = -EIO;
3895 goto GetInodeNumOut;
3897 pfinfo = (struct file_internal_info *)
3898 (data_offset + (char *) &pSMBr->hdr.Protocol);
3899 *inode_number = pfinfo->UniqueId;
3902 GetInodeNumOut:
3903 cifs_buf_release(pSMB);
3904 if (rc == -EAGAIN)
3905 goto GetInodeNumberRetry;
3906 return rc;
3909 /* computes length of UCS string converted to host codepage
3910 * @src: UCS string
3911 * @maxlen: length of the input string in UCS characters
3912 * (not in bytes)
3914 * return: size of input string in host codepage
3916 static int hostlen_fromUCS(const __le16 *src, const int maxlen,
3917 const struct nls_table *nls_codepage) {
3918 int i;
3919 int hostlen = 0;
3920 char to[4];
3921 int charlen;
3922 for (i = 0; (i < maxlen) && src[i]; ++i) {
3923 charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
3924 to, NLS_MAX_CHARSET_SIZE);
3925 hostlen += charlen > 0 ? charlen : 1;
3927 return hostlen;
3930 /* parses DFS refferal V3 structure
3931 * caller is responsible for freeing target_nodes
3932 * returns:
3933 * on success - 0
3934 * on failure - errno
3936 static int
3937 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3938 unsigned int *num_of_nodes,
3939 struct dfs_info3_param **target_nodes,
3940 const struct nls_table *nls_codepage, int remap,
3941 const char *searchName)
3943 int i, rc = 0;
3944 char *data_end;
3945 bool is_unicode;
3946 struct dfs_referral_level_3 *ref;
3948 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3949 is_unicode = true;
3950 else
3951 is_unicode = false;
3952 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3954 if (*num_of_nodes < 1) {
3955 cERROR(1, ("num_referrals: must be at least > 0,"
3956 "but we get num_referrals = %d\n", *num_of_nodes));
3957 rc = -EINVAL;
3958 goto parse_DFS_referrals_exit;
3961 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3962 if (ref->VersionNumber != cpu_to_le16(3)) {
3963 cERROR(1, ("Referrals of V%d version are not supported,"
3964 "should be V3", le16_to_cpu(ref->VersionNumber)));
3965 rc = -EINVAL;
3966 goto parse_DFS_referrals_exit;
3969 /* get the upper boundary of the resp buffer */
3970 data_end = (char *)(&(pSMBr->PathConsumed)) +
3971 le16_to_cpu(pSMBr->t2.DataCount);
3973 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3974 *num_of_nodes,
3975 le16_to_cpu(pSMBr->DFSFlags)));
3977 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3978 *num_of_nodes, GFP_KERNEL);
3979 if (*target_nodes == NULL) {
3980 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3981 rc = -ENOMEM;
3982 goto parse_DFS_referrals_exit;
3985 /* collect neccessary data from referrals */
3986 for (i = 0; i < *num_of_nodes; i++) {
3987 char *temp;
3988 int max_len;
3989 struct dfs_info3_param *node = (*target_nodes)+i;
3991 node->flags = le16_to_cpu(pSMBr->DFSFlags);
3992 if (is_unicode) {
3993 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3994 GFP_KERNEL);
3995 cifsConvertToUCS((__le16 *) tmp, searchName,
3996 PATH_MAX, nls_codepage, remap);
3997 node->path_consumed = hostlen_fromUCS(tmp,
3998 le16_to_cpu(pSMBr->PathConsumed)/2,
3999 nls_codepage);
4000 kfree(tmp);
4001 } else
4002 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4004 node->server_type = le16_to_cpu(ref->ServerType);
4005 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4007 /* copy DfsPath */
4008 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4009 max_len = data_end - temp;
4010 rc = cifs_strncpy_to_host(&(node->path_name), temp,
4011 max_len, is_unicode, nls_codepage);
4012 if (rc)
4013 goto parse_DFS_referrals_exit;
4015 /* copy link target UNC */
4016 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4017 max_len = data_end - temp;
4018 rc = cifs_strncpy_to_host(&(node->node_name), temp,
4019 max_len, is_unicode, nls_codepage);
4020 if (rc)
4021 goto parse_DFS_referrals_exit;
4023 ref += le16_to_cpu(ref->Size);
4026 parse_DFS_referrals_exit:
4027 if (rc) {
4028 free_dfs_info_array(*target_nodes, *num_of_nodes);
4029 *target_nodes = NULL;
4030 *num_of_nodes = 0;
4032 return rc;
4036 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4037 const unsigned char *searchName,
4038 struct dfs_info3_param **target_nodes,
4039 unsigned int *num_of_nodes,
4040 const struct nls_table *nls_codepage, int remap)
4042 /* TRANS2_GET_DFS_REFERRAL */
4043 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4044 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4045 int rc = 0;
4046 int bytes_returned;
4047 int name_len;
4048 __u16 params, byte_count;
4049 *num_of_nodes = 0;
4050 *target_nodes = NULL;
4052 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4053 if (ses == NULL)
4054 return -ENODEV;
4055 getDFSRetry:
4056 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4057 (void **) &pSMBr);
4058 if (rc)
4059 return rc;
4061 /* server pointer checked in called function,
4062 but should never be null here anyway */
4063 pSMB->hdr.Mid = GetNextMid(ses->server);
4064 pSMB->hdr.Tid = ses->ipc_tid;
4065 pSMB->hdr.Uid = ses->Suid;
4066 if (ses->capabilities & CAP_STATUS32)
4067 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4068 if (ses->capabilities & CAP_DFS)
4069 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4071 if (ses->capabilities & CAP_UNICODE) {
4072 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4073 name_len =
4074 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4075 searchName, PATH_MAX, nls_codepage, remap);
4076 name_len++; /* trailing null */
4077 name_len *= 2;
4078 } else { /* BB improve the check for buffer overruns BB */
4079 name_len = strnlen(searchName, PATH_MAX);
4080 name_len++; /* trailing null */
4081 strncpy(pSMB->RequestFileName, searchName, name_len);
4084 if (ses->server) {
4085 if (ses->server->secMode &
4086 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4087 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4090 pSMB->hdr.Uid = ses->Suid;
4092 params = 2 /* level */ + name_len /*includes null */ ;
4093 pSMB->TotalDataCount = 0;
4094 pSMB->DataCount = 0;
4095 pSMB->DataOffset = 0;
4096 pSMB->MaxParameterCount = 0;
4097 /* BB find exact max SMB PDU from sess structure BB */
4098 pSMB->MaxDataCount = cpu_to_le16(4000);
4099 pSMB->MaxSetupCount = 0;
4100 pSMB->Reserved = 0;
4101 pSMB->Flags = 0;
4102 pSMB->Timeout = 0;
4103 pSMB->Reserved2 = 0;
4104 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4105 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4106 pSMB->SetupCount = 1;
4107 pSMB->Reserved3 = 0;
4108 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4109 byte_count = params + 3 /* pad */ ;
4110 pSMB->ParameterCount = cpu_to_le16(params);
4111 pSMB->TotalParameterCount = pSMB->ParameterCount;
4112 pSMB->MaxReferralLevel = cpu_to_le16(3);
4113 pSMB->hdr.smb_buf_length += byte_count;
4114 pSMB->ByteCount = cpu_to_le16(byte_count);
4116 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4117 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4118 if (rc) {
4119 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4120 goto GetDFSRefExit;
4122 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4124 /* BB Also check if enough total bytes returned? */
4125 if (rc || (pSMBr->ByteCount < 17)) {
4126 rc = -EIO; /* bad smb */
4127 goto GetDFSRefExit;
4130 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4131 pSMBr->ByteCount,
4132 le16_to_cpu(pSMBr->t2.DataOffset)));
4134 /* parse returned result into more usable form */
4135 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4136 target_nodes, nls_codepage, remap,
4137 searchName);
4139 GetDFSRefExit:
4140 cifs_buf_release(pSMB);
4142 if (rc == -EAGAIN)
4143 goto getDFSRetry;
4145 return rc;
4148 /* Query File System Info such as free space to old servers such as Win 9x */
4150 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4152 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4153 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4154 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4155 FILE_SYSTEM_ALLOC_INFO *response_data;
4156 int rc = 0;
4157 int bytes_returned = 0;
4158 __u16 params, byte_count;
4160 cFYI(1, ("OldQFSInfo"));
4161 oldQFSInfoRetry:
4162 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4163 (void **) &pSMBr);
4164 if (rc)
4165 return rc;
4167 params = 2; /* level */
4168 pSMB->TotalDataCount = 0;
4169 pSMB->MaxParameterCount = cpu_to_le16(2);
4170 pSMB->MaxDataCount = cpu_to_le16(1000);
4171 pSMB->MaxSetupCount = 0;
4172 pSMB->Reserved = 0;
4173 pSMB->Flags = 0;
4174 pSMB->Timeout = 0;
4175 pSMB->Reserved2 = 0;
4176 byte_count = params + 1 /* pad */ ;
4177 pSMB->TotalParameterCount = cpu_to_le16(params);
4178 pSMB->ParameterCount = pSMB->TotalParameterCount;
4179 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4180 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4181 pSMB->DataCount = 0;
4182 pSMB->DataOffset = 0;
4183 pSMB->SetupCount = 1;
4184 pSMB->Reserved3 = 0;
4185 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4186 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4187 pSMB->hdr.smb_buf_length += byte_count;
4188 pSMB->ByteCount = cpu_to_le16(byte_count);
4190 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4191 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4192 if (rc) {
4193 cFYI(1, ("Send error in QFSInfo = %d", rc));
4194 } else { /* decode response */
4195 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4197 if (rc || (pSMBr->ByteCount < 18))
4198 rc = -EIO; /* bad smb */
4199 else {
4200 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4201 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4202 pSMBr->ByteCount, data_offset));
4204 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4205 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4206 FSData->f_bsize =
4207 le16_to_cpu(response_data->BytesPerSector) *
4208 le32_to_cpu(response_data->
4209 SectorsPerAllocationUnit);
4210 FSData->f_blocks =
4211 le32_to_cpu(response_data->TotalAllocationUnits);
4212 FSData->f_bfree = FSData->f_bavail =
4213 le32_to_cpu(response_data->FreeAllocationUnits);
4214 cFYI(1,
4215 ("Blocks: %lld Free: %lld Block size %ld",
4216 (unsigned long long)FSData->f_blocks,
4217 (unsigned long long)FSData->f_bfree,
4218 FSData->f_bsize));
4221 cifs_buf_release(pSMB);
4223 if (rc == -EAGAIN)
4224 goto oldQFSInfoRetry;
4226 return rc;
4230 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4232 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4233 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4234 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4235 FILE_SYSTEM_INFO *response_data;
4236 int rc = 0;
4237 int bytes_returned = 0;
4238 __u16 params, byte_count;
4240 cFYI(1, ("In QFSInfo"));
4241 QFSInfoRetry:
4242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4243 (void **) &pSMBr);
4244 if (rc)
4245 return rc;
4247 params = 2; /* level */
4248 pSMB->TotalDataCount = 0;
4249 pSMB->MaxParameterCount = cpu_to_le16(2);
4250 pSMB->MaxDataCount = cpu_to_le16(1000);
4251 pSMB->MaxSetupCount = 0;
4252 pSMB->Reserved = 0;
4253 pSMB->Flags = 0;
4254 pSMB->Timeout = 0;
4255 pSMB->Reserved2 = 0;
4256 byte_count = params + 1 /* pad */ ;
4257 pSMB->TotalParameterCount = cpu_to_le16(params);
4258 pSMB->ParameterCount = pSMB->TotalParameterCount;
4259 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4260 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4261 pSMB->DataCount = 0;
4262 pSMB->DataOffset = 0;
4263 pSMB->SetupCount = 1;
4264 pSMB->Reserved3 = 0;
4265 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4266 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4267 pSMB->hdr.smb_buf_length += byte_count;
4268 pSMB->ByteCount = cpu_to_le16(byte_count);
4270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4271 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4272 if (rc) {
4273 cFYI(1, ("Send error in QFSInfo = %d", rc));
4274 } else { /* decode response */
4275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4277 if (rc || (pSMBr->ByteCount < 24))
4278 rc = -EIO; /* bad smb */
4279 else {
4280 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4282 response_data =
4283 (FILE_SYSTEM_INFO
4284 *) (((char *) &pSMBr->hdr.Protocol) +
4285 data_offset);
4286 FSData->f_bsize =
4287 le32_to_cpu(response_data->BytesPerSector) *
4288 le32_to_cpu(response_data->
4289 SectorsPerAllocationUnit);
4290 FSData->f_blocks =
4291 le64_to_cpu(response_data->TotalAllocationUnits);
4292 FSData->f_bfree = FSData->f_bavail =
4293 le64_to_cpu(response_data->FreeAllocationUnits);
4294 cFYI(1,
4295 ("Blocks: %lld Free: %lld Block size %ld",
4296 (unsigned long long)FSData->f_blocks,
4297 (unsigned long long)FSData->f_bfree,
4298 FSData->f_bsize));
4301 cifs_buf_release(pSMB);
4303 if (rc == -EAGAIN)
4304 goto QFSInfoRetry;
4306 return rc;
4310 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4312 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4313 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4314 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4315 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4316 int rc = 0;
4317 int bytes_returned = 0;
4318 __u16 params, byte_count;
4320 cFYI(1, ("In QFSAttributeInfo"));
4321 QFSAttributeRetry:
4322 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4323 (void **) &pSMBr);
4324 if (rc)
4325 return rc;
4327 params = 2; /* level */
4328 pSMB->TotalDataCount = 0;
4329 pSMB->MaxParameterCount = cpu_to_le16(2);
4330 /* BB find exact max SMB PDU from sess structure BB */
4331 pSMB->MaxDataCount = cpu_to_le16(1000);
4332 pSMB->MaxSetupCount = 0;
4333 pSMB->Reserved = 0;
4334 pSMB->Flags = 0;
4335 pSMB->Timeout = 0;
4336 pSMB->Reserved2 = 0;
4337 byte_count = params + 1 /* pad */ ;
4338 pSMB->TotalParameterCount = cpu_to_le16(params);
4339 pSMB->ParameterCount = pSMB->TotalParameterCount;
4340 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4341 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4342 pSMB->DataCount = 0;
4343 pSMB->DataOffset = 0;
4344 pSMB->SetupCount = 1;
4345 pSMB->Reserved3 = 0;
4346 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4347 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4348 pSMB->hdr.smb_buf_length += byte_count;
4349 pSMB->ByteCount = cpu_to_le16(byte_count);
4351 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4352 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4353 if (rc) {
4354 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4355 } else { /* decode response */
4356 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4358 if (rc || (pSMBr->ByteCount < 13)) {
4359 /* BB also check if enough bytes returned */
4360 rc = -EIO; /* bad smb */
4361 } else {
4362 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4363 response_data =
4364 (FILE_SYSTEM_ATTRIBUTE_INFO
4365 *) (((char *) &pSMBr->hdr.Protocol) +
4366 data_offset);
4367 memcpy(&tcon->fsAttrInfo, response_data,
4368 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4371 cifs_buf_release(pSMB);
4373 if (rc == -EAGAIN)
4374 goto QFSAttributeRetry;
4376 return rc;
4380 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4382 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4383 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4384 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4385 FILE_SYSTEM_DEVICE_INFO *response_data;
4386 int rc = 0;
4387 int bytes_returned = 0;
4388 __u16 params, byte_count;
4390 cFYI(1, ("In QFSDeviceInfo"));
4391 QFSDeviceRetry:
4392 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4393 (void **) &pSMBr);
4394 if (rc)
4395 return rc;
4397 params = 2; /* level */
4398 pSMB->TotalDataCount = 0;
4399 pSMB->MaxParameterCount = cpu_to_le16(2);
4400 /* BB find exact max SMB PDU from sess structure BB */
4401 pSMB->MaxDataCount = cpu_to_le16(1000);
4402 pSMB->MaxSetupCount = 0;
4403 pSMB->Reserved = 0;
4404 pSMB->Flags = 0;
4405 pSMB->Timeout = 0;
4406 pSMB->Reserved2 = 0;
4407 byte_count = params + 1 /* pad */ ;
4408 pSMB->TotalParameterCount = cpu_to_le16(params);
4409 pSMB->ParameterCount = pSMB->TotalParameterCount;
4410 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4411 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4413 pSMB->DataCount = 0;
4414 pSMB->DataOffset = 0;
4415 pSMB->SetupCount = 1;
4416 pSMB->Reserved3 = 0;
4417 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4418 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4419 pSMB->hdr.smb_buf_length += byte_count;
4420 pSMB->ByteCount = cpu_to_le16(byte_count);
4422 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4423 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4424 if (rc) {
4425 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4426 } else { /* decode response */
4427 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4429 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4430 rc = -EIO; /* bad smb */
4431 else {
4432 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4433 response_data =
4434 (FILE_SYSTEM_DEVICE_INFO *)
4435 (((char *) &pSMBr->hdr.Protocol) +
4436 data_offset);
4437 memcpy(&tcon->fsDevInfo, response_data,
4438 sizeof(FILE_SYSTEM_DEVICE_INFO));
4441 cifs_buf_release(pSMB);
4443 if (rc == -EAGAIN)
4444 goto QFSDeviceRetry;
4446 return rc;
4450 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4452 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4453 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4454 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4455 FILE_SYSTEM_UNIX_INFO *response_data;
4456 int rc = 0;
4457 int bytes_returned = 0;
4458 __u16 params, byte_count;
4460 cFYI(1, ("In QFSUnixInfo"));
4461 QFSUnixRetry:
4462 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4463 (void **) &pSMBr);
4464 if (rc)
4465 return rc;
4467 params = 2; /* level */
4468 pSMB->TotalDataCount = 0;
4469 pSMB->DataCount = 0;
4470 pSMB->DataOffset = 0;
4471 pSMB->MaxParameterCount = cpu_to_le16(2);
4472 /* BB find exact max SMB PDU from sess structure BB */
4473 pSMB->MaxDataCount = cpu_to_le16(100);
4474 pSMB->MaxSetupCount = 0;
4475 pSMB->Reserved = 0;
4476 pSMB->Flags = 0;
4477 pSMB->Timeout = 0;
4478 pSMB->Reserved2 = 0;
4479 byte_count = params + 1 /* pad */ ;
4480 pSMB->ParameterCount = cpu_to_le16(params);
4481 pSMB->TotalParameterCount = pSMB->ParameterCount;
4482 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4483 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4484 pSMB->SetupCount = 1;
4485 pSMB->Reserved3 = 0;
4486 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4487 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4488 pSMB->hdr.smb_buf_length += byte_count;
4489 pSMB->ByteCount = cpu_to_le16(byte_count);
4491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4493 if (rc) {
4494 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4495 } else { /* decode response */
4496 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4498 if (rc || (pSMBr->ByteCount < 13)) {
4499 rc = -EIO; /* bad smb */
4500 } else {
4501 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4502 response_data =
4503 (FILE_SYSTEM_UNIX_INFO
4504 *) (((char *) &pSMBr->hdr.Protocol) +
4505 data_offset);
4506 memcpy(&tcon->fsUnixInfo, response_data,
4507 sizeof(FILE_SYSTEM_UNIX_INFO));
4510 cifs_buf_release(pSMB);
4512 if (rc == -EAGAIN)
4513 goto QFSUnixRetry;
4516 return rc;
4520 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4522 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4523 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4524 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4525 int rc = 0;
4526 int bytes_returned = 0;
4527 __u16 params, param_offset, offset, byte_count;
4529 cFYI(1, ("In SETFSUnixInfo"));
4530 SETFSUnixRetry:
4531 /* BB switch to small buf init to save memory */
4532 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4533 (void **) &pSMBr);
4534 if (rc)
4535 return rc;
4537 params = 4; /* 2 bytes zero followed by info level. */
4538 pSMB->MaxSetupCount = 0;
4539 pSMB->Reserved = 0;
4540 pSMB->Flags = 0;
4541 pSMB->Timeout = 0;
4542 pSMB->Reserved2 = 0;
4543 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4544 - 4;
4545 offset = param_offset + params;
4547 pSMB->MaxParameterCount = cpu_to_le16(4);
4548 /* BB find exact max SMB PDU from sess structure BB */
4549 pSMB->MaxDataCount = cpu_to_le16(100);
4550 pSMB->SetupCount = 1;
4551 pSMB->Reserved3 = 0;
4552 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4553 byte_count = 1 /* pad */ + params + 12;
4555 pSMB->DataCount = cpu_to_le16(12);
4556 pSMB->ParameterCount = cpu_to_le16(params);
4557 pSMB->TotalDataCount = pSMB->DataCount;
4558 pSMB->TotalParameterCount = pSMB->ParameterCount;
4559 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4560 pSMB->DataOffset = cpu_to_le16(offset);
4562 /* Params. */
4563 pSMB->FileNum = 0;
4564 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4566 /* Data. */
4567 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4568 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4569 pSMB->ClientUnixCap = cpu_to_le64(cap);
4571 pSMB->hdr.smb_buf_length += byte_count;
4572 pSMB->ByteCount = cpu_to_le16(byte_count);
4574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4576 if (rc) {
4577 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4578 } else { /* decode response */
4579 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4580 if (rc)
4581 rc = -EIO; /* bad smb */
4583 cifs_buf_release(pSMB);
4585 if (rc == -EAGAIN)
4586 goto SETFSUnixRetry;
4588 return rc;
4594 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4595 struct kstatfs *FSData)
4597 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4598 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4599 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4600 FILE_SYSTEM_POSIX_INFO *response_data;
4601 int rc = 0;
4602 int bytes_returned = 0;
4603 __u16 params, byte_count;
4605 cFYI(1, ("In QFSPosixInfo"));
4606 QFSPosixRetry:
4607 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4608 (void **) &pSMBr);
4609 if (rc)
4610 return rc;
4612 params = 2; /* level */
4613 pSMB->TotalDataCount = 0;
4614 pSMB->DataCount = 0;
4615 pSMB->DataOffset = 0;
4616 pSMB->MaxParameterCount = cpu_to_le16(2);
4617 /* BB find exact max SMB PDU from sess structure BB */
4618 pSMB->MaxDataCount = cpu_to_le16(100);
4619 pSMB->MaxSetupCount = 0;
4620 pSMB->Reserved = 0;
4621 pSMB->Flags = 0;
4622 pSMB->Timeout = 0;
4623 pSMB->Reserved2 = 0;
4624 byte_count = params + 1 /* pad */ ;
4625 pSMB->ParameterCount = cpu_to_le16(params);
4626 pSMB->TotalParameterCount = pSMB->ParameterCount;
4627 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4628 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4629 pSMB->SetupCount = 1;
4630 pSMB->Reserved3 = 0;
4631 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4632 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4633 pSMB->hdr.smb_buf_length += byte_count;
4634 pSMB->ByteCount = cpu_to_le16(byte_count);
4636 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4637 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4638 if (rc) {
4639 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4640 } else { /* decode response */
4641 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4643 if (rc || (pSMBr->ByteCount < 13)) {
4644 rc = -EIO; /* bad smb */
4645 } else {
4646 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4647 response_data =
4648 (FILE_SYSTEM_POSIX_INFO
4649 *) (((char *) &pSMBr->hdr.Protocol) +
4650 data_offset);
4651 FSData->f_bsize =
4652 le32_to_cpu(response_data->BlockSize);
4653 FSData->f_blocks =
4654 le64_to_cpu(response_data->TotalBlocks);
4655 FSData->f_bfree =
4656 le64_to_cpu(response_data->BlocksAvail);
4657 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4658 FSData->f_bavail = FSData->f_bfree;
4659 } else {
4660 FSData->f_bavail =
4661 le64_to_cpu(response_data->UserBlocksAvail);
4663 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4664 FSData->f_files =
4665 le64_to_cpu(response_data->TotalFileNodes);
4666 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4667 FSData->f_ffree =
4668 le64_to_cpu(response_data->FreeFileNodes);
4671 cifs_buf_release(pSMB);
4673 if (rc == -EAGAIN)
4674 goto QFSPosixRetry;
4676 return rc;
4680 /* We can not use write of zero bytes trick to
4681 set file size due to need for large file support. Also note that
4682 this SetPathInfo is preferred to SetFileInfo based method in next
4683 routine which is only needed to work around a sharing violation bug
4684 in Samba which this routine can run into */
4687 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4688 __u64 size, bool SetAllocation,
4689 const struct nls_table *nls_codepage, int remap)
4691 struct smb_com_transaction2_spi_req *pSMB = NULL;
4692 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4693 struct file_end_of_file_info *parm_data;
4694 int name_len;
4695 int rc = 0;
4696 int bytes_returned = 0;
4697 __u16 params, byte_count, data_count, param_offset, offset;
4699 cFYI(1, ("In SetEOF"));
4700 SetEOFRetry:
4701 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4702 (void **) &pSMBr);
4703 if (rc)
4704 return rc;
4706 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4707 name_len =
4708 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4709 PATH_MAX, nls_codepage, remap);
4710 name_len++; /* trailing null */
4711 name_len *= 2;
4712 } else { /* BB improve the check for buffer overruns BB */
4713 name_len = strnlen(fileName, PATH_MAX);
4714 name_len++; /* trailing null */
4715 strncpy(pSMB->FileName, fileName, name_len);
4717 params = 6 + name_len;
4718 data_count = sizeof(struct file_end_of_file_info);
4719 pSMB->MaxParameterCount = cpu_to_le16(2);
4720 pSMB->MaxDataCount = cpu_to_le16(4100);
4721 pSMB->MaxSetupCount = 0;
4722 pSMB->Reserved = 0;
4723 pSMB->Flags = 0;
4724 pSMB->Timeout = 0;
4725 pSMB->Reserved2 = 0;
4726 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4727 InformationLevel) - 4;
4728 offset = param_offset + params;
4729 if (SetAllocation) {
4730 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4731 pSMB->InformationLevel =
4732 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4733 else
4734 pSMB->InformationLevel =
4735 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4736 } else /* Set File Size */ {
4737 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4738 pSMB->InformationLevel =
4739 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4740 else
4741 pSMB->InformationLevel =
4742 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4745 parm_data =
4746 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4747 offset);
4748 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4749 pSMB->DataOffset = cpu_to_le16(offset);
4750 pSMB->SetupCount = 1;
4751 pSMB->Reserved3 = 0;
4752 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4753 byte_count = 3 /* pad */ + params + data_count;
4754 pSMB->DataCount = cpu_to_le16(data_count);
4755 pSMB->TotalDataCount = pSMB->DataCount;
4756 pSMB->ParameterCount = cpu_to_le16(params);
4757 pSMB->TotalParameterCount = pSMB->ParameterCount;
4758 pSMB->Reserved4 = 0;
4759 pSMB->hdr.smb_buf_length += byte_count;
4760 parm_data->FileSize = cpu_to_le64(size);
4761 pSMB->ByteCount = cpu_to_le16(byte_count);
4762 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4763 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4764 if (rc)
4765 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4767 cifs_buf_release(pSMB);
4769 if (rc == -EAGAIN)
4770 goto SetEOFRetry;
4772 return rc;
4776 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4777 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4779 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4780 char *data_offset;
4781 struct file_end_of_file_info *parm_data;
4782 int rc = 0;
4783 __u16 params, param_offset, offset, byte_count, count;
4785 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4786 (long long)size));
4787 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4789 if (rc)
4790 return rc;
4792 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4793 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4795 params = 6;
4796 pSMB->MaxSetupCount = 0;
4797 pSMB->Reserved = 0;
4798 pSMB->Flags = 0;
4799 pSMB->Timeout = 0;
4800 pSMB->Reserved2 = 0;
4801 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4802 offset = param_offset + params;
4804 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4806 count = sizeof(struct file_end_of_file_info);
4807 pSMB->MaxParameterCount = cpu_to_le16(2);
4808 /* BB find exact max SMB PDU from sess structure BB */
4809 pSMB->MaxDataCount = cpu_to_le16(1000);
4810 pSMB->SetupCount = 1;
4811 pSMB->Reserved3 = 0;
4812 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4813 byte_count = 3 /* pad */ + params + count;
4814 pSMB->DataCount = cpu_to_le16(count);
4815 pSMB->ParameterCount = cpu_to_le16(params);
4816 pSMB->TotalDataCount = pSMB->DataCount;
4817 pSMB->TotalParameterCount = pSMB->ParameterCount;
4818 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4819 parm_data =
4820 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4821 + offset);
4822 pSMB->DataOffset = cpu_to_le16(offset);
4823 parm_data->FileSize = cpu_to_le64(size);
4824 pSMB->Fid = fid;
4825 if (SetAllocation) {
4826 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4827 pSMB->InformationLevel =
4828 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4829 else
4830 pSMB->InformationLevel =
4831 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4832 } else /* Set File Size */ {
4833 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4834 pSMB->InformationLevel =
4835 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4836 else
4837 pSMB->InformationLevel =
4838 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4840 pSMB->Reserved4 = 0;
4841 pSMB->hdr.smb_buf_length += byte_count;
4842 pSMB->ByteCount = cpu_to_le16(byte_count);
4843 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4844 if (rc) {
4845 cFYI(1,
4846 ("Send error in SetFileInfo (SetFileSize) = %d",
4847 rc));
4850 /* Note: On -EAGAIN error only caller can retry on handle based calls
4851 since file handle passed in no longer valid */
4853 return rc;
4856 /* Some legacy servers such as NT4 require that the file times be set on
4857 an open handle, rather than by pathname - this is awkward due to
4858 potential access conflicts on the open, but it is unavoidable for these
4859 old servers since the only other choice is to go from 100 nanosecond DCE
4860 time and resort to the original setpathinfo level which takes the ancient
4861 DOS time format with 2 second granularity */
4863 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4864 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4866 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4867 char *data_offset;
4868 int rc = 0;
4869 __u16 params, param_offset, offset, byte_count, count;
4871 cFYI(1, ("Set Times (via SetFileInfo)"));
4872 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4874 if (rc)
4875 return rc;
4877 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4878 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4880 params = 6;
4881 pSMB->MaxSetupCount = 0;
4882 pSMB->Reserved = 0;
4883 pSMB->Flags = 0;
4884 pSMB->Timeout = 0;
4885 pSMB->Reserved2 = 0;
4886 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4887 offset = param_offset + params;
4889 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4891 count = sizeof(FILE_BASIC_INFO);
4892 pSMB->MaxParameterCount = cpu_to_le16(2);
4893 /* BB find max SMB PDU from sess */
4894 pSMB->MaxDataCount = cpu_to_le16(1000);
4895 pSMB->SetupCount = 1;
4896 pSMB->Reserved3 = 0;
4897 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4898 byte_count = 3 /* pad */ + params + count;
4899 pSMB->DataCount = cpu_to_le16(count);
4900 pSMB->ParameterCount = cpu_to_le16(params);
4901 pSMB->TotalDataCount = pSMB->DataCount;
4902 pSMB->TotalParameterCount = pSMB->ParameterCount;
4903 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4904 pSMB->DataOffset = cpu_to_le16(offset);
4905 pSMB->Fid = fid;
4906 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4907 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4908 else
4909 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4910 pSMB->Reserved4 = 0;
4911 pSMB->hdr.smb_buf_length += byte_count;
4912 pSMB->ByteCount = cpu_to_le16(byte_count);
4913 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4914 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4915 if (rc)
4916 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4918 /* Note: On -EAGAIN error only caller can retry on handle based calls
4919 since file handle passed in no longer valid */
4921 return rc;
4925 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4926 bool delete_file, __u16 fid, __u32 pid_of_opener)
4928 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4929 char *data_offset;
4930 int rc = 0;
4931 __u16 params, param_offset, offset, byte_count, count;
4933 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4934 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4936 if (rc)
4937 return rc;
4939 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4940 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4942 params = 6;
4943 pSMB->MaxSetupCount = 0;
4944 pSMB->Reserved = 0;
4945 pSMB->Flags = 0;
4946 pSMB->Timeout = 0;
4947 pSMB->Reserved2 = 0;
4948 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4949 offset = param_offset + params;
4951 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4953 count = 1;
4954 pSMB->MaxParameterCount = cpu_to_le16(2);
4955 /* BB find max SMB PDU from sess */
4956 pSMB->MaxDataCount = cpu_to_le16(1000);
4957 pSMB->SetupCount = 1;
4958 pSMB->Reserved3 = 0;
4959 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4960 byte_count = 3 /* pad */ + params + count;
4961 pSMB->DataCount = cpu_to_le16(count);
4962 pSMB->ParameterCount = cpu_to_le16(params);
4963 pSMB->TotalDataCount = pSMB->DataCount;
4964 pSMB->TotalParameterCount = pSMB->ParameterCount;
4965 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4966 pSMB->DataOffset = cpu_to_le16(offset);
4967 pSMB->Fid = fid;
4968 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4969 pSMB->Reserved4 = 0;
4970 pSMB->hdr.smb_buf_length += byte_count;
4971 pSMB->ByteCount = cpu_to_le16(byte_count);
4972 *data_offset = delete_file ? 1 : 0;
4973 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4974 if (rc)
4975 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4977 return rc;
4981 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4982 const char *fileName, const FILE_BASIC_INFO *data,
4983 const struct nls_table *nls_codepage, int remap)
4985 TRANSACTION2_SPI_REQ *pSMB = NULL;
4986 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4987 int name_len;
4988 int rc = 0;
4989 int bytes_returned = 0;
4990 char *data_offset;
4991 __u16 params, param_offset, offset, byte_count, count;
4993 cFYI(1, ("In SetTimes"));
4995 SetTimesRetry:
4996 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4997 (void **) &pSMBr);
4998 if (rc)
4999 return rc;
5001 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5002 name_len =
5003 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5004 PATH_MAX, nls_codepage, remap);
5005 name_len++; /* trailing null */
5006 name_len *= 2;
5007 } else { /* BB improve the check for buffer overruns BB */
5008 name_len = strnlen(fileName, PATH_MAX);
5009 name_len++; /* trailing null */
5010 strncpy(pSMB->FileName, fileName, name_len);
5013 params = 6 + name_len;
5014 count = sizeof(FILE_BASIC_INFO);
5015 pSMB->MaxParameterCount = cpu_to_le16(2);
5016 /* BB find max SMB PDU from sess structure BB */
5017 pSMB->MaxDataCount = cpu_to_le16(1000);
5018 pSMB->MaxSetupCount = 0;
5019 pSMB->Reserved = 0;
5020 pSMB->Flags = 0;
5021 pSMB->Timeout = 0;
5022 pSMB->Reserved2 = 0;
5023 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5024 InformationLevel) - 4;
5025 offset = param_offset + params;
5026 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5027 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5028 pSMB->DataOffset = cpu_to_le16(offset);
5029 pSMB->SetupCount = 1;
5030 pSMB->Reserved3 = 0;
5031 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5032 byte_count = 3 /* pad */ + params + count;
5034 pSMB->DataCount = cpu_to_le16(count);
5035 pSMB->ParameterCount = cpu_to_le16(params);
5036 pSMB->TotalDataCount = pSMB->DataCount;
5037 pSMB->TotalParameterCount = pSMB->ParameterCount;
5038 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5039 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5040 else
5041 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5042 pSMB->Reserved4 = 0;
5043 pSMB->hdr.smb_buf_length += byte_count;
5044 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5045 pSMB->ByteCount = cpu_to_le16(byte_count);
5046 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5047 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5048 if (rc)
5049 cFYI(1, ("SetPathInfo (times) returned %d", rc));
5051 cifs_buf_release(pSMB);
5053 if (rc == -EAGAIN)
5054 goto SetTimesRetry;
5056 return rc;
5059 /* Can not be used to set time stamps yet (due to old DOS time format) */
5060 /* Can be used to set attributes */
5061 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5062 handling it anyway and NT4 was what we thought it would be needed for
5063 Do not delete it until we prove whether needed for Win9x though */
5065 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5066 __u16 dos_attrs, const struct nls_table *nls_codepage)
5068 SETATTR_REQ *pSMB = NULL;
5069 SETATTR_RSP *pSMBr = NULL;
5070 int rc = 0;
5071 int bytes_returned;
5072 int name_len;
5074 cFYI(1, ("In SetAttrLegacy"));
5076 SetAttrLgcyRetry:
5077 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5078 (void **) &pSMBr);
5079 if (rc)
5080 return rc;
5082 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5083 name_len =
5084 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5085 PATH_MAX, nls_codepage);
5086 name_len++; /* trailing null */
5087 name_len *= 2;
5088 } else { /* BB improve the check for buffer overruns BB */
5089 name_len = strnlen(fileName, PATH_MAX);
5090 name_len++; /* trailing null */
5091 strncpy(pSMB->fileName, fileName, name_len);
5093 pSMB->attr = cpu_to_le16(dos_attrs);
5094 pSMB->BufferFormat = 0x04;
5095 pSMB->hdr.smb_buf_length += name_len + 1;
5096 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5099 if (rc)
5100 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5102 cifs_buf_release(pSMB);
5104 if (rc == -EAGAIN)
5105 goto SetAttrLgcyRetry;
5107 return rc;
5109 #endif /* temporarily unneeded SetAttr legacy function */
5112 CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5113 const struct cifs_unix_set_info_args *args,
5114 const struct nls_table *nls_codepage, int remap)
5116 TRANSACTION2_SPI_REQ *pSMB = NULL;
5117 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5118 int name_len;
5119 int rc = 0;
5120 int bytes_returned = 0;
5121 FILE_UNIX_BASIC_INFO *data_offset;
5122 __u16 params, param_offset, offset, count, byte_count;
5123 __u64 mode = args->mode;
5125 cFYI(1, ("In SetUID/GID/Mode"));
5126 setPermsRetry:
5127 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5128 (void **) &pSMBr);
5129 if (rc)
5130 return rc;
5132 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5133 name_len =
5134 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5135 PATH_MAX, nls_codepage, remap);
5136 name_len++; /* trailing null */
5137 name_len *= 2;
5138 } else { /* BB improve the check for buffer overruns BB */
5139 name_len = strnlen(fileName, PATH_MAX);
5140 name_len++; /* trailing null */
5141 strncpy(pSMB->FileName, fileName, name_len);
5144 params = 6 + name_len;
5145 count = sizeof(FILE_UNIX_BASIC_INFO);
5146 pSMB->MaxParameterCount = cpu_to_le16(2);
5147 /* BB find max SMB PDU from sess structure BB */
5148 pSMB->MaxDataCount = cpu_to_le16(1000);
5149 pSMB->MaxSetupCount = 0;
5150 pSMB->Reserved = 0;
5151 pSMB->Flags = 0;
5152 pSMB->Timeout = 0;
5153 pSMB->Reserved2 = 0;
5154 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5155 InformationLevel) - 4;
5156 offset = param_offset + params;
5157 data_offset =
5158 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5159 offset);
5160 memset(data_offset, 0, count);
5161 pSMB->DataOffset = cpu_to_le16(offset);
5162 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5163 pSMB->SetupCount = 1;
5164 pSMB->Reserved3 = 0;
5165 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5166 byte_count = 3 /* pad */ + params + count;
5167 pSMB->ParameterCount = cpu_to_le16(params);
5168 pSMB->DataCount = cpu_to_le16(count);
5169 pSMB->TotalParameterCount = pSMB->ParameterCount;
5170 pSMB->TotalDataCount = pSMB->DataCount;
5171 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5172 pSMB->Reserved4 = 0;
5173 pSMB->hdr.smb_buf_length += byte_count;
5174 /* Samba server ignores set of file size to zero due to bugs in some
5175 older clients, but we should be precise - we use SetFileSize to
5176 set file size and do not want to truncate file size to zero
5177 accidently as happened on one Samba server beta by putting
5178 zero instead of -1 here */
5179 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5180 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5181 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5182 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5183 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5184 data_offset->Uid = cpu_to_le64(args->uid);
5185 data_offset->Gid = cpu_to_le64(args->gid);
5186 /* better to leave device as zero when it is */
5187 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5188 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5189 data_offset->Permissions = cpu_to_le64(mode);
5191 if (S_ISREG(mode))
5192 data_offset->Type = cpu_to_le32(UNIX_FILE);
5193 else if (S_ISDIR(mode))
5194 data_offset->Type = cpu_to_le32(UNIX_DIR);
5195 else if (S_ISLNK(mode))
5196 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5197 else if (S_ISCHR(mode))
5198 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5199 else if (S_ISBLK(mode))
5200 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5201 else if (S_ISFIFO(mode))
5202 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5203 else if (S_ISSOCK(mode))
5204 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5207 pSMB->ByteCount = cpu_to_le16(byte_count);
5208 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5209 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5210 if (rc)
5211 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5213 cifs_buf_release(pSMB);
5214 if (rc == -EAGAIN)
5215 goto setPermsRetry;
5216 return rc;
5219 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5220 const int notify_subdirs, const __u16 netfid,
5221 __u32 filter, struct file *pfile, int multishot,
5222 const struct nls_table *nls_codepage)
5224 int rc = 0;
5225 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5226 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5227 struct dir_notify_req *dnotify_req;
5228 int bytes_returned;
5230 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5231 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5232 (void **) &pSMBr);
5233 if (rc)
5234 return rc;
5236 pSMB->TotalParameterCount = 0 ;
5237 pSMB->TotalDataCount = 0;
5238 pSMB->MaxParameterCount = cpu_to_le32(2);
5239 /* BB find exact data count max from sess structure BB */
5240 pSMB->MaxDataCount = 0; /* same in little endian or be */
5241 /* BB VERIFY verify which is correct for above BB */
5242 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5243 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5245 pSMB->MaxSetupCount = 4;
5246 pSMB->Reserved = 0;
5247 pSMB->ParameterOffset = 0;
5248 pSMB->DataCount = 0;
5249 pSMB->DataOffset = 0;
5250 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5251 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5252 pSMB->ParameterCount = pSMB->TotalParameterCount;
5253 if (notify_subdirs)
5254 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5255 pSMB->Reserved2 = 0;
5256 pSMB->CompletionFilter = cpu_to_le32(filter);
5257 pSMB->Fid = netfid; /* file handle always le */
5258 pSMB->ByteCount = 0;
5260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5261 (struct smb_hdr *)pSMBr, &bytes_returned,
5262 CIFS_ASYNC_OP);
5263 if (rc) {
5264 cFYI(1, ("Error in Notify = %d", rc));
5265 } else {
5266 /* Add file to outstanding requests */
5267 /* BB change to kmem cache alloc */
5268 dnotify_req = kmalloc(
5269 sizeof(struct dir_notify_req),
5270 GFP_KERNEL);
5271 if (dnotify_req) {
5272 dnotify_req->Pid = pSMB->hdr.Pid;
5273 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5274 dnotify_req->Mid = pSMB->hdr.Mid;
5275 dnotify_req->Tid = pSMB->hdr.Tid;
5276 dnotify_req->Uid = pSMB->hdr.Uid;
5277 dnotify_req->netfid = netfid;
5278 dnotify_req->pfile = pfile;
5279 dnotify_req->filter = filter;
5280 dnotify_req->multishot = multishot;
5281 spin_lock(&GlobalMid_Lock);
5282 list_add_tail(&dnotify_req->lhead,
5283 &GlobalDnotifyReqList);
5284 spin_unlock(&GlobalMid_Lock);
5285 } else
5286 rc = -ENOMEM;
5288 cifs_buf_release(pSMB);
5289 return rc;
5291 #ifdef CONFIG_CIFS_XATTR
5292 ssize_t
5293 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5294 const unsigned char *searchName,
5295 char *EAData, size_t buf_size,
5296 const struct nls_table *nls_codepage, int remap)
5298 /* BB assumes one setup word */
5299 TRANSACTION2_QPI_REQ *pSMB = NULL;
5300 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5301 int rc = 0;
5302 int bytes_returned;
5303 int name_len;
5304 struct fea *temp_fea;
5305 char *temp_ptr;
5306 __u16 params, byte_count;
5308 cFYI(1, ("In Query All EAs path %s", searchName));
5309 QAllEAsRetry:
5310 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5311 (void **) &pSMBr);
5312 if (rc)
5313 return rc;
5315 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5316 name_len =
5317 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5318 PATH_MAX, nls_codepage, remap);
5319 name_len++; /* trailing null */
5320 name_len *= 2;
5321 } else { /* BB improve the check for buffer overruns BB */
5322 name_len = strnlen(searchName, PATH_MAX);
5323 name_len++; /* trailing null */
5324 strncpy(pSMB->FileName, searchName, name_len);
5327 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5328 pSMB->TotalDataCount = 0;
5329 pSMB->MaxParameterCount = cpu_to_le16(2);
5330 /* BB find exact max SMB PDU from sess structure BB */
5331 pSMB->MaxDataCount = cpu_to_le16(4000);
5332 pSMB->MaxSetupCount = 0;
5333 pSMB->Reserved = 0;
5334 pSMB->Flags = 0;
5335 pSMB->Timeout = 0;
5336 pSMB->Reserved2 = 0;
5337 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5338 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5339 pSMB->DataCount = 0;
5340 pSMB->DataOffset = 0;
5341 pSMB->SetupCount = 1;
5342 pSMB->Reserved3 = 0;
5343 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5344 byte_count = params + 1 /* pad */ ;
5345 pSMB->TotalParameterCount = cpu_to_le16(params);
5346 pSMB->ParameterCount = pSMB->TotalParameterCount;
5347 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5348 pSMB->Reserved4 = 0;
5349 pSMB->hdr.smb_buf_length += byte_count;
5350 pSMB->ByteCount = cpu_to_le16(byte_count);
5352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5354 if (rc) {
5355 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5356 } else { /* decode response */
5357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5359 /* BB also check enough total bytes returned */
5360 /* BB we need to improve the validity checking
5361 of these trans2 responses */
5362 if (rc || (pSMBr->ByteCount < 4))
5363 rc = -EIO; /* bad smb */
5364 /* else if (pFindData){
5365 memcpy((char *) pFindData,
5366 (char *) &pSMBr->hdr.Protocol +
5367 data_offset, kl);
5368 }*/ else {
5369 /* check that length of list is not more than bcc */
5370 /* check that each entry does not go beyond length
5371 of list */
5372 /* check that each element of each entry does not
5373 go beyond end of list */
5374 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5375 struct fealist *ea_response_data;
5376 rc = 0;
5377 /* validate_trans2_offsets() */
5378 /* BB check if start of smb + data_offset > &bcc+ bcc */
5379 ea_response_data = (struct fealist *)
5380 (((char *) &pSMBr->hdr.Protocol) +
5381 data_offset);
5382 name_len = le32_to_cpu(ea_response_data->list_len);
5383 cFYI(1, ("ea length %d", name_len));
5384 if (name_len <= 8) {
5385 /* returned EA size zeroed at top of function */
5386 cFYI(1, ("empty EA list returned from server"));
5387 } else {
5388 /* account for ea list len */
5389 name_len -= 4;
5390 temp_fea = ea_response_data->list;
5391 temp_ptr = (char *)temp_fea;
5392 while (name_len > 0) {
5393 __u16 value_len;
5394 name_len -= 4;
5395 temp_ptr += 4;
5396 rc += temp_fea->name_len;
5397 /* account for prefix user. and trailing null */
5398 rc = rc + 5 + 1;
5399 if (rc < (int)buf_size) {
5400 memcpy(EAData, "user.", 5);
5401 EAData += 5;
5402 memcpy(EAData, temp_ptr,
5403 temp_fea->name_len);
5404 EAData += temp_fea->name_len;
5405 /* null terminate name */
5406 *EAData = 0;
5407 EAData = EAData + 1;
5408 } else if (buf_size == 0) {
5409 /* skip copy - calc size only */
5410 } else {
5411 /* stop before overrun buffer */
5412 rc = -ERANGE;
5413 break;
5415 name_len -= temp_fea->name_len;
5416 temp_ptr += temp_fea->name_len;
5417 /* account for trailing null */
5418 name_len--;
5419 temp_ptr++;
5420 value_len =
5421 le16_to_cpu(temp_fea->value_len);
5422 name_len -= value_len;
5423 temp_ptr += value_len;
5424 /* BB check that temp_ptr is still
5425 within the SMB BB*/
5427 /* no trailing null to account for
5428 in value len */
5429 /* go on to next EA */
5430 temp_fea = (struct fea *)temp_ptr;
5435 cifs_buf_release(pSMB);
5436 if (rc == -EAGAIN)
5437 goto QAllEAsRetry;
5439 return (ssize_t)rc;
5442 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5443 const unsigned char *searchName, const unsigned char *ea_name,
5444 unsigned char *ea_value, size_t buf_size,
5445 const struct nls_table *nls_codepage, int remap)
5447 TRANSACTION2_QPI_REQ *pSMB = NULL;
5448 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5449 int rc = 0;
5450 int bytes_returned;
5451 int name_len;
5452 struct fea *temp_fea;
5453 char *temp_ptr;
5454 __u16 params, byte_count;
5456 cFYI(1, ("In Query EA path %s", searchName));
5457 QEARetry:
5458 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5459 (void **) &pSMBr);
5460 if (rc)
5461 return rc;
5463 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5464 name_len =
5465 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5466 PATH_MAX, nls_codepage, remap);
5467 name_len++; /* trailing null */
5468 name_len *= 2;
5469 } else { /* BB improve the check for buffer overruns BB */
5470 name_len = strnlen(searchName, PATH_MAX);
5471 name_len++; /* trailing null */
5472 strncpy(pSMB->FileName, searchName, name_len);
5475 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5476 pSMB->TotalDataCount = 0;
5477 pSMB->MaxParameterCount = cpu_to_le16(2);
5478 /* BB find exact max SMB PDU from sess structure BB */
5479 pSMB->MaxDataCount = cpu_to_le16(4000);
5480 pSMB->MaxSetupCount = 0;
5481 pSMB->Reserved = 0;
5482 pSMB->Flags = 0;
5483 pSMB->Timeout = 0;
5484 pSMB->Reserved2 = 0;
5485 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5486 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5487 pSMB->DataCount = 0;
5488 pSMB->DataOffset = 0;
5489 pSMB->SetupCount = 1;
5490 pSMB->Reserved3 = 0;
5491 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5492 byte_count = params + 1 /* pad */ ;
5493 pSMB->TotalParameterCount = cpu_to_le16(params);
5494 pSMB->ParameterCount = pSMB->TotalParameterCount;
5495 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5496 pSMB->Reserved4 = 0;
5497 pSMB->hdr.smb_buf_length += byte_count;
5498 pSMB->ByteCount = cpu_to_le16(byte_count);
5500 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5501 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5502 if (rc) {
5503 cFYI(1, ("Send error in Query EA = %d", rc));
5504 } else { /* decode response */
5505 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5507 /* BB also check enough total bytes returned */
5508 /* BB we need to improve the validity checking
5509 of these trans2 responses */
5510 if (rc || (pSMBr->ByteCount < 4))
5511 rc = -EIO; /* bad smb */
5512 /* else if (pFindData){
5513 memcpy((char *) pFindData,
5514 (char *) &pSMBr->hdr.Protocol +
5515 data_offset, kl);
5516 }*/ else {
5517 /* check that length of list is not more than bcc */
5518 /* check that each entry does not go beyond length
5519 of list */
5520 /* check that each element of each entry does not
5521 go beyond end of list */
5522 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5523 struct fealist *ea_response_data;
5524 rc = -ENODATA;
5525 /* validate_trans2_offsets() */
5526 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5527 ea_response_data = (struct fealist *)
5528 (((char *) &pSMBr->hdr.Protocol) +
5529 data_offset);
5530 name_len = le32_to_cpu(ea_response_data->list_len);
5531 cFYI(1, ("ea length %d", name_len));
5532 if (name_len <= 8) {
5533 /* returned EA size zeroed at top of function */
5534 cFYI(1, ("empty EA list returned from server"));
5535 } else {
5536 /* account for ea list len */
5537 name_len -= 4;
5538 temp_fea = ea_response_data->list;
5539 temp_ptr = (char *)temp_fea;
5540 /* loop through checking if we have a matching
5541 name and then return the associated value */
5542 while (name_len > 0) {
5543 __u16 value_len;
5544 name_len -= 4;
5545 temp_ptr += 4;
5546 value_len =
5547 le16_to_cpu(temp_fea->value_len);
5548 /* BB validate that value_len falls within SMB,
5549 even though maximum for name_len is 255 */
5550 if (memcmp(temp_fea->name, ea_name,
5551 temp_fea->name_len) == 0) {
5552 /* found a match */
5553 rc = value_len;
5554 /* account for prefix user. and trailing null */
5555 if (rc <= (int)buf_size) {
5556 memcpy(ea_value,
5557 temp_fea->name+temp_fea->name_len+1,
5558 rc);
5559 /* ea values, unlike ea
5560 names, are not null
5561 terminated */
5562 } else if (buf_size == 0) {
5563 /* skip copy - calc size only */
5564 } else {
5565 /* stop before overrun buffer */
5566 rc = -ERANGE;
5568 break;
5570 name_len -= temp_fea->name_len;
5571 temp_ptr += temp_fea->name_len;
5572 /* account for trailing null */
5573 name_len--;
5574 temp_ptr++;
5575 name_len -= value_len;
5576 temp_ptr += value_len;
5577 /* No trailing null to account for in
5578 value_len. Go on to next EA */
5579 temp_fea = (struct fea *)temp_ptr;
5584 cifs_buf_release(pSMB);
5585 if (rc == -EAGAIN)
5586 goto QEARetry;
5588 return (ssize_t)rc;
5592 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5593 const char *ea_name, const void *ea_value,
5594 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5595 int remap)
5597 struct smb_com_transaction2_spi_req *pSMB = NULL;
5598 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5599 struct fealist *parm_data;
5600 int name_len;
5601 int rc = 0;
5602 int bytes_returned = 0;
5603 __u16 params, param_offset, byte_count, offset, count;
5605 cFYI(1, ("In SetEA"));
5606 SetEARetry:
5607 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5608 (void **) &pSMBr);
5609 if (rc)
5610 return rc;
5612 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5613 name_len =
5614 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5615 PATH_MAX, nls_codepage, remap);
5616 name_len++; /* trailing null */
5617 name_len *= 2;
5618 } else { /* BB improve the check for buffer overruns BB */
5619 name_len = strnlen(fileName, PATH_MAX);
5620 name_len++; /* trailing null */
5621 strncpy(pSMB->FileName, fileName, name_len);
5624 params = 6 + name_len;
5626 /* done calculating parms using name_len of file name,
5627 now use name_len to calculate length of ea name
5628 we are going to create in the inode xattrs */
5629 if (ea_name == NULL)
5630 name_len = 0;
5631 else
5632 name_len = strnlen(ea_name, 255);
5634 count = sizeof(*parm_data) + ea_value_len + name_len;
5635 pSMB->MaxParameterCount = cpu_to_le16(2);
5636 /* BB find max SMB PDU from sess */
5637 pSMB->MaxDataCount = cpu_to_le16(1000);
5638 pSMB->MaxSetupCount = 0;
5639 pSMB->Reserved = 0;
5640 pSMB->Flags = 0;
5641 pSMB->Timeout = 0;
5642 pSMB->Reserved2 = 0;
5643 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5644 InformationLevel) - 4;
5645 offset = param_offset + params;
5646 pSMB->InformationLevel =
5647 cpu_to_le16(SMB_SET_FILE_EA);
5649 parm_data =
5650 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5651 offset);
5652 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5653 pSMB->DataOffset = cpu_to_le16(offset);
5654 pSMB->SetupCount = 1;
5655 pSMB->Reserved3 = 0;
5656 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5657 byte_count = 3 /* pad */ + params + count;
5658 pSMB->DataCount = cpu_to_le16(count);
5659 parm_data->list_len = cpu_to_le32(count);
5660 parm_data->list[0].EA_flags = 0;
5661 /* we checked above that name len is less than 255 */
5662 parm_data->list[0].name_len = (__u8)name_len;
5663 /* EA names are always ASCII */
5664 if (ea_name)
5665 strncpy(parm_data->list[0].name, ea_name, name_len);
5666 parm_data->list[0].name[name_len] = 0;
5667 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5668 /* caller ensures that ea_value_len is less than 64K but
5669 we need to ensure that it fits within the smb */
5671 /*BB add length check to see if it would fit in
5672 negotiated SMB buffer size BB */
5673 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5674 if (ea_value_len)
5675 memcpy(parm_data->list[0].name+name_len+1,
5676 ea_value, ea_value_len);
5678 pSMB->TotalDataCount = pSMB->DataCount;
5679 pSMB->ParameterCount = cpu_to_le16(params);
5680 pSMB->TotalParameterCount = pSMB->ParameterCount;
5681 pSMB->Reserved4 = 0;
5682 pSMB->hdr.smb_buf_length += byte_count;
5683 pSMB->ByteCount = cpu_to_le16(byte_count);
5684 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5685 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5686 if (rc)
5687 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5689 cifs_buf_release(pSMB);
5691 if (rc == -EAGAIN)
5692 goto SetEARetry;
5694 return rc;
5697 #endif