cifs: rename CIFSSMBUnixSetInfo to CIFSSMBUnixSetPathInfo
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blob1cd01ba03656375cebb48cd8c78d51bc16fee863
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2009
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 /* Mark as invalid, all open files on tree connections since they
85 were closed when session to server was lost */
86 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
88 struct cifsFileInfo *open_file = NULL;
89 struct list_head *tmp;
90 struct list_head *tmp1;
92 /* list all files open on tree connection and mark them invalid */
93 write_lock(&GlobalSMBSeslock);
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
95 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
96 open_file->invalidHandle = true;
98 write_unlock(&GlobalSMBSeslock);
99 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
100 to this tcon */
103 /* Allocate and return pointer to an SMB request buffer, and set basic
104 SMB information in the SMB header. If the return code is zero, this
105 function must have filled in request_buf pointer */
106 static int
107 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108 void **request_buf)
110 int rc = 0;
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
121 (smb_command != SMB_COM_OPEN_ANDX) &&
122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
123 cFYI(1, ("can not send cmd %d while umounting",
124 smb_command));
125 return -ENODEV;
128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
129 (tcon->ses->server)) {
130 struct nls_table *nls_codepage;
131 /* Give Demultiplex thread up to 10 seconds to
132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
134 while (tcon->ses->server->tcpStatus ==
135 CifsNeedReconnect) {
136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
137 (tcon->ses->server->tcpStatus ==
138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
141 /* on "soft" mounts we wait once */
142 if (!tcon->retry ||
143 (tcon->ses->status == CifsExiting)) {
144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
146 return -EHOSTDOWN;
147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
150 } else /* TCP session is reestablished now */
151 break;
154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
158 if (tcon->ses->need_reconnect)
159 rc = cifs_setup_session(0, tcon->ses,
160 nls_codepage);
161 if (!rc && (tcon->need_reconnect)) {
162 mark_open_files_invalid(tcon);
163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
164 tcon, nls_codepage);
165 up(&tcon->ses->sesSem);
166 /* BB FIXME add code to check if wsize needs
167 update due to negotiated smb buffer size
168 shrinking */
169 if (rc == 0) {
170 atomic_inc(&tconInfoReconnectCount);
171 /* tell server Unix caps we support */
172 if (tcon->ses->capabilities & CAP_UNIX)
173 reset_cifs_unix_caps(
174 0 /* no xid */,
175 tcon,
176 NULL /* we do not know sb */,
177 NULL /* no vol info */);
180 cFYI(1, ("reconnect tcon rc = %d", rc));
181 /* Removed call to reopen open files here.
182 It is safer (and faster) to reopen files
183 one at a time as needed in read and write */
185 /* Check if handle based operation so we
186 know whether we can continue or not without
187 returning to caller to reset file handle */
188 switch (smb_command) {
189 case SMB_COM_READ_ANDX:
190 case SMB_COM_WRITE_ANDX:
191 case SMB_COM_CLOSE:
192 case SMB_COM_FIND_CLOSE2:
193 case SMB_COM_LOCKING_ANDX: {
194 unload_nls(nls_codepage);
195 return -EAGAIN;
198 } else {
199 up(&tcon->ses->sesSem);
201 unload_nls(nls_codepage);
203 } else {
204 return -EIO;
207 if (rc)
208 return rc;
210 *request_buf = cifs_small_buf_get();
211 if (*request_buf == NULL) {
212 /* BB should we add a retry in here if not a writepage? */
213 return -ENOMEM;
216 header_assemble((struct smb_hdr *) *request_buf, smb_command,
217 tcon, wct);
219 if (tcon != NULL)
220 cifs_stats_inc(&tcon->num_smbs_sent);
222 return rc;
226 small_smb_init_no_tc(const int smb_command, const int wct,
227 struct cifsSesInfo *ses, void **request_buf)
229 int rc;
230 struct smb_hdr *buffer;
232 rc = small_smb_init(smb_command, wct, NULL, request_buf);
233 if (rc)
234 return rc;
236 buffer = (struct smb_hdr *)*request_buf;
237 buffer->Mid = GetNextMid(ses->server);
238 if (ses->capabilities & CAP_UNICODE)
239 buffer->Flags2 |= SMBFLG2_UNICODE;
240 if (ses->capabilities & CAP_STATUS32)
241 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
243 /* uid, tid can stay at zero as set in header assemble */
245 /* BB add support for turning on the signing when
246 this function is used after 1st of session setup requests */
248 return rc;
251 /* If the return code is zero, this function must fill in request_buf pointer */
252 static int
253 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
254 void **request_buf /* returned */ ,
255 void **response_buf /* returned */ )
257 int rc = 0;
259 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
260 check for tcp and smb session status done differently
261 for those three - in the calling routine */
262 if (tcon) {
263 if (tcon->tidStatus == CifsExiting) {
264 /* only tree disconnect, open, and write,
265 (and ulogoff which does not have tcon)
266 are allowed as we start force umount */
267 if ((smb_command != SMB_COM_WRITE_ANDX) &&
268 (smb_command != SMB_COM_OPEN_ANDX) &&
269 (smb_command != SMB_COM_TREE_DISCONNECT)) {
270 cFYI(1, ("can not send cmd %d while umounting",
271 smb_command));
272 return -ENODEV;
276 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
277 (tcon->ses->server)) {
278 struct nls_table *nls_codepage;
279 /* Give Demultiplex thread up to 10 seconds to
280 reconnect, should be greater than cifs socket
281 timeout which is 7 seconds */
282 while (tcon->ses->server->tcpStatus ==
283 CifsNeedReconnect) {
284 wait_event_interruptible_timeout(tcon->ses->server->response_q,
285 (tcon->ses->server->tcpStatus ==
286 CifsGood), 10 * HZ);
287 if (tcon->ses->server->tcpStatus ==
288 CifsNeedReconnect) {
289 /* on "soft" mounts we wait once */
290 if (!tcon->retry ||
291 (tcon->ses->status == CifsExiting)) {
292 cFYI(1, ("gave up waiting on "
293 "reconnect in smb_init"));
294 return -EHOSTDOWN;
295 } /* else "hard" mount - keep retrying
296 until process is killed or server
297 comes on-line */
298 } else /* TCP session is reestablished now */
299 break;
301 nls_codepage = load_nls_default();
302 /* need to prevent multiple threads trying to
303 simultaneously reconnect the same SMB session */
304 down(&tcon->ses->sesSem);
305 if (tcon->ses->need_reconnect)
306 rc = cifs_setup_session(0, tcon->ses,
307 nls_codepage);
308 if (!rc && (tcon->need_reconnect)) {
309 mark_open_files_invalid(tcon);
310 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
311 tcon, nls_codepage);
312 up(&tcon->ses->sesSem);
313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
316 if (rc == 0) {
317 atomic_inc(&tconInfoReconnectCount);
318 /* tell server Unix caps we support */
319 if (tcon->ses->capabilities & CAP_UNIX)
320 reset_cifs_unix_caps(
321 0 /* no xid */,
322 tcon,
323 NULL /* do not know sb */,
324 NULL /* no vol info */);
327 cFYI(1, ("reconnect tcon rc = %d", rc));
328 /* Removed call to reopen open files here.
329 It is safer (and faster) to reopen files
330 one at a time as needed in read and write */
332 /* Check if handle based operation so we
333 know whether we can continue or not without
334 returning to caller to reset file handle */
335 switch (smb_command) {
336 case SMB_COM_READ_ANDX:
337 case SMB_COM_WRITE_ANDX:
338 case SMB_COM_CLOSE:
339 case SMB_COM_FIND_CLOSE2:
340 case SMB_COM_LOCKING_ANDX: {
341 unload_nls(nls_codepage);
342 return -EAGAIN;
345 } else {
346 up(&tcon->ses->sesSem);
348 unload_nls(nls_codepage);
350 } else {
351 return -EIO;
354 if (rc)
355 return rc;
357 *request_buf = cifs_buf_get();
358 if (*request_buf == NULL) {
359 /* BB should we add a retry in here if not a writepage? */
360 return -ENOMEM;
362 /* Although the original thought was we needed the response buf for */
363 /* potential retries of smb operations it turns out we can determine */
364 /* from the mid flags when the request buffer can be resent without */
365 /* having to use a second distinct buffer for the response */
366 if (response_buf)
367 *response_buf = *request_buf;
369 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
370 wct);
372 if (tcon != NULL)
373 cifs_stats_inc(&tcon->num_smbs_sent);
375 return rc;
378 static int validate_t2(struct smb_t2_rsp *pSMB)
380 int rc = -EINVAL;
381 int total_size;
382 char *pBCC;
384 /* check for plausible wct, bcc and t2 data and parm sizes */
385 /* check for parm and data offset going beyond end of smb */
386 if (pSMB->hdr.WordCount >= 10) {
387 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
388 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
389 /* check that bcc is at least as big as parms + data */
390 /* check that bcc is less than negotiated smb buffer */
391 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
392 if (total_size < 512) {
393 total_size +=
394 le16_to_cpu(pSMB->t2_rsp.DataCount);
395 /* BCC le converted in SendReceive */
396 pBCC = (pSMB->hdr.WordCount * 2) +
397 sizeof(struct smb_hdr) +
398 (char *)pSMB;
399 if ((total_size <= (*(u16 *)pBCC)) &&
400 (total_size <
401 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
402 return 0;
407 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
408 sizeof(struct smb_t2_rsp) + 16);
409 return rc;
412 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
414 NEGOTIATE_REQ *pSMB;
415 NEGOTIATE_RSP *pSMBr;
416 int rc = 0;
417 int bytes_returned;
418 int i;
419 struct TCP_Server_Info *server;
420 u16 count;
421 unsigned int secFlags;
422 u16 dialect;
424 if (ses->server)
425 server = ses->server;
426 else {
427 rc = -EIO;
428 return rc;
430 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
431 (void **) &pSMB, (void **) &pSMBr);
432 if (rc)
433 return rc;
435 /* if any of auth flags (ie not sign or seal) are overriden use them */
436 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
437 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
438 else /* if override flags set only sign/seal OR them with global auth */
439 secFlags = extended_security | ses->overrideSecFlg;
441 cFYI(1, ("secFlags 0x%x", secFlags));
443 pSMB->hdr.Mid = GetNextMid(server);
444 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
446 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
447 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
448 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
449 cFYI(1, ("Kerberos only mechanism, enable extended security"));
450 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
452 #ifdef CONFIG_CIFS_EXPERIMENTAL
453 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
454 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
455 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
456 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
457 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
459 #endif
461 count = 0;
462 for (i = 0; i < CIFS_NUM_PROT; i++) {
463 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
464 count += strlen(protocols[i].name) + 1;
465 /* null at end of source and target buffers anyway */
467 pSMB->hdr.smb_buf_length += count;
468 pSMB->ByteCount = cpu_to_le16(count);
470 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
472 if (rc != 0)
473 goto neg_err_exit;
475 dialect = le16_to_cpu(pSMBr->DialectIndex);
476 cFYI(1, ("Dialect: %d", dialect));
477 /* Check wct = 1 error case */
478 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
479 /* core returns wct = 1, but we do not ask for core - otherwise
480 small wct just comes when dialect index is -1 indicating we
481 could not negotiate a common dialect */
482 rc = -EOPNOTSUPP;
483 goto neg_err_exit;
484 #ifdef CONFIG_CIFS_WEAK_PW_HASH
485 } else if ((pSMBr->hdr.WordCount == 13)
486 && ((dialect == LANMAN_PROT)
487 || (dialect == LANMAN2_PROT))) {
488 __s16 tmp;
489 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
491 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
492 (secFlags & CIFSSEC_MAY_PLNTXT))
493 server->secType = LANMAN;
494 else {
495 cERROR(1, ("mount failed weak security disabled"
496 " in /proc/fs/cifs/SecurityFlags"));
497 rc = -EOPNOTSUPP;
498 goto neg_err_exit;
500 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
501 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
502 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
503 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
504 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
505 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
506 /* even though we do not use raw we might as well set this
507 accurately, in case we ever find a need for it */
508 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
509 server->max_rw = 0xFF00;
510 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
511 } else {
512 server->max_rw = 0;/* do not need to use raw anyway */
513 server->capabilities = CAP_MPX_MODE;
515 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
516 if (tmp == -1) {
517 /* OS/2 often does not set timezone therefore
518 * we must use server time to calc time zone.
519 * Could deviate slightly from the right zone.
520 * Smallest defined timezone difference is 15 minutes
521 * (i.e. Nepal). Rounding up/down is done to match
522 * this requirement.
524 int val, seconds, remain, result;
525 struct timespec ts, utc;
526 utc = CURRENT_TIME;
527 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
528 rsp->SrvTime.Time, 0);
529 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
530 (int)ts.tv_sec, (int)utc.tv_sec,
531 (int)(utc.tv_sec - ts.tv_sec)));
532 val = (int)(utc.tv_sec - ts.tv_sec);
533 seconds = abs(val);
534 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
535 remain = seconds % MIN_TZ_ADJ;
536 if (remain >= (MIN_TZ_ADJ / 2))
537 result += MIN_TZ_ADJ;
538 if (val < 0)
539 result = -result;
540 server->timeAdj = result;
541 } else {
542 server->timeAdj = (int)tmp;
543 server->timeAdj *= 60; /* also in seconds */
545 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
548 /* BB get server time for time conversions and add
549 code to use it and timezone since this is not UTC */
551 if (rsp->EncryptionKeyLength ==
552 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
553 memcpy(server->cryptKey, rsp->EncryptionKey,
554 CIFS_CRYPTO_KEY_SIZE);
555 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
556 rc = -EIO; /* need cryptkey unless plain text */
557 goto neg_err_exit;
560 cFYI(1, ("LANMAN negotiated"));
561 /* we will not end up setting signing flags - as no signing
562 was in LANMAN and server did not return the flags on */
563 goto signing_check;
564 #else /* weak security disabled */
565 } else if (pSMBr->hdr.WordCount == 13) {
566 cERROR(1, ("mount failed, cifs module not built "
567 "with CIFS_WEAK_PW_HASH support"));
568 rc = -EOPNOTSUPP;
569 #endif /* WEAK_PW_HASH */
570 goto neg_err_exit;
571 } else if (pSMBr->hdr.WordCount != 17) {
572 /* unknown wct */
573 rc = -EOPNOTSUPP;
574 goto neg_err_exit;
576 /* else wct == 17 NTLM */
577 server->secMode = pSMBr->SecurityMode;
578 if ((server->secMode & SECMODE_USER) == 0)
579 cFYI(1, ("share mode security"));
581 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
582 #ifdef CONFIG_CIFS_WEAK_PW_HASH
583 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
584 #endif /* CIFS_WEAK_PW_HASH */
585 cERROR(1, ("Server requests plain text password"
586 " but client support disabled"));
588 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
589 server->secType = NTLMv2;
590 else if (secFlags & CIFSSEC_MAY_NTLM)
591 server->secType = NTLM;
592 else if (secFlags & CIFSSEC_MAY_NTLMV2)
593 server->secType = NTLMv2;
594 else if (secFlags & CIFSSEC_MAY_KRB5)
595 server->secType = Kerberos;
596 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
597 server->secType = RawNTLMSSP;
598 else if (secFlags & CIFSSEC_MAY_LANMAN)
599 server->secType = LANMAN;
600 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
601 else if (secFlags & CIFSSEC_MAY_PLNTXT)
602 server->secType = ??
603 #endif */
604 else {
605 rc = -EOPNOTSUPP;
606 cERROR(1, ("Invalid security type"));
607 goto neg_err_exit;
609 /* else ... any others ...? */
611 /* one byte, so no need to convert this or EncryptionKeyLen from
612 little endian */
613 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
614 /* probably no need to store and check maxvcs */
615 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
616 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
617 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
618 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
619 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
620 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
621 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
622 server->timeAdj *= 60;
623 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
624 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
625 CIFS_CRYPTO_KEY_SIZE);
626 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
627 && (pSMBr->EncryptionKeyLength == 0)) {
628 /* decode security blob */
629 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
630 rc = -EIO; /* no crypt key only if plain text pwd */
631 goto neg_err_exit;
634 /* BB might be helpful to save off the domain of server here */
636 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
637 (server->capabilities & CAP_EXTENDED_SECURITY)) {
638 count = pSMBr->ByteCount;
639 if (count < 16) {
640 rc = -EIO;
641 goto neg_err_exit;
643 read_lock(&cifs_tcp_ses_lock);
644 if (server->srv_count > 1) {
645 read_unlock(&cifs_tcp_ses_lock);
646 if (memcmp(server->server_GUID,
647 pSMBr->u.extended_response.
648 GUID, 16) != 0) {
649 cFYI(1, ("server UID changed"));
650 memcpy(server->server_GUID,
651 pSMBr->u.extended_response.GUID,
652 16);
654 } else {
655 read_unlock(&cifs_tcp_ses_lock);
656 memcpy(server->server_GUID,
657 pSMBr->u.extended_response.GUID, 16);
660 if (count == 16) {
661 server->secType = RawNTLMSSP;
662 } else {
663 rc = decode_negTokenInit(pSMBr->u.extended_response.
664 SecurityBlob,
665 count - 16,
666 &server->secType);
667 if (rc == 1)
668 rc = 0;
669 else
670 rc = -EINVAL;
672 } else
673 server->capabilities &= ~CAP_EXTENDED_SECURITY;
675 #ifdef CONFIG_CIFS_WEAK_PW_HASH
676 signing_check:
677 #endif
678 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
679 /* MUST_SIGN already includes the MAY_SIGN FLAG
680 so if this is zero it means that signing is disabled */
681 cFYI(1, ("Signing disabled"));
682 if (server->secMode & SECMODE_SIGN_REQUIRED) {
683 cERROR(1, ("Server requires "
684 "packet signing to be enabled in "
685 "/proc/fs/cifs/SecurityFlags."));
686 rc = -EOPNOTSUPP;
688 server->secMode &=
689 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
690 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
691 /* signing required */
692 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
693 if ((server->secMode &
694 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
695 cERROR(1,
696 ("signing required but server lacks support"));
697 rc = -EOPNOTSUPP;
698 } else
699 server->secMode |= SECMODE_SIGN_REQUIRED;
700 } else {
701 /* signing optional ie CIFSSEC_MAY_SIGN */
702 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
703 server->secMode &=
704 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
707 neg_err_exit:
708 cifs_buf_release(pSMB);
710 cFYI(1, ("negprot rc %d", rc));
711 return rc;
715 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
717 struct smb_hdr *smb_buffer;
718 int rc = 0;
720 cFYI(1, ("In tree disconnect"));
722 /* BB: do we need to check this? These should never be NULL. */
723 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
724 return -EIO;
727 * No need to return error on this operation if tid invalidated and
728 * closed on server already e.g. due to tcp session crashing. Also,
729 * the tcon is no longer on the list, so no need to take lock before
730 * checking this.
732 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
733 return 0;
735 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
736 (void **)&smb_buffer);
737 if (rc)
738 return rc;
740 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
741 if (rc)
742 cFYI(1, ("Tree disconnect failed %d", rc));
744 /* No need to return error on this operation if tid invalidated and
745 closed on server already e.g. due to tcp session crashing */
746 if (rc == -EAGAIN)
747 rc = 0;
749 return rc;
753 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
755 LOGOFF_ANDX_REQ *pSMB;
756 int rc = 0;
758 cFYI(1, ("In SMBLogoff for session disconnect"));
761 * BB: do we need to check validity of ses and server? They should
762 * always be valid since we have an active reference. If not, that
763 * should probably be a BUG()
765 if (!ses || !ses->server)
766 return -EIO;
768 down(&ses->sesSem);
769 if (ses->need_reconnect)
770 goto session_already_dead; /* no need to send SMBlogoff if uid
771 already closed due to reconnect */
772 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
773 if (rc) {
774 up(&ses->sesSem);
775 return rc;
778 pSMB->hdr.Mid = GetNextMid(ses->server);
780 if (ses->server->secMode &
781 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
782 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
784 pSMB->hdr.Uid = ses->Suid;
786 pSMB->AndXCommand = 0xFF;
787 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
788 session_already_dead:
789 up(&ses->sesSem);
791 /* if session dead then we do not need to do ulogoff,
792 since server closed smb session, no sense reporting
793 error */
794 if (rc == -EAGAIN)
795 rc = 0;
796 return rc;
800 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
801 __u16 type, const struct nls_table *nls_codepage, int remap)
803 TRANSACTION2_SPI_REQ *pSMB = NULL;
804 TRANSACTION2_SPI_RSP *pSMBr = NULL;
805 struct unlink_psx_rq *pRqD;
806 int name_len;
807 int rc = 0;
808 int bytes_returned = 0;
809 __u16 params, param_offset, offset, byte_count;
811 cFYI(1, ("In POSIX delete"));
812 PsxDelete:
813 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
814 (void **) &pSMBr);
815 if (rc)
816 return rc;
818 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
819 name_len =
820 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
821 PATH_MAX, nls_codepage, remap);
822 name_len++; /* trailing null */
823 name_len *= 2;
824 } else { /* BB add path length overrun check */
825 name_len = strnlen(fileName, PATH_MAX);
826 name_len++; /* trailing null */
827 strncpy(pSMB->FileName, fileName, name_len);
830 params = 6 + name_len;
831 pSMB->MaxParameterCount = cpu_to_le16(2);
832 pSMB->MaxDataCount = 0; /* BB double check this with jra */
833 pSMB->MaxSetupCount = 0;
834 pSMB->Reserved = 0;
835 pSMB->Flags = 0;
836 pSMB->Timeout = 0;
837 pSMB->Reserved2 = 0;
838 param_offset = offsetof(struct smb_com_transaction2_spi_req,
839 InformationLevel) - 4;
840 offset = param_offset + params;
842 /* Setup pointer to Request Data (inode type) */
843 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
844 pRqD->type = cpu_to_le16(type);
845 pSMB->ParameterOffset = cpu_to_le16(param_offset);
846 pSMB->DataOffset = cpu_to_le16(offset);
847 pSMB->SetupCount = 1;
848 pSMB->Reserved3 = 0;
849 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
850 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
852 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
853 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
854 pSMB->ParameterCount = cpu_to_le16(params);
855 pSMB->TotalParameterCount = pSMB->ParameterCount;
856 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
857 pSMB->Reserved4 = 0;
858 pSMB->hdr.smb_buf_length += byte_count;
859 pSMB->ByteCount = cpu_to_le16(byte_count);
860 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
861 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
862 if (rc)
863 cFYI(1, ("Posix delete returned %d", rc));
864 cifs_buf_release(pSMB);
866 cifs_stats_inc(&tcon->num_deletes);
868 if (rc == -EAGAIN)
869 goto PsxDelete;
871 return rc;
875 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
876 const struct nls_table *nls_codepage, int remap)
878 DELETE_FILE_REQ *pSMB = NULL;
879 DELETE_FILE_RSP *pSMBr = NULL;
880 int rc = 0;
881 int bytes_returned;
882 int name_len;
884 DelFileRetry:
885 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
886 (void **) &pSMBr);
887 if (rc)
888 return rc;
890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
891 name_len =
892 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
893 PATH_MAX, nls_codepage, remap);
894 name_len++; /* trailing null */
895 name_len *= 2;
896 } else { /* BB improve check for buffer overruns BB */
897 name_len = strnlen(fileName, PATH_MAX);
898 name_len++; /* trailing null */
899 strncpy(pSMB->fileName, fileName, name_len);
901 pSMB->SearchAttributes =
902 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
903 pSMB->BufferFormat = 0x04;
904 pSMB->hdr.smb_buf_length += name_len + 1;
905 pSMB->ByteCount = cpu_to_le16(name_len + 1);
906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
908 cifs_stats_inc(&tcon->num_deletes);
909 if (rc)
910 cFYI(1, ("Error in RMFile = %d", rc));
912 cifs_buf_release(pSMB);
913 if (rc == -EAGAIN)
914 goto DelFileRetry;
916 return rc;
920 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
921 const struct nls_table *nls_codepage, int remap)
923 DELETE_DIRECTORY_REQ *pSMB = NULL;
924 DELETE_DIRECTORY_RSP *pSMBr = NULL;
925 int rc = 0;
926 int bytes_returned;
927 int name_len;
929 cFYI(1, ("In CIFSSMBRmDir"));
930 RmDirRetry:
931 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
932 (void **) &pSMBr);
933 if (rc)
934 return rc;
936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
937 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
938 PATH_MAX, nls_codepage, remap);
939 name_len++; /* trailing null */
940 name_len *= 2;
941 } else { /* BB improve check for buffer overruns BB */
942 name_len = strnlen(dirName, PATH_MAX);
943 name_len++; /* trailing null */
944 strncpy(pSMB->DirName, dirName, name_len);
947 pSMB->BufferFormat = 0x04;
948 pSMB->hdr.smb_buf_length += name_len + 1;
949 pSMB->ByteCount = cpu_to_le16(name_len + 1);
950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
952 cifs_stats_inc(&tcon->num_rmdirs);
953 if (rc)
954 cFYI(1, ("Error in RMDir = %d", rc));
956 cifs_buf_release(pSMB);
957 if (rc == -EAGAIN)
958 goto RmDirRetry;
959 return rc;
963 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
964 const char *name, const struct nls_table *nls_codepage, int remap)
966 int rc = 0;
967 CREATE_DIRECTORY_REQ *pSMB = NULL;
968 CREATE_DIRECTORY_RSP *pSMBr = NULL;
969 int bytes_returned;
970 int name_len;
972 cFYI(1, ("In CIFSSMBMkDir"));
973 MkDirRetry:
974 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
975 (void **) &pSMBr);
976 if (rc)
977 return rc;
979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
980 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
981 PATH_MAX, nls_codepage, remap);
982 name_len++; /* trailing null */
983 name_len *= 2;
984 } else { /* BB improve check for buffer overruns BB */
985 name_len = strnlen(name, PATH_MAX);
986 name_len++; /* trailing null */
987 strncpy(pSMB->DirName, name, name_len);
990 pSMB->BufferFormat = 0x04;
991 pSMB->hdr.smb_buf_length += name_len + 1;
992 pSMB->ByteCount = cpu_to_le16(name_len + 1);
993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
995 cifs_stats_inc(&tcon->num_mkdirs);
996 if (rc)
997 cFYI(1, ("Error in Mkdir = %d", rc));
999 cifs_buf_release(pSMB);
1000 if (rc == -EAGAIN)
1001 goto MkDirRetry;
1002 return rc;
1006 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1007 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1008 __u32 *pOplock, const char *name,
1009 const struct nls_table *nls_codepage, int remap)
1011 TRANSACTION2_SPI_REQ *pSMB = NULL;
1012 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1013 int name_len;
1014 int rc = 0;
1015 int bytes_returned = 0;
1016 __u16 params, param_offset, offset, byte_count, count;
1017 OPEN_PSX_REQ *pdata;
1018 OPEN_PSX_RSP *psx_rsp;
1020 cFYI(1, ("In POSIX Create"));
1021 PsxCreat:
1022 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1023 (void **) &pSMBr);
1024 if (rc)
1025 return rc;
1027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1028 name_len =
1029 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1030 PATH_MAX, nls_codepage, remap);
1031 name_len++; /* trailing null */
1032 name_len *= 2;
1033 } else { /* BB improve the check for buffer overruns BB */
1034 name_len = strnlen(name, PATH_MAX);
1035 name_len++; /* trailing null */
1036 strncpy(pSMB->FileName, name, name_len);
1039 params = 6 + name_len;
1040 count = sizeof(OPEN_PSX_REQ);
1041 pSMB->MaxParameterCount = cpu_to_le16(2);
1042 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1043 pSMB->MaxSetupCount = 0;
1044 pSMB->Reserved = 0;
1045 pSMB->Flags = 0;
1046 pSMB->Timeout = 0;
1047 pSMB->Reserved2 = 0;
1048 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1049 InformationLevel) - 4;
1050 offset = param_offset + params;
1051 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1052 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1053 pdata->Permissions = cpu_to_le64(mode);
1054 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1055 pdata->OpenFlags = cpu_to_le32(*pOplock);
1056 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1057 pSMB->DataOffset = cpu_to_le16(offset);
1058 pSMB->SetupCount = 1;
1059 pSMB->Reserved3 = 0;
1060 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1061 byte_count = 3 /* pad */ + params + count;
1063 pSMB->DataCount = cpu_to_le16(count);
1064 pSMB->ParameterCount = cpu_to_le16(params);
1065 pSMB->TotalDataCount = pSMB->DataCount;
1066 pSMB->TotalParameterCount = pSMB->ParameterCount;
1067 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1068 pSMB->Reserved4 = 0;
1069 pSMB->hdr.smb_buf_length += byte_count;
1070 pSMB->ByteCount = cpu_to_le16(byte_count);
1071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1073 if (rc) {
1074 cFYI(1, ("Posix create returned %d", rc));
1075 goto psx_create_err;
1078 cFYI(1, ("copying inode info"));
1079 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1081 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1082 rc = -EIO; /* bad smb */
1083 goto psx_create_err;
1086 /* copy return information to pRetData */
1087 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1088 + le16_to_cpu(pSMBr->t2.DataOffset));
1090 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1091 if (netfid)
1092 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1093 /* Let caller know file was created so we can set the mode. */
1094 /* Do we care about the CreateAction in any other cases? */
1095 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1096 *pOplock |= CIFS_CREATE_ACTION;
1097 /* check to make sure response data is there */
1098 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1099 pRetData->Type = cpu_to_le32(-1); /* unknown */
1100 cFYI(DBG2, ("unknown type"));
1101 } else {
1102 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1103 + sizeof(FILE_UNIX_BASIC_INFO)) {
1104 cERROR(1, ("Open response data too small"));
1105 pRetData->Type = cpu_to_le32(-1);
1106 goto psx_create_err;
1108 memcpy((char *) pRetData,
1109 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1110 sizeof(FILE_UNIX_BASIC_INFO));
1113 psx_create_err:
1114 cifs_buf_release(pSMB);
1116 cifs_stats_inc(&tcon->num_mkdirs);
1118 if (rc == -EAGAIN)
1119 goto PsxCreat;
1121 return rc;
1124 static __u16 convert_disposition(int disposition)
1126 __u16 ofun = 0;
1128 switch (disposition) {
1129 case FILE_SUPERSEDE:
1130 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1131 break;
1132 case FILE_OPEN:
1133 ofun = SMBOPEN_OAPPEND;
1134 break;
1135 case FILE_CREATE:
1136 ofun = SMBOPEN_OCREATE;
1137 break;
1138 case FILE_OPEN_IF:
1139 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_OVERWRITE:
1142 ofun = SMBOPEN_OTRUNC;
1143 break;
1144 case FILE_OVERWRITE_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 default:
1148 cFYI(1, ("unknown disposition %d", disposition));
1149 ofun = SMBOPEN_OAPPEND; /* regular open */
1151 return ofun;
1154 static int
1155 access_flags_to_smbopen_mode(const int access_flags)
1157 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1159 if (masked_flags == GENERIC_READ)
1160 return SMBOPEN_READ;
1161 else if (masked_flags == GENERIC_WRITE)
1162 return SMBOPEN_WRITE;
1164 /* just go for read/write */
1165 return SMBOPEN_READWRITE;
1169 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1170 const char *fileName, const int openDisposition,
1171 const int access_flags, const int create_options, __u16 *netfid,
1172 int *pOplock, FILE_ALL_INFO *pfile_info,
1173 const struct nls_table *nls_codepage, int remap)
1175 int rc = -EACCES;
1176 OPENX_REQ *pSMB = NULL;
1177 OPENX_RSP *pSMBr = NULL;
1178 int bytes_returned;
1179 int name_len;
1180 __u16 count;
1182 OldOpenRetry:
1183 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1184 (void **) &pSMBr);
1185 if (rc)
1186 return rc;
1188 pSMB->AndXCommand = 0xFF; /* none */
1190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1191 count = 1; /* account for one byte pad to word boundary */
1192 name_len =
1193 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1194 fileName, PATH_MAX, nls_codepage, remap);
1195 name_len++; /* trailing null */
1196 name_len *= 2;
1197 } else { /* BB improve check for buffer overruns BB */
1198 count = 0; /* no pad */
1199 name_len = strnlen(fileName, PATH_MAX);
1200 name_len++; /* trailing null */
1201 strncpy(pSMB->fileName, fileName, name_len);
1203 if (*pOplock & REQ_OPLOCK)
1204 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1205 else if (*pOplock & REQ_BATCHOPLOCK)
1206 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1208 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1209 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1210 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1211 /* set file as system file if special file such
1212 as fifo and server expecting SFU style and
1213 no Unix extensions */
1215 if (create_options & CREATE_OPTION_SPECIAL)
1216 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1217 else /* BB FIXME BB */
1218 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1220 if (create_options & CREATE_OPTION_READONLY)
1221 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1223 /* BB FIXME BB */
1224 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1225 CREATE_OPTIONS_MASK); */
1226 /* BB FIXME END BB */
1228 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1229 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1230 count += name_len;
1231 pSMB->hdr.smb_buf_length += count;
1233 pSMB->ByteCount = cpu_to_le16(count);
1234 /* long_op set to 1 to allow for oplock break timeouts */
1235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1236 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1237 cifs_stats_inc(&tcon->num_opens);
1238 if (rc) {
1239 cFYI(1, ("Error in Open = %d", rc));
1240 } else {
1241 /* BB verify if wct == 15 */
1243 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1245 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1246 /* Let caller know file was created so we can set the mode. */
1247 /* Do we care about the CreateAction in any other cases? */
1248 /* BB FIXME BB */
1249 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1250 *pOplock |= CIFS_CREATE_ACTION; */
1251 /* BB FIXME END */
1253 if (pfile_info) {
1254 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1255 pfile_info->LastAccessTime = 0; /* BB fixme */
1256 pfile_info->LastWriteTime = 0; /* BB fixme */
1257 pfile_info->ChangeTime = 0; /* BB fixme */
1258 pfile_info->Attributes =
1259 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1260 /* the file_info buf is endian converted by caller */
1261 pfile_info->AllocationSize =
1262 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1263 pfile_info->EndOfFile = pfile_info->AllocationSize;
1264 pfile_info->NumberOfLinks = cpu_to_le32(1);
1265 pfile_info->DeletePending = 0;
1269 cifs_buf_release(pSMB);
1270 if (rc == -EAGAIN)
1271 goto OldOpenRetry;
1272 return rc;
1276 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1277 const char *fileName, const int openDisposition,
1278 const int access_flags, const int create_options, __u16 *netfid,
1279 int *pOplock, FILE_ALL_INFO *pfile_info,
1280 const struct nls_table *nls_codepage, int remap)
1282 int rc = -EACCES;
1283 OPEN_REQ *pSMB = NULL;
1284 OPEN_RSP *pSMBr = NULL;
1285 int bytes_returned;
1286 int name_len;
1287 __u16 count;
1289 openRetry:
1290 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1291 (void **) &pSMBr);
1292 if (rc)
1293 return rc;
1295 pSMB->AndXCommand = 0xFF; /* none */
1297 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1298 count = 1; /* account for one byte pad to word boundary */
1299 name_len =
1300 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1301 fileName, PATH_MAX, nls_codepage, remap);
1302 name_len++; /* trailing null */
1303 name_len *= 2;
1304 pSMB->NameLength = cpu_to_le16(name_len);
1305 } else { /* BB improve check for buffer overruns BB */
1306 count = 0; /* no pad */
1307 name_len = strnlen(fileName, PATH_MAX);
1308 name_len++; /* trailing null */
1309 pSMB->NameLength = cpu_to_le16(name_len);
1310 strncpy(pSMB->fileName, fileName, name_len);
1312 if (*pOplock & REQ_OPLOCK)
1313 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1314 else if (*pOplock & REQ_BATCHOPLOCK)
1315 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1316 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1317 pSMB->AllocationSize = 0;
1318 /* set file as system file if special file such
1319 as fifo and server expecting SFU style and
1320 no Unix extensions */
1321 if (create_options & CREATE_OPTION_SPECIAL)
1322 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1323 else
1324 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1326 /* XP does not handle ATTR_POSIX_SEMANTICS */
1327 /* but it helps speed up case sensitive checks for other
1328 servers such as Samba */
1329 if (tcon->ses->capabilities & CAP_UNIX)
1330 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1332 if (create_options & CREATE_OPTION_READONLY)
1333 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1335 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1336 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1337 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1338 /* BB Expirement with various impersonation levels and verify */
1339 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1340 pSMB->SecurityFlags =
1341 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1343 count += name_len;
1344 pSMB->hdr.smb_buf_length += count;
1346 pSMB->ByteCount = cpu_to_le16(count);
1347 /* long_op set to 1 to allow for oplock break timeouts */
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1349 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1350 cifs_stats_inc(&tcon->num_opens);
1351 if (rc) {
1352 cFYI(1, ("Error in Open = %d", rc));
1353 } else {
1354 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1355 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1356 /* Let caller know file was created so we can set the mode. */
1357 /* Do we care about the CreateAction in any other cases? */
1358 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1359 *pOplock |= CIFS_CREATE_ACTION;
1360 if (pfile_info) {
1361 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1362 36 /* CreationTime to Attributes */);
1363 /* the file_info buf is endian converted by caller */
1364 pfile_info->AllocationSize = pSMBr->AllocationSize;
1365 pfile_info->EndOfFile = pSMBr->EndOfFile;
1366 pfile_info->NumberOfLinks = cpu_to_le32(1);
1367 pfile_info->DeletePending = 0;
1371 cifs_buf_release(pSMB);
1372 if (rc == -EAGAIN)
1373 goto openRetry;
1374 return rc;
1378 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1379 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1380 char **buf, int *pbuf_type)
1382 int rc = -EACCES;
1383 READ_REQ *pSMB = NULL;
1384 READ_RSP *pSMBr = NULL;
1385 char *pReadData = NULL;
1386 int wct;
1387 int resp_buf_type = 0;
1388 struct kvec iov[1];
1390 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1391 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1392 wct = 12;
1393 else {
1394 wct = 10; /* old style read */
1395 if ((lseek >> 32) > 0) {
1396 /* can not handle this big offset for old */
1397 return -EIO;
1401 *nbytes = 0;
1402 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1403 if (rc)
1404 return rc;
1406 /* tcon and ses pointer are checked in smb_init */
1407 if (tcon->ses->server == NULL)
1408 return -ECONNABORTED;
1410 pSMB->AndXCommand = 0xFF; /* none */
1411 pSMB->Fid = netfid;
1412 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1413 if (wct == 12)
1414 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1416 pSMB->Remaining = 0;
1417 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1418 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1419 if (wct == 12)
1420 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1421 else {
1422 /* old style read */
1423 struct smb_com_readx_req *pSMBW =
1424 (struct smb_com_readx_req *)pSMB;
1425 pSMBW->ByteCount = 0;
1428 iov[0].iov_base = (char *)pSMB;
1429 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1430 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1431 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1432 cifs_stats_inc(&tcon->num_reads);
1433 pSMBr = (READ_RSP *)iov[0].iov_base;
1434 if (rc) {
1435 cERROR(1, ("Send error in read = %d", rc));
1436 } else {
1437 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1438 data_length = data_length << 16;
1439 data_length += le16_to_cpu(pSMBr->DataLength);
1440 *nbytes = data_length;
1442 /*check that DataLength would not go beyond end of SMB */
1443 if ((data_length > CIFSMaxBufSize)
1444 || (data_length > count)) {
1445 cFYI(1, ("bad length %d for count %d",
1446 data_length, count));
1447 rc = -EIO;
1448 *nbytes = 0;
1449 } else {
1450 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1451 le16_to_cpu(pSMBr->DataOffset);
1452 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1453 cERROR(1,("Faulting on read rc = %d",rc));
1454 rc = -EFAULT;
1455 }*/ /* can not use copy_to_user when using page cache*/
1456 if (*buf)
1457 memcpy(*buf, pReadData, data_length);
1461 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1462 if (*buf) {
1463 if (resp_buf_type == CIFS_SMALL_BUFFER)
1464 cifs_small_buf_release(iov[0].iov_base);
1465 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1466 cifs_buf_release(iov[0].iov_base);
1467 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1468 /* return buffer to caller to free */
1469 *buf = iov[0].iov_base;
1470 if (resp_buf_type == CIFS_SMALL_BUFFER)
1471 *pbuf_type = CIFS_SMALL_BUFFER;
1472 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1473 *pbuf_type = CIFS_LARGE_BUFFER;
1474 } /* else no valid buffer on return - leave as null */
1476 /* Note: On -EAGAIN error only caller can retry on handle based calls
1477 since file handle passed in no longer valid */
1478 return rc;
1483 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1484 const int netfid, const unsigned int count,
1485 const __u64 offset, unsigned int *nbytes, const char *buf,
1486 const char __user *ubuf, const int long_op)
1488 int rc = -EACCES;
1489 WRITE_REQ *pSMB = NULL;
1490 WRITE_RSP *pSMBr = NULL;
1491 int bytes_returned, wct;
1492 __u32 bytes_sent;
1493 __u16 byte_count;
1495 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
1496 if (tcon->ses == NULL)
1497 return -ECONNABORTED;
1499 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1500 wct = 14;
1501 else {
1502 wct = 12;
1503 if ((offset >> 32) > 0) {
1504 /* can not handle big offset for old srv */
1505 return -EIO;
1509 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1510 (void **) &pSMBr);
1511 if (rc)
1512 return rc;
1513 /* tcon and ses pointer are checked in smb_init */
1514 if (tcon->ses->server == NULL)
1515 return -ECONNABORTED;
1517 pSMB->AndXCommand = 0xFF; /* none */
1518 pSMB->Fid = netfid;
1519 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1520 if (wct == 14)
1521 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1523 pSMB->Reserved = 0xFFFFFFFF;
1524 pSMB->WriteMode = 0;
1525 pSMB->Remaining = 0;
1527 /* Can increase buffer size if buffer is big enough in some cases ie we
1528 can send more if LARGE_WRITE_X capability returned by the server and if
1529 our buffer is big enough or if we convert to iovecs on socket writes
1530 and eliminate the copy to the CIFS buffer */
1531 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1532 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1533 } else {
1534 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1535 & ~0xFF;
1538 if (bytes_sent > count)
1539 bytes_sent = count;
1540 pSMB->DataOffset =
1541 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1542 if (buf)
1543 memcpy(pSMB->Data, buf, bytes_sent);
1544 else if (ubuf) {
1545 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1546 cifs_buf_release(pSMB);
1547 return -EFAULT;
1549 } else if (count != 0) {
1550 /* No buffer */
1551 cifs_buf_release(pSMB);
1552 return -EINVAL;
1553 } /* else setting file size with write of zero bytes */
1554 if (wct == 14)
1555 byte_count = bytes_sent + 1; /* pad */
1556 else /* wct == 12 */
1557 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1559 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1560 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1561 pSMB->hdr.smb_buf_length += byte_count;
1563 if (wct == 14)
1564 pSMB->ByteCount = cpu_to_le16(byte_count);
1565 else { /* old style write has byte count 4 bytes earlier
1566 so 4 bytes pad */
1567 struct smb_com_writex_req *pSMBW =
1568 (struct smb_com_writex_req *)pSMB;
1569 pSMBW->ByteCount = cpu_to_le16(byte_count);
1572 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1573 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1574 cifs_stats_inc(&tcon->num_writes);
1575 if (rc) {
1576 cFYI(1, ("Send error in write = %d", rc));
1577 *nbytes = 0;
1578 } else {
1579 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1580 *nbytes = (*nbytes) << 16;
1581 *nbytes += le16_to_cpu(pSMBr->Count);
1584 cifs_buf_release(pSMB);
1586 /* Note: On -EAGAIN error only caller can retry on handle based calls
1587 since file handle passed in no longer valid */
1589 return rc;
1593 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1594 const int netfid, const unsigned int count,
1595 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1596 int n_vec, const int long_op)
1598 int rc = -EACCES;
1599 WRITE_REQ *pSMB = NULL;
1600 int wct;
1601 int smb_hdr_len;
1602 int resp_buf_type = 0;
1604 *nbytes = 0;
1606 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1608 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1609 wct = 14;
1610 } else {
1611 wct = 12;
1612 if ((offset >> 32) > 0) {
1613 /* can not handle big offset for old srv */
1614 return -EIO;
1617 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1618 if (rc)
1619 return rc;
1620 /* tcon and ses pointer are checked in smb_init */
1621 if (tcon->ses->server == NULL)
1622 return -ECONNABORTED;
1624 pSMB->AndXCommand = 0xFF; /* none */
1625 pSMB->Fid = netfid;
1626 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1627 if (wct == 14)
1628 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1629 pSMB->Reserved = 0xFFFFFFFF;
1630 pSMB->WriteMode = 0;
1631 pSMB->Remaining = 0;
1633 pSMB->DataOffset =
1634 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1636 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1637 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1638 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1639 if (wct == 14)
1640 pSMB->hdr.smb_buf_length += count+1;
1641 else /* wct == 12 */
1642 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1643 if (wct == 14)
1644 pSMB->ByteCount = cpu_to_le16(count + 1);
1645 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1646 struct smb_com_writex_req *pSMBW =
1647 (struct smb_com_writex_req *)pSMB;
1648 pSMBW->ByteCount = cpu_to_le16(count + 5);
1650 iov[0].iov_base = pSMB;
1651 if (wct == 14)
1652 iov[0].iov_len = smb_hdr_len + 4;
1653 else /* wct == 12 pad bigger by four bytes */
1654 iov[0].iov_len = smb_hdr_len + 8;
1657 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1658 long_op);
1659 cifs_stats_inc(&tcon->num_writes);
1660 if (rc) {
1661 cFYI(1, ("Send error Write2 = %d", rc));
1662 } else if (resp_buf_type == 0) {
1663 /* presumably this can not happen, but best to be safe */
1664 rc = -EIO;
1665 } else {
1666 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1667 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1668 *nbytes = (*nbytes) << 16;
1669 *nbytes += le16_to_cpu(pSMBr->Count);
1672 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1673 if (resp_buf_type == CIFS_SMALL_BUFFER)
1674 cifs_small_buf_release(iov[0].iov_base);
1675 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1676 cifs_buf_release(iov[0].iov_base);
1678 /* Note: On -EAGAIN error only caller can retry on handle based calls
1679 since file handle passed in no longer valid */
1681 return rc;
1686 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1687 const __u16 smb_file_id, const __u64 len,
1688 const __u64 offset, const __u32 numUnlock,
1689 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1691 int rc = 0;
1692 LOCK_REQ *pSMB = NULL;
1693 /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1694 int bytes_returned;
1695 int timeout = 0;
1696 __u16 count;
1698 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1699 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1701 if (rc)
1702 return rc;
1704 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1705 timeout = CIFS_ASYNC_OP; /* no response expected */
1706 pSMB->Timeout = 0;
1707 } else if (waitFlag) {
1708 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1709 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1710 } else {
1711 pSMB->Timeout = 0;
1714 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1715 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1716 pSMB->LockType = lockType;
1717 pSMB->AndXCommand = 0xFF; /* none */
1718 pSMB->Fid = smb_file_id; /* netfid stays le */
1720 if ((numLock != 0) || (numUnlock != 0)) {
1721 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1722 /* BB where to store pid high? */
1723 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1724 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1725 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1726 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1727 count = sizeof(LOCKING_ANDX_RANGE);
1728 } else {
1729 /* oplock break */
1730 count = 0;
1732 pSMB->hdr.smb_buf_length += count;
1733 pSMB->ByteCount = cpu_to_le16(count);
1735 if (waitFlag) {
1736 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1737 (struct smb_hdr *) pSMB, &bytes_returned);
1738 cifs_small_buf_release(pSMB);
1739 } else {
1740 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1741 timeout);
1742 /* SMB buffer freed by function above */
1744 cifs_stats_inc(&tcon->num_locks);
1745 if (rc)
1746 cFYI(1, ("Send error in Lock = %d", rc));
1748 /* Note: On -EAGAIN error only caller can retry on handle based calls
1749 since file handle passed in no longer valid */
1750 return rc;
1754 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1755 const __u16 smb_file_id, const int get_flag, const __u64 len,
1756 struct file_lock *pLockData, const __u16 lock_type,
1757 const bool waitFlag)
1759 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1760 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1761 struct cifs_posix_lock *parm_data;
1762 int rc = 0;
1763 int timeout = 0;
1764 int bytes_returned = 0;
1765 int resp_buf_type = 0;
1766 __u16 params, param_offset, offset, byte_count, count;
1767 struct kvec iov[1];
1769 cFYI(1, ("Posix Lock"));
1771 if (pLockData == NULL)
1772 return -EINVAL;
1774 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1776 if (rc)
1777 return rc;
1779 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1781 params = 6;
1782 pSMB->MaxSetupCount = 0;
1783 pSMB->Reserved = 0;
1784 pSMB->Flags = 0;
1785 pSMB->Reserved2 = 0;
1786 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1787 offset = param_offset + params;
1789 count = sizeof(struct cifs_posix_lock);
1790 pSMB->MaxParameterCount = cpu_to_le16(2);
1791 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1792 pSMB->SetupCount = 1;
1793 pSMB->Reserved3 = 0;
1794 if (get_flag)
1795 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1796 else
1797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1798 byte_count = 3 /* pad */ + params + count;
1799 pSMB->DataCount = cpu_to_le16(count);
1800 pSMB->ParameterCount = cpu_to_le16(params);
1801 pSMB->TotalDataCount = pSMB->DataCount;
1802 pSMB->TotalParameterCount = pSMB->ParameterCount;
1803 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1804 parm_data = (struct cifs_posix_lock *)
1805 (((char *) &pSMB->hdr.Protocol) + offset);
1807 parm_data->lock_type = cpu_to_le16(lock_type);
1808 if (waitFlag) {
1809 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1810 parm_data->lock_flags = cpu_to_le16(1);
1811 pSMB->Timeout = cpu_to_le32(-1);
1812 } else
1813 pSMB->Timeout = 0;
1815 parm_data->pid = cpu_to_le32(current->tgid);
1816 parm_data->start = cpu_to_le64(pLockData->fl_start);
1817 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1819 pSMB->DataOffset = cpu_to_le16(offset);
1820 pSMB->Fid = smb_file_id;
1821 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1822 pSMB->Reserved4 = 0;
1823 pSMB->hdr.smb_buf_length += byte_count;
1824 pSMB->ByteCount = cpu_to_le16(byte_count);
1825 if (waitFlag) {
1826 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1827 (struct smb_hdr *) pSMBr, &bytes_returned);
1828 } else {
1829 iov[0].iov_base = (char *)pSMB;
1830 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1831 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1832 &resp_buf_type, timeout);
1833 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1834 not try to free it twice below on exit */
1835 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1838 if (rc) {
1839 cFYI(1, ("Send error in Posix Lock = %d", rc));
1840 } else if (get_flag) {
1841 /* lock structure can be returned on get */
1842 __u16 data_offset;
1843 __u16 data_count;
1844 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1846 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1847 rc = -EIO; /* bad smb */
1848 goto plk_err_exit;
1850 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1851 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1852 if (data_count < sizeof(struct cifs_posix_lock)) {
1853 rc = -EIO;
1854 goto plk_err_exit;
1856 parm_data = (struct cifs_posix_lock *)
1857 ((char *)&pSMBr->hdr.Protocol + data_offset);
1858 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1859 pLockData->fl_type = F_UNLCK;
1862 plk_err_exit:
1863 if (pSMB)
1864 cifs_small_buf_release(pSMB);
1866 if (resp_buf_type == CIFS_SMALL_BUFFER)
1867 cifs_small_buf_release(iov[0].iov_base);
1868 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1869 cifs_buf_release(iov[0].iov_base);
1871 /* Note: On -EAGAIN error only caller can retry on handle based calls
1872 since file handle passed in no longer valid */
1874 return rc;
1879 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1881 int rc = 0;
1882 CLOSE_REQ *pSMB = NULL;
1883 cFYI(1, ("In CIFSSMBClose"));
1885 /* do not retry on dead session on close */
1886 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1887 if (rc == -EAGAIN)
1888 return 0;
1889 if (rc)
1890 return rc;
1892 pSMB->FileID = (__u16) smb_file_id;
1893 pSMB->LastWriteTime = 0xFFFFFFFF;
1894 pSMB->ByteCount = 0;
1895 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1896 cifs_stats_inc(&tcon->num_closes);
1897 if (rc) {
1898 if (rc != -EINTR) {
1899 /* EINTR is expected when user ctl-c to kill app */
1900 cERROR(1, ("Send error in Close = %d", rc));
1904 /* Since session is dead, file will be closed on server already */
1905 if (rc == -EAGAIN)
1906 rc = 0;
1908 return rc;
1912 CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1914 int rc = 0;
1915 FLUSH_REQ *pSMB = NULL;
1916 cFYI(1, ("In CIFSSMBFlush"));
1918 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1919 if (rc)
1920 return rc;
1922 pSMB->FileID = (__u16) smb_file_id;
1923 pSMB->ByteCount = 0;
1924 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1925 cifs_stats_inc(&tcon->num_flushes);
1926 if (rc)
1927 cERROR(1, ("Send error in Flush = %d", rc));
1929 return rc;
1933 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1934 const char *fromName, const char *toName,
1935 const struct nls_table *nls_codepage, int remap)
1937 int rc = 0;
1938 RENAME_REQ *pSMB = NULL;
1939 RENAME_RSP *pSMBr = NULL;
1940 int bytes_returned;
1941 int name_len, name_len2;
1942 __u16 count;
1944 cFYI(1, ("In CIFSSMBRename"));
1945 renameRetry:
1946 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1947 (void **) &pSMBr);
1948 if (rc)
1949 return rc;
1951 pSMB->BufferFormat = 0x04;
1952 pSMB->SearchAttributes =
1953 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1954 ATTR_DIRECTORY);
1956 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1957 name_len =
1958 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1959 PATH_MAX, nls_codepage, remap);
1960 name_len++; /* trailing null */
1961 name_len *= 2;
1962 pSMB->OldFileName[name_len] = 0x04; /* pad */
1963 /* protocol requires ASCII signature byte on Unicode string */
1964 pSMB->OldFileName[name_len + 1] = 0x00;
1965 name_len2 =
1966 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1967 toName, PATH_MAX, nls_codepage, remap);
1968 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1969 name_len2 *= 2; /* convert to bytes */
1970 } else { /* BB improve the check for buffer overruns BB */
1971 name_len = strnlen(fromName, PATH_MAX);
1972 name_len++; /* trailing null */
1973 strncpy(pSMB->OldFileName, fromName, name_len);
1974 name_len2 = strnlen(toName, PATH_MAX);
1975 name_len2++; /* trailing null */
1976 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1977 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1978 name_len2++; /* trailing null */
1979 name_len2++; /* signature byte */
1982 count = 1 /* 1st signature byte */ + name_len + name_len2;
1983 pSMB->hdr.smb_buf_length += count;
1984 pSMB->ByteCount = cpu_to_le16(count);
1986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1988 cifs_stats_inc(&tcon->num_renames);
1989 if (rc)
1990 cFYI(1, ("Send error in rename = %d", rc));
1992 cifs_buf_release(pSMB);
1994 if (rc == -EAGAIN)
1995 goto renameRetry;
1997 return rc;
2000 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2001 int netfid, const char *target_name,
2002 const struct nls_table *nls_codepage, int remap)
2004 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2005 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2006 struct set_file_rename *rename_info;
2007 char *data_offset;
2008 char dummy_string[30];
2009 int rc = 0;
2010 int bytes_returned = 0;
2011 int len_of_str;
2012 __u16 params, param_offset, offset, count, byte_count;
2014 cFYI(1, ("Rename to File by handle"));
2015 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2016 (void **) &pSMBr);
2017 if (rc)
2018 return rc;
2020 params = 6;
2021 pSMB->MaxSetupCount = 0;
2022 pSMB->Reserved = 0;
2023 pSMB->Flags = 0;
2024 pSMB->Timeout = 0;
2025 pSMB->Reserved2 = 0;
2026 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2027 offset = param_offset + params;
2029 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2030 rename_info = (struct set_file_rename *) data_offset;
2031 pSMB->MaxParameterCount = cpu_to_le16(2);
2032 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2033 pSMB->SetupCount = 1;
2034 pSMB->Reserved3 = 0;
2035 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2036 byte_count = 3 /* pad */ + params;
2037 pSMB->ParameterCount = cpu_to_le16(params);
2038 pSMB->TotalParameterCount = pSMB->ParameterCount;
2039 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2040 pSMB->DataOffset = cpu_to_le16(offset);
2041 /* construct random name ".cifs_tmp<inodenum><mid>" */
2042 rename_info->overwrite = cpu_to_le32(1);
2043 rename_info->root_fid = 0;
2044 /* unicode only call */
2045 if (target_name == NULL) {
2046 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2047 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2048 dummy_string, 24, nls_codepage, remap);
2049 } else {
2050 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2051 target_name, PATH_MAX, nls_codepage,
2052 remap);
2054 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2055 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2056 byte_count += count;
2057 pSMB->DataCount = cpu_to_le16(count);
2058 pSMB->TotalDataCount = pSMB->DataCount;
2059 pSMB->Fid = netfid;
2060 pSMB->InformationLevel =
2061 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2062 pSMB->Reserved4 = 0;
2063 pSMB->hdr.smb_buf_length += byte_count;
2064 pSMB->ByteCount = cpu_to_le16(byte_count);
2065 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2066 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2067 cifs_stats_inc(&pTcon->num_t2renames);
2068 if (rc)
2069 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2071 cifs_buf_release(pSMB);
2073 /* Note: On -EAGAIN error only caller can retry on handle based calls
2074 since file handle passed in no longer valid */
2076 return rc;
2080 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2081 const __u16 target_tid, const char *toName, const int flags,
2082 const struct nls_table *nls_codepage, int remap)
2084 int rc = 0;
2085 COPY_REQ *pSMB = NULL;
2086 COPY_RSP *pSMBr = NULL;
2087 int bytes_returned;
2088 int name_len, name_len2;
2089 __u16 count;
2091 cFYI(1, ("In CIFSSMBCopy"));
2092 copyRetry:
2093 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2094 (void **) &pSMBr);
2095 if (rc)
2096 return rc;
2098 pSMB->BufferFormat = 0x04;
2099 pSMB->Tid2 = target_tid;
2101 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2103 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2104 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2105 fromName, PATH_MAX, nls_codepage,
2106 remap);
2107 name_len++; /* trailing null */
2108 name_len *= 2;
2109 pSMB->OldFileName[name_len] = 0x04; /* pad */
2110 /* protocol requires ASCII signature byte on Unicode string */
2111 pSMB->OldFileName[name_len + 1] = 0x00;
2112 name_len2 =
2113 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2114 toName, PATH_MAX, nls_codepage, remap);
2115 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2116 name_len2 *= 2; /* convert to bytes */
2117 } else { /* BB improve the check for buffer overruns BB */
2118 name_len = strnlen(fromName, PATH_MAX);
2119 name_len++; /* trailing null */
2120 strncpy(pSMB->OldFileName, fromName, name_len);
2121 name_len2 = strnlen(toName, PATH_MAX);
2122 name_len2++; /* trailing null */
2123 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2124 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2125 name_len2++; /* trailing null */
2126 name_len2++; /* signature byte */
2129 count = 1 /* 1st signature byte */ + name_len + name_len2;
2130 pSMB->hdr.smb_buf_length += count;
2131 pSMB->ByteCount = cpu_to_le16(count);
2133 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2134 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2135 if (rc) {
2136 cFYI(1, ("Send error in copy = %d with %d files copied",
2137 rc, le16_to_cpu(pSMBr->CopyCount)));
2139 cifs_buf_release(pSMB);
2141 if (rc == -EAGAIN)
2142 goto copyRetry;
2144 return rc;
2148 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2149 const char *fromName, const char *toName,
2150 const struct nls_table *nls_codepage)
2152 TRANSACTION2_SPI_REQ *pSMB = NULL;
2153 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2154 char *data_offset;
2155 int name_len;
2156 int name_len_target;
2157 int rc = 0;
2158 int bytes_returned = 0;
2159 __u16 params, param_offset, offset, byte_count;
2161 cFYI(1, ("In Symlink Unix style"));
2162 createSymLinkRetry:
2163 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2164 (void **) &pSMBr);
2165 if (rc)
2166 return rc;
2168 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2169 name_len =
2170 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2171 /* find define for this maxpathcomponent */
2172 , nls_codepage);
2173 name_len++; /* trailing null */
2174 name_len *= 2;
2176 } else { /* BB improve the check for buffer overruns BB */
2177 name_len = strnlen(fromName, PATH_MAX);
2178 name_len++; /* trailing null */
2179 strncpy(pSMB->FileName, fromName, name_len);
2181 params = 6 + name_len;
2182 pSMB->MaxSetupCount = 0;
2183 pSMB->Reserved = 0;
2184 pSMB->Flags = 0;
2185 pSMB->Timeout = 0;
2186 pSMB->Reserved2 = 0;
2187 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2188 InformationLevel) - 4;
2189 offset = param_offset + params;
2191 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2192 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2193 name_len_target =
2194 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2195 /* find define for this maxpathcomponent */
2196 , nls_codepage);
2197 name_len_target++; /* trailing null */
2198 name_len_target *= 2;
2199 } else { /* BB improve the check for buffer overruns BB */
2200 name_len_target = strnlen(toName, PATH_MAX);
2201 name_len_target++; /* trailing null */
2202 strncpy(data_offset, toName, name_len_target);
2205 pSMB->MaxParameterCount = cpu_to_le16(2);
2206 /* BB find exact max on data count below from sess */
2207 pSMB->MaxDataCount = cpu_to_le16(1000);
2208 pSMB->SetupCount = 1;
2209 pSMB->Reserved3 = 0;
2210 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2211 byte_count = 3 /* pad */ + params + name_len_target;
2212 pSMB->DataCount = cpu_to_le16(name_len_target);
2213 pSMB->ParameterCount = cpu_to_le16(params);
2214 pSMB->TotalDataCount = pSMB->DataCount;
2215 pSMB->TotalParameterCount = pSMB->ParameterCount;
2216 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2217 pSMB->DataOffset = cpu_to_le16(offset);
2218 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2219 pSMB->Reserved4 = 0;
2220 pSMB->hdr.smb_buf_length += byte_count;
2221 pSMB->ByteCount = cpu_to_le16(byte_count);
2222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2224 cifs_stats_inc(&tcon->num_symlinks);
2225 if (rc)
2226 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2228 cifs_buf_release(pSMB);
2230 if (rc == -EAGAIN)
2231 goto createSymLinkRetry;
2233 return rc;
2237 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2238 const char *fromName, const char *toName,
2239 const struct nls_table *nls_codepage, int remap)
2241 TRANSACTION2_SPI_REQ *pSMB = NULL;
2242 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2243 char *data_offset;
2244 int name_len;
2245 int name_len_target;
2246 int rc = 0;
2247 int bytes_returned = 0;
2248 __u16 params, param_offset, offset, byte_count;
2250 cFYI(1, ("In Create Hard link Unix style"));
2251 createHardLinkRetry:
2252 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2253 (void **) &pSMBr);
2254 if (rc)
2255 return rc;
2257 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2258 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2259 PATH_MAX, nls_codepage, remap);
2260 name_len++; /* trailing null */
2261 name_len *= 2;
2263 } else { /* BB improve the check for buffer overruns BB */
2264 name_len = strnlen(toName, PATH_MAX);
2265 name_len++; /* trailing null */
2266 strncpy(pSMB->FileName, toName, name_len);
2268 params = 6 + name_len;
2269 pSMB->MaxSetupCount = 0;
2270 pSMB->Reserved = 0;
2271 pSMB->Flags = 0;
2272 pSMB->Timeout = 0;
2273 pSMB->Reserved2 = 0;
2274 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2275 InformationLevel) - 4;
2276 offset = param_offset + params;
2278 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2279 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2280 name_len_target =
2281 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2282 nls_codepage, remap);
2283 name_len_target++; /* trailing null */
2284 name_len_target *= 2;
2285 } else { /* BB improve the check for buffer overruns BB */
2286 name_len_target = strnlen(fromName, PATH_MAX);
2287 name_len_target++; /* trailing null */
2288 strncpy(data_offset, fromName, name_len_target);
2291 pSMB->MaxParameterCount = cpu_to_le16(2);
2292 /* BB find exact max on data count below from sess*/
2293 pSMB->MaxDataCount = cpu_to_le16(1000);
2294 pSMB->SetupCount = 1;
2295 pSMB->Reserved3 = 0;
2296 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2297 byte_count = 3 /* pad */ + params + name_len_target;
2298 pSMB->ParameterCount = cpu_to_le16(params);
2299 pSMB->TotalParameterCount = pSMB->ParameterCount;
2300 pSMB->DataCount = cpu_to_le16(name_len_target);
2301 pSMB->TotalDataCount = pSMB->DataCount;
2302 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2303 pSMB->DataOffset = cpu_to_le16(offset);
2304 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2305 pSMB->Reserved4 = 0;
2306 pSMB->hdr.smb_buf_length += byte_count;
2307 pSMB->ByteCount = cpu_to_le16(byte_count);
2308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2309 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2310 cifs_stats_inc(&tcon->num_hardlinks);
2311 if (rc)
2312 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2314 cifs_buf_release(pSMB);
2315 if (rc == -EAGAIN)
2316 goto createHardLinkRetry;
2318 return rc;
2322 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2323 const char *fromName, const char *toName,
2324 const struct nls_table *nls_codepage, int remap)
2326 int rc = 0;
2327 NT_RENAME_REQ *pSMB = NULL;
2328 RENAME_RSP *pSMBr = NULL;
2329 int bytes_returned;
2330 int name_len, name_len2;
2331 __u16 count;
2333 cFYI(1, ("In CIFSCreateHardLink"));
2334 winCreateHardLinkRetry:
2336 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2337 (void **) &pSMBr);
2338 if (rc)
2339 return rc;
2341 pSMB->SearchAttributes =
2342 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2343 ATTR_DIRECTORY);
2344 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2345 pSMB->ClusterCount = 0;
2347 pSMB->BufferFormat = 0x04;
2349 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2350 name_len =
2351 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2352 PATH_MAX, nls_codepage, remap);
2353 name_len++; /* trailing null */
2354 name_len *= 2;
2356 /* protocol specifies ASCII buffer format (0x04) for unicode */
2357 pSMB->OldFileName[name_len] = 0x04;
2358 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
2359 name_len2 =
2360 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2361 toName, PATH_MAX, nls_codepage, remap);
2362 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2363 name_len2 *= 2; /* convert to bytes */
2364 } else { /* BB improve the check for buffer overruns BB */
2365 name_len = strnlen(fromName, PATH_MAX);
2366 name_len++; /* trailing null */
2367 strncpy(pSMB->OldFileName, fromName, name_len);
2368 name_len2 = strnlen(toName, PATH_MAX);
2369 name_len2++; /* trailing null */
2370 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2371 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2372 name_len2++; /* trailing null */
2373 name_len2++; /* signature byte */
2376 count = 1 /* string type byte */ + name_len + name_len2;
2377 pSMB->hdr.smb_buf_length += count;
2378 pSMB->ByteCount = cpu_to_le16(count);
2380 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2381 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2382 cifs_stats_inc(&tcon->num_hardlinks);
2383 if (rc)
2384 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2386 cifs_buf_release(pSMB);
2387 if (rc == -EAGAIN)
2388 goto winCreateHardLinkRetry;
2390 return rc;
2394 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2395 const unsigned char *searchName, char **symlinkinfo,
2396 const struct nls_table *nls_codepage)
2398 /* SMB_QUERY_FILE_UNIX_LINK */
2399 TRANSACTION2_QPI_REQ *pSMB = NULL;
2400 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2401 int rc = 0;
2402 int bytes_returned;
2403 int name_len;
2404 __u16 params, byte_count;
2405 char *data_start;
2407 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2409 querySymLinkRetry:
2410 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2411 (void **) &pSMBr);
2412 if (rc)
2413 return rc;
2415 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2416 name_len =
2417 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2418 PATH_MAX, nls_codepage);
2419 name_len++; /* trailing null */
2420 name_len *= 2;
2421 } else { /* BB improve the check for buffer overruns BB */
2422 name_len = strnlen(searchName, PATH_MAX);
2423 name_len++; /* trailing null */
2424 strncpy(pSMB->FileName, searchName, name_len);
2427 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2428 pSMB->TotalDataCount = 0;
2429 pSMB->MaxParameterCount = cpu_to_le16(2);
2430 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
2431 pSMB->MaxSetupCount = 0;
2432 pSMB->Reserved = 0;
2433 pSMB->Flags = 0;
2434 pSMB->Timeout = 0;
2435 pSMB->Reserved2 = 0;
2436 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2437 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2438 pSMB->DataCount = 0;
2439 pSMB->DataOffset = 0;
2440 pSMB->SetupCount = 1;
2441 pSMB->Reserved3 = 0;
2442 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2443 byte_count = params + 1 /* pad */ ;
2444 pSMB->TotalParameterCount = cpu_to_le16(params);
2445 pSMB->ParameterCount = pSMB->TotalParameterCount;
2446 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2447 pSMB->Reserved4 = 0;
2448 pSMB->hdr.smb_buf_length += byte_count;
2449 pSMB->ByteCount = cpu_to_le16(byte_count);
2451 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2452 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2453 if (rc) {
2454 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2455 } else {
2456 /* decode response */
2458 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2459 /* BB also check enough total bytes returned */
2460 if (rc || (pSMBr->ByteCount < 2))
2461 rc = -EIO;
2462 else {
2463 bool is_unicode;
2464 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2466 data_start = ((char *) &pSMBr->hdr.Protocol) +
2467 le16_to_cpu(pSMBr->t2.DataOffset);
2469 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2470 is_unicode = true;
2471 else
2472 is_unicode = false;
2474 /* BB FIXME investigate remapping reserved chars here */
2475 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
2476 is_unicode, nls_codepage);
2477 if (!*symlinkinfo)
2478 rc = -ENOMEM;
2481 cifs_buf_release(pSMB);
2482 if (rc == -EAGAIN)
2483 goto querySymLinkRetry;
2484 return rc;
2487 #ifdef CONFIG_CIFS_EXPERIMENTAL
2488 /* Initialize NT TRANSACT SMB into small smb request buffer.
2489 This assumes that all NT TRANSACTS that we init here have
2490 total parm and data under about 400 bytes (to fit in small cifs
2491 buffer size), which is the case so far, it easily fits. NB:
2492 Setup words themselves and ByteCount
2493 MaxSetupCount (size of returned setup area) and
2494 MaxParameterCount (returned parms size) must be set by caller */
2495 static int
2496 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2497 const int parm_len, struct cifsTconInfo *tcon,
2498 void **ret_buf)
2500 int rc;
2501 __u32 temp_offset;
2502 struct smb_com_ntransact_req *pSMB;
2504 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2505 (void **)&pSMB);
2506 if (rc)
2507 return rc;
2508 *ret_buf = (void *)pSMB;
2509 pSMB->Reserved = 0;
2510 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2511 pSMB->TotalDataCount = 0;
2512 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2513 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2514 pSMB->ParameterCount = pSMB->TotalParameterCount;
2515 pSMB->DataCount = pSMB->TotalDataCount;
2516 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2517 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2518 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2519 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2520 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2521 pSMB->SubCommand = cpu_to_le16(sub_command);
2522 return 0;
2525 static int
2526 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2527 __u32 *pparmlen, __u32 *pdatalen)
2529 char *end_of_smb;
2530 __u32 data_count, data_offset, parm_count, parm_offset;
2531 struct smb_com_ntransact_rsp *pSMBr;
2533 *pdatalen = 0;
2534 *pparmlen = 0;
2536 if (buf == NULL)
2537 return -EINVAL;
2539 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2541 /* ByteCount was converted from little endian in SendReceive */
2542 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2543 (char *)&pSMBr->ByteCount;
2545 data_offset = le32_to_cpu(pSMBr->DataOffset);
2546 data_count = le32_to_cpu(pSMBr->DataCount);
2547 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2548 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2550 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2551 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2553 /* should we also check that parm and data areas do not overlap? */
2554 if (*ppparm > end_of_smb) {
2555 cFYI(1, ("parms start after end of smb"));
2556 return -EINVAL;
2557 } else if (parm_count + *ppparm > end_of_smb) {
2558 cFYI(1, ("parm end after end of smb"));
2559 return -EINVAL;
2560 } else if (*ppdata > end_of_smb) {
2561 cFYI(1, ("data starts after end of smb"));
2562 return -EINVAL;
2563 } else if (data_count + *ppdata > end_of_smb) {
2564 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2565 *ppdata, data_count, (data_count + *ppdata),
2566 end_of_smb, pSMBr));
2567 return -EINVAL;
2568 } else if (parm_count + data_count > pSMBr->ByteCount) {
2569 cFYI(1, ("parm count and data count larger than SMB"));
2570 return -EINVAL;
2572 *pdatalen = data_count;
2573 *pparmlen = parm_count;
2574 return 0;
2578 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2579 const unsigned char *searchName,
2580 char *symlinkinfo, const int buflen, __u16 fid,
2581 const struct nls_table *nls_codepage)
2583 int rc = 0;
2584 int bytes_returned;
2585 struct smb_com_transaction_ioctl_req *pSMB;
2586 struct smb_com_transaction_ioctl_rsp *pSMBr;
2588 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2589 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2590 (void **) &pSMBr);
2591 if (rc)
2592 return rc;
2594 pSMB->TotalParameterCount = 0 ;
2595 pSMB->TotalDataCount = 0;
2596 pSMB->MaxParameterCount = cpu_to_le32(2);
2597 /* BB find exact data count max from sess structure BB */
2598 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2599 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2600 pSMB->MaxSetupCount = 4;
2601 pSMB->Reserved = 0;
2602 pSMB->ParameterOffset = 0;
2603 pSMB->DataCount = 0;
2604 pSMB->DataOffset = 0;
2605 pSMB->SetupCount = 4;
2606 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2607 pSMB->ParameterCount = pSMB->TotalParameterCount;
2608 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2609 pSMB->IsFsctl = 1; /* FSCTL */
2610 pSMB->IsRootFlag = 0;
2611 pSMB->Fid = fid; /* file handle always le */
2612 pSMB->ByteCount = 0;
2614 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2616 if (rc) {
2617 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2618 } else { /* decode response */
2619 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2620 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2621 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
2622 /* BB also check enough total bytes returned */
2623 rc = -EIO; /* bad smb */
2624 goto qreparse_out;
2626 if (data_count && (data_count < 2048)) {
2627 char *end_of_smb = 2 /* sizeof byte count */ +
2628 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
2630 struct reparse_data *reparse_buf =
2631 (struct reparse_data *)
2632 ((char *)&pSMBr->hdr.Protocol
2633 + data_offset);
2634 if ((char *)reparse_buf >= end_of_smb) {
2635 rc = -EIO;
2636 goto qreparse_out;
2638 if ((reparse_buf->LinkNamesBuf +
2639 reparse_buf->TargetNameOffset +
2640 reparse_buf->TargetNameLen) > end_of_smb) {
2641 cFYI(1, ("reparse buf beyond SMB"));
2642 rc = -EIO;
2643 goto qreparse_out;
2646 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2647 cifs_from_ucs2(symlinkinfo, (__le16 *)
2648 (reparse_buf->LinkNamesBuf +
2649 reparse_buf->TargetNameOffset),
2650 buflen,
2651 reparse_buf->TargetNameLen,
2652 nls_codepage, 0);
2653 } else { /* ASCII names */
2654 strncpy(symlinkinfo,
2655 reparse_buf->LinkNamesBuf +
2656 reparse_buf->TargetNameOffset,
2657 min_t(const int, buflen,
2658 reparse_buf->TargetNameLen));
2660 } else {
2661 rc = -EIO;
2662 cFYI(1, ("Invalid return data count on "
2663 "get reparse info ioctl"));
2665 symlinkinfo[buflen] = 0; /* just in case so the caller
2666 does not go off the end of the buffer */
2667 cFYI(1, ("readlink result - %s", symlinkinfo));
2670 qreparse_out:
2671 cifs_buf_release(pSMB);
2673 /* Note: On -EAGAIN error only caller can retry on handle based calls
2674 since file handle passed in no longer valid */
2676 return rc;
2678 #endif /* CIFS_EXPERIMENTAL */
2680 #ifdef CONFIG_CIFS_POSIX
2682 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2683 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2684 struct cifs_posix_ace *cifs_ace)
2686 /* u8 cifs fields do not need le conversion */
2687 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2688 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2689 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2690 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2692 return;
2695 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2696 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2697 const int acl_type, const int size_of_data_area)
2699 int size = 0;
2700 int i;
2701 __u16 count;
2702 struct cifs_posix_ace *pACE;
2703 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2704 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2706 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2707 return -EOPNOTSUPP;
2709 if (acl_type & ACL_TYPE_ACCESS) {
2710 count = le16_to_cpu(cifs_acl->access_entry_count);
2711 pACE = &cifs_acl->ace_array[0];
2712 size = sizeof(struct cifs_posix_acl);
2713 size += sizeof(struct cifs_posix_ace) * count;
2714 /* check if we would go beyond end of SMB */
2715 if (size_of_data_area < size) {
2716 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2717 size_of_data_area, size));
2718 return -EINVAL;
2720 } else if (acl_type & ACL_TYPE_DEFAULT) {
2721 count = le16_to_cpu(cifs_acl->access_entry_count);
2722 size = sizeof(struct cifs_posix_acl);
2723 size += sizeof(struct cifs_posix_ace) * count;
2724 /* skip past access ACEs to get to default ACEs */
2725 pACE = &cifs_acl->ace_array[count];
2726 count = le16_to_cpu(cifs_acl->default_entry_count);
2727 size += sizeof(struct cifs_posix_ace) * count;
2728 /* check if we would go beyond end of SMB */
2729 if (size_of_data_area < size)
2730 return -EINVAL;
2731 } else {
2732 /* illegal type */
2733 return -EINVAL;
2736 size = posix_acl_xattr_size(count);
2737 if ((buflen == 0) || (local_acl == NULL)) {
2738 /* used to query ACL EA size */
2739 } else if (size > buflen) {
2740 return -ERANGE;
2741 } else /* buffer big enough */ {
2742 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2743 for (i = 0; i < count ; i++) {
2744 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2745 pACE++;
2748 return size;
2751 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2752 const posix_acl_xattr_entry *local_ace)
2754 __u16 rc = 0; /* 0 = ACL converted ok */
2756 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2757 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2758 /* BB is there a better way to handle the large uid? */
2759 if (local_ace->e_id == cpu_to_le32(-1)) {
2760 /* Probably no need to le convert -1 on any arch but can not hurt */
2761 cifs_ace->cifs_uid = cpu_to_le64(-1);
2762 } else
2763 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2764 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2765 return rc;
2768 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2769 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2770 const int buflen, const int acl_type)
2772 __u16 rc = 0;
2773 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2774 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2775 int count;
2776 int i;
2778 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2779 return 0;
2781 count = posix_acl_xattr_count((size_t)buflen);
2782 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2783 "version of %d",
2784 count, buflen, le32_to_cpu(local_acl->a_version)));
2785 if (le32_to_cpu(local_acl->a_version) != 2) {
2786 cFYI(1, ("unknown POSIX ACL version %d",
2787 le32_to_cpu(local_acl->a_version)));
2788 return 0;
2790 cifs_acl->version = cpu_to_le16(1);
2791 if (acl_type == ACL_TYPE_ACCESS)
2792 cifs_acl->access_entry_count = cpu_to_le16(count);
2793 else if (acl_type == ACL_TYPE_DEFAULT)
2794 cifs_acl->default_entry_count = cpu_to_le16(count);
2795 else {
2796 cFYI(1, ("unknown ACL type %d", acl_type));
2797 return 0;
2799 for (i = 0; i < count; i++) {
2800 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2801 &local_acl->a_entries[i]);
2802 if (rc != 0) {
2803 /* ACE not converted */
2804 break;
2807 if (rc == 0) {
2808 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2809 rc += sizeof(struct cifs_posix_acl);
2810 /* BB add check to make sure ACL does not overflow SMB */
2812 return rc;
2816 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2817 const unsigned char *searchName,
2818 char *acl_inf, const int buflen, const int acl_type,
2819 const struct nls_table *nls_codepage, int remap)
2821 /* SMB_QUERY_POSIX_ACL */
2822 TRANSACTION2_QPI_REQ *pSMB = NULL;
2823 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2824 int rc = 0;
2825 int bytes_returned;
2826 int name_len;
2827 __u16 params, byte_count;
2829 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2831 queryAclRetry:
2832 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2833 (void **) &pSMBr);
2834 if (rc)
2835 return rc;
2837 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2838 name_len =
2839 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2840 PATH_MAX, nls_codepage, remap);
2841 name_len++; /* trailing null */
2842 name_len *= 2;
2843 pSMB->FileName[name_len] = 0;
2844 pSMB->FileName[name_len+1] = 0;
2845 } else { /* BB improve the check for buffer overruns BB */
2846 name_len = strnlen(searchName, PATH_MAX);
2847 name_len++; /* trailing null */
2848 strncpy(pSMB->FileName, searchName, name_len);
2851 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2852 pSMB->TotalDataCount = 0;
2853 pSMB->MaxParameterCount = cpu_to_le16(2);
2854 /* BB find exact max data count below from sess structure BB */
2855 pSMB->MaxDataCount = cpu_to_le16(4000);
2856 pSMB->MaxSetupCount = 0;
2857 pSMB->Reserved = 0;
2858 pSMB->Flags = 0;
2859 pSMB->Timeout = 0;
2860 pSMB->Reserved2 = 0;
2861 pSMB->ParameterOffset = cpu_to_le16(
2862 offsetof(struct smb_com_transaction2_qpi_req,
2863 InformationLevel) - 4);
2864 pSMB->DataCount = 0;
2865 pSMB->DataOffset = 0;
2866 pSMB->SetupCount = 1;
2867 pSMB->Reserved3 = 0;
2868 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2869 byte_count = params + 1 /* pad */ ;
2870 pSMB->TotalParameterCount = cpu_to_le16(params);
2871 pSMB->ParameterCount = pSMB->TotalParameterCount;
2872 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2873 pSMB->Reserved4 = 0;
2874 pSMB->hdr.smb_buf_length += byte_count;
2875 pSMB->ByteCount = cpu_to_le16(byte_count);
2877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2879 cifs_stats_inc(&tcon->num_acl_get);
2880 if (rc) {
2881 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2882 } else {
2883 /* decode response */
2885 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2886 if (rc || (pSMBr->ByteCount < 2))
2887 /* BB also check enough total bytes returned */
2888 rc = -EIO; /* bad smb */
2889 else {
2890 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2891 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2892 rc = cifs_copy_posix_acl(acl_inf,
2893 (char *)&pSMBr->hdr.Protocol+data_offset,
2894 buflen, acl_type, count);
2897 cifs_buf_release(pSMB);
2898 if (rc == -EAGAIN)
2899 goto queryAclRetry;
2900 return rc;
2904 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2905 const unsigned char *fileName,
2906 const char *local_acl, const int buflen,
2907 const int acl_type,
2908 const struct nls_table *nls_codepage, int remap)
2910 struct smb_com_transaction2_spi_req *pSMB = NULL;
2911 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2912 char *parm_data;
2913 int name_len;
2914 int rc = 0;
2915 int bytes_returned = 0;
2916 __u16 params, byte_count, data_count, param_offset, offset;
2918 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2919 setAclRetry:
2920 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2921 (void **) &pSMBr);
2922 if (rc)
2923 return rc;
2924 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2925 name_len =
2926 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2927 PATH_MAX, nls_codepage, remap);
2928 name_len++; /* trailing null */
2929 name_len *= 2;
2930 } else { /* BB improve the check for buffer overruns BB */
2931 name_len = strnlen(fileName, PATH_MAX);
2932 name_len++; /* trailing null */
2933 strncpy(pSMB->FileName, fileName, name_len);
2935 params = 6 + name_len;
2936 pSMB->MaxParameterCount = cpu_to_le16(2);
2937 /* BB find max SMB size from sess */
2938 pSMB->MaxDataCount = cpu_to_le16(1000);
2939 pSMB->MaxSetupCount = 0;
2940 pSMB->Reserved = 0;
2941 pSMB->Flags = 0;
2942 pSMB->Timeout = 0;
2943 pSMB->Reserved2 = 0;
2944 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2945 InformationLevel) - 4;
2946 offset = param_offset + params;
2947 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2948 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2950 /* convert to on the wire format for POSIX ACL */
2951 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2953 if (data_count == 0) {
2954 rc = -EOPNOTSUPP;
2955 goto setACLerrorExit;
2957 pSMB->DataOffset = cpu_to_le16(offset);
2958 pSMB->SetupCount = 1;
2959 pSMB->Reserved3 = 0;
2960 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2961 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2962 byte_count = 3 /* pad */ + params + data_count;
2963 pSMB->DataCount = cpu_to_le16(data_count);
2964 pSMB->TotalDataCount = pSMB->DataCount;
2965 pSMB->ParameterCount = cpu_to_le16(params);
2966 pSMB->TotalParameterCount = pSMB->ParameterCount;
2967 pSMB->Reserved4 = 0;
2968 pSMB->hdr.smb_buf_length += byte_count;
2969 pSMB->ByteCount = cpu_to_le16(byte_count);
2970 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2971 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2972 if (rc)
2973 cFYI(1, ("Set POSIX ACL returned %d", rc));
2975 setACLerrorExit:
2976 cifs_buf_release(pSMB);
2977 if (rc == -EAGAIN)
2978 goto setAclRetry;
2979 return rc;
2982 /* BB fix tabs in this function FIXME BB */
2984 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2985 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2987 int rc = 0;
2988 struct smb_t2_qfi_req *pSMB = NULL;
2989 struct smb_t2_qfi_rsp *pSMBr = NULL;
2990 int bytes_returned;
2991 __u16 params, byte_count;
2993 cFYI(1, ("In GetExtAttr"));
2994 if (tcon == NULL)
2995 return -ENODEV;
2997 GetExtAttrRetry:
2998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2999 (void **) &pSMBr);
3000 if (rc)
3001 return rc;
3003 params = 2 /* level */ + 2 /* fid */;
3004 pSMB->t2.TotalDataCount = 0;
3005 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3006 /* BB find exact max data count below from sess structure BB */
3007 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3008 pSMB->t2.MaxSetupCount = 0;
3009 pSMB->t2.Reserved = 0;
3010 pSMB->t2.Flags = 0;
3011 pSMB->t2.Timeout = 0;
3012 pSMB->t2.Reserved2 = 0;
3013 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3014 Fid) - 4);
3015 pSMB->t2.DataCount = 0;
3016 pSMB->t2.DataOffset = 0;
3017 pSMB->t2.SetupCount = 1;
3018 pSMB->t2.Reserved3 = 0;
3019 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3020 byte_count = params + 1 /* pad */ ;
3021 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3022 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3023 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3024 pSMB->Pad = 0;
3025 pSMB->Fid = netfid;
3026 pSMB->hdr.smb_buf_length += byte_count;
3027 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3031 if (rc) {
3032 cFYI(1, ("error %d in GetExtAttr", rc));
3033 } else {
3034 /* decode response */
3035 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3036 if (rc || (pSMBr->ByteCount < 2))
3037 /* BB also check enough total bytes returned */
3038 /* If rc should we check for EOPNOSUPP and
3039 disable the srvino flag? or in caller? */
3040 rc = -EIO; /* bad smb */
3041 else {
3042 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3043 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3044 struct file_chattr_info *pfinfo;
3045 /* BB Do we need a cast or hash here ? */
3046 if (count != 16) {
3047 cFYI(1, ("Illegal size ret in GetExtAttr"));
3048 rc = -EIO;
3049 goto GetExtAttrOut;
3051 pfinfo = (struct file_chattr_info *)
3052 (data_offset + (char *) &pSMBr->hdr.Protocol);
3053 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3054 *pMask = le64_to_cpu(pfinfo->mask);
3057 GetExtAttrOut:
3058 cifs_buf_release(pSMB);
3059 if (rc == -EAGAIN)
3060 goto GetExtAttrRetry;
3061 return rc;
3064 #endif /* CONFIG_POSIX */
3066 #ifdef CONFIG_CIFS_EXPERIMENTAL
3067 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3069 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3070 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3072 int rc = 0;
3073 int buf_type = 0;
3074 QUERY_SEC_DESC_REQ *pSMB;
3075 struct kvec iov[1];
3077 cFYI(1, ("GetCifsACL"));
3079 *pbuflen = 0;
3080 *acl_inf = NULL;
3082 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3083 8 /* parm len */, tcon, (void **) &pSMB);
3084 if (rc)
3085 return rc;
3087 pSMB->MaxParameterCount = cpu_to_le32(4);
3088 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3089 pSMB->MaxSetupCount = 0;
3090 pSMB->Fid = fid; /* file handle always le */
3091 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3092 CIFS_ACL_DACL);
3093 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3094 pSMB->hdr.smb_buf_length += 11;
3095 iov[0].iov_base = (char *)pSMB;
3096 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3098 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3099 CIFS_STD_OP);
3100 cifs_stats_inc(&tcon->num_acl_get);
3101 if (rc) {
3102 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3103 } else { /* decode response */
3104 __le32 *parm;
3105 __u32 parm_len;
3106 __u32 acl_len;
3107 struct smb_com_ntransact_rsp *pSMBr;
3108 char *pdata;
3110 /* validate_nttransact */
3111 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3112 &pdata, &parm_len, pbuflen);
3113 if (rc)
3114 goto qsec_out;
3115 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3117 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3119 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3120 rc = -EIO; /* bad smb */
3121 *pbuflen = 0;
3122 goto qsec_out;
3125 /* BB check that data area is minimum length and as big as acl_len */
3127 acl_len = le32_to_cpu(*parm);
3128 if (acl_len != *pbuflen) {
3129 cERROR(1, ("acl length %d does not match %d",
3130 acl_len, *pbuflen));
3131 if (*pbuflen > acl_len)
3132 *pbuflen = acl_len;
3135 /* check if buffer is big enough for the acl
3136 header followed by the smallest SID */
3137 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3138 (*pbuflen >= 64 * 1024)) {
3139 cERROR(1, ("bad acl length %d", *pbuflen));
3140 rc = -EINVAL;
3141 *pbuflen = 0;
3142 } else {
3143 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3144 if (*acl_inf == NULL) {
3145 *pbuflen = 0;
3146 rc = -ENOMEM;
3148 memcpy(*acl_inf, pdata, *pbuflen);
3151 qsec_out:
3152 if (buf_type == CIFS_SMALL_BUFFER)
3153 cifs_small_buf_release(iov[0].iov_base);
3154 else if (buf_type == CIFS_LARGE_BUFFER)
3155 cifs_buf_release(iov[0].iov_base);
3156 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3157 return rc;
3161 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3162 struct cifs_ntsd *pntsd, __u32 acllen)
3164 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3165 int rc = 0;
3166 int bytes_returned = 0;
3167 SET_SEC_DESC_REQ *pSMB = NULL;
3168 NTRANSACT_RSP *pSMBr = NULL;
3170 setCifsAclRetry:
3171 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3172 (void **) &pSMBr);
3173 if (rc)
3174 return (rc);
3176 pSMB->MaxSetupCount = 0;
3177 pSMB->Reserved = 0;
3179 param_count = 8;
3180 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3181 data_count = acllen;
3182 data_offset = param_offset + param_count;
3183 byte_count = 3 /* pad */ + param_count;
3185 pSMB->DataCount = cpu_to_le32(data_count);
3186 pSMB->TotalDataCount = pSMB->DataCount;
3187 pSMB->MaxParameterCount = cpu_to_le32(4);
3188 pSMB->MaxDataCount = cpu_to_le32(16384);
3189 pSMB->ParameterCount = cpu_to_le32(param_count);
3190 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3191 pSMB->TotalParameterCount = pSMB->ParameterCount;
3192 pSMB->DataOffset = cpu_to_le32(data_offset);
3193 pSMB->SetupCount = 0;
3194 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3195 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3197 pSMB->Fid = fid; /* file handle always le */
3198 pSMB->Reserved2 = 0;
3199 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3201 if (pntsd && acllen) {
3202 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3203 (char *) pntsd,
3204 acllen);
3205 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3207 } else
3208 pSMB->hdr.smb_buf_length += byte_count;
3210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3213 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3214 if (rc)
3215 cFYI(1, ("Set CIFS ACL returned %d", rc));
3216 cifs_buf_release(pSMB);
3218 if (rc == -EAGAIN)
3219 goto setCifsAclRetry;
3221 return (rc);
3224 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3226 /* Legacy Query Path Information call for lookup to old servers such
3227 as Win9x/WinME */
3228 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3229 const unsigned char *searchName,
3230 FILE_ALL_INFO *pFinfo,
3231 const struct nls_table *nls_codepage, int remap)
3233 QUERY_INFORMATION_REQ *pSMB;
3234 QUERY_INFORMATION_RSP *pSMBr;
3235 int rc = 0;
3236 int bytes_returned;
3237 int name_len;
3239 cFYI(1, ("In SMBQPath path %s", searchName));
3240 QInfRetry:
3241 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3242 (void **) &pSMBr);
3243 if (rc)
3244 return rc;
3246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3247 name_len =
3248 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3249 PATH_MAX, nls_codepage, remap);
3250 name_len++; /* trailing null */
3251 name_len *= 2;
3252 } else {
3253 name_len = strnlen(searchName, PATH_MAX);
3254 name_len++; /* trailing null */
3255 strncpy(pSMB->FileName, searchName, name_len);
3257 pSMB->BufferFormat = 0x04;
3258 name_len++; /* account for buffer type byte */
3259 pSMB->hdr.smb_buf_length += (__u16) name_len;
3260 pSMB->ByteCount = cpu_to_le16(name_len);
3262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3264 if (rc) {
3265 cFYI(1, ("Send error in QueryInfo = %d", rc));
3266 } else if (pFinfo) {
3267 struct timespec ts;
3268 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3270 /* decode response */
3271 /* BB FIXME - add time zone adjustment BB */
3272 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3273 ts.tv_nsec = 0;
3274 ts.tv_sec = time;
3275 /* decode time fields */
3276 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3277 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3278 pFinfo->LastAccessTime = 0;
3279 pFinfo->AllocationSize =
3280 cpu_to_le64(le32_to_cpu(pSMBr->size));
3281 pFinfo->EndOfFile = pFinfo->AllocationSize;
3282 pFinfo->Attributes =
3283 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3284 } else
3285 rc = -EIO; /* bad buffer passed in */
3287 cifs_buf_release(pSMB);
3289 if (rc == -EAGAIN)
3290 goto QInfRetry;
3292 return rc;
3299 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3300 const unsigned char *searchName,
3301 FILE_ALL_INFO *pFindData,
3302 int legacy /* old style infolevel */,
3303 const struct nls_table *nls_codepage, int remap)
3305 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3306 TRANSACTION2_QPI_REQ *pSMB = NULL;
3307 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3308 int rc = 0;
3309 int bytes_returned;
3310 int name_len;
3311 __u16 params, byte_count;
3313 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3314 QPathInfoRetry:
3315 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3316 (void **) &pSMBr);
3317 if (rc)
3318 return rc;
3320 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3321 name_len =
3322 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3323 PATH_MAX, nls_codepage, remap);
3324 name_len++; /* trailing null */
3325 name_len *= 2;
3326 } else { /* BB improve the check for buffer overruns BB */
3327 name_len = strnlen(searchName, PATH_MAX);
3328 name_len++; /* trailing null */
3329 strncpy(pSMB->FileName, searchName, name_len);
3332 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3333 pSMB->TotalDataCount = 0;
3334 pSMB->MaxParameterCount = cpu_to_le16(2);
3335 /* BB find exact max SMB PDU from sess structure BB */
3336 pSMB->MaxDataCount = cpu_to_le16(4000);
3337 pSMB->MaxSetupCount = 0;
3338 pSMB->Reserved = 0;
3339 pSMB->Flags = 0;
3340 pSMB->Timeout = 0;
3341 pSMB->Reserved2 = 0;
3342 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3343 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3344 pSMB->DataCount = 0;
3345 pSMB->DataOffset = 0;
3346 pSMB->SetupCount = 1;
3347 pSMB->Reserved3 = 0;
3348 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3349 byte_count = params + 1 /* pad */ ;
3350 pSMB->TotalParameterCount = cpu_to_le16(params);
3351 pSMB->ParameterCount = pSMB->TotalParameterCount;
3352 if (legacy)
3353 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3354 else
3355 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3356 pSMB->Reserved4 = 0;
3357 pSMB->hdr.smb_buf_length += byte_count;
3358 pSMB->ByteCount = cpu_to_le16(byte_count);
3360 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3361 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3362 if (rc) {
3363 cFYI(1, ("Send error in QPathInfo = %d", rc));
3364 } else { /* decode response */
3365 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3367 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3368 rc = -EIO;
3369 else if (!legacy && (pSMBr->ByteCount < 40))
3370 rc = -EIO; /* bad smb */
3371 else if (legacy && (pSMBr->ByteCount < 24))
3372 rc = -EIO; /* 24 or 26 expected but we do not read
3373 last field */
3374 else if (pFindData) {
3375 int size;
3376 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3378 /* On legacy responses we do not read the last field,
3379 EAsize, fortunately since it varies by subdialect and
3380 also note it differs on Set vs. Get, ie two bytes or 4
3381 bytes depending but we don't care here */
3382 if (legacy)
3383 size = sizeof(FILE_INFO_STANDARD);
3384 else
3385 size = sizeof(FILE_ALL_INFO);
3386 memcpy((char *) pFindData,
3387 (char *) &pSMBr->hdr.Protocol +
3388 data_offset, size);
3389 } else
3390 rc = -ENOMEM;
3392 cifs_buf_release(pSMB);
3393 if (rc == -EAGAIN)
3394 goto QPathInfoRetry;
3396 return rc;
3400 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3401 const unsigned char *searchName,
3402 FILE_UNIX_BASIC_INFO *pFindData,
3403 const struct nls_table *nls_codepage, int remap)
3405 /* SMB_QUERY_FILE_UNIX_BASIC */
3406 TRANSACTION2_QPI_REQ *pSMB = NULL;
3407 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3408 int rc = 0;
3409 int bytes_returned = 0;
3410 int name_len;
3411 __u16 params, byte_count;
3413 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3414 UnixQPathInfoRetry:
3415 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3416 (void **) &pSMBr);
3417 if (rc)
3418 return rc;
3420 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3421 name_len =
3422 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3423 PATH_MAX, nls_codepage, remap);
3424 name_len++; /* trailing null */
3425 name_len *= 2;
3426 } else { /* BB improve the check for buffer overruns BB */
3427 name_len = strnlen(searchName, PATH_MAX);
3428 name_len++; /* trailing null */
3429 strncpy(pSMB->FileName, searchName, name_len);
3432 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3433 pSMB->TotalDataCount = 0;
3434 pSMB->MaxParameterCount = cpu_to_le16(2);
3435 /* BB find exact max SMB PDU from sess structure BB */
3436 pSMB->MaxDataCount = cpu_to_le16(4000);
3437 pSMB->MaxSetupCount = 0;
3438 pSMB->Reserved = 0;
3439 pSMB->Flags = 0;
3440 pSMB->Timeout = 0;
3441 pSMB->Reserved2 = 0;
3442 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3443 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3444 pSMB->DataCount = 0;
3445 pSMB->DataOffset = 0;
3446 pSMB->SetupCount = 1;
3447 pSMB->Reserved3 = 0;
3448 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3449 byte_count = params + 1 /* pad */ ;
3450 pSMB->TotalParameterCount = cpu_to_le16(params);
3451 pSMB->ParameterCount = pSMB->TotalParameterCount;
3452 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3453 pSMB->Reserved4 = 0;
3454 pSMB->hdr.smb_buf_length += byte_count;
3455 pSMB->ByteCount = cpu_to_le16(byte_count);
3457 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3458 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3459 if (rc) {
3460 cFYI(1, ("Send error in QPathInfo = %d", rc));
3461 } else { /* decode response */
3462 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3464 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3465 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3466 "Unix Extensions can be disabled on mount "
3467 "by specifying the nosfu mount option."));
3468 rc = -EIO; /* bad smb */
3469 } else {
3470 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3471 memcpy((char *) pFindData,
3472 (char *) &pSMBr->hdr.Protocol +
3473 data_offset,
3474 sizeof(FILE_UNIX_BASIC_INFO));
3477 cifs_buf_release(pSMB);
3478 if (rc == -EAGAIN)
3479 goto UnixQPathInfoRetry;
3481 return rc;
3484 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3486 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3487 const char *searchName,
3488 const struct nls_table *nls_codepage,
3489 __u16 *pnetfid,
3490 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3492 /* level 257 SMB_ */
3493 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3494 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3495 T2_FFIRST_RSP_PARMS *parms;
3496 int rc = 0;
3497 int bytes_returned = 0;
3498 int name_len;
3499 __u16 params, byte_count;
3501 cFYI(1, ("In FindFirst for %s", searchName));
3503 findFirstRetry:
3504 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3505 (void **) &pSMBr);
3506 if (rc)
3507 return rc;
3509 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3510 name_len =
3511 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3512 PATH_MAX, nls_codepage, remap);
3513 /* We can not add the asterik earlier in case
3514 it got remapped to 0xF03A as if it were part of the
3515 directory name instead of a wildcard */
3516 name_len *= 2;
3517 pSMB->FileName[name_len] = dirsep;
3518 pSMB->FileName[name_len+1] = 0;
3519 pSMB->FileName[name_len+2] = '*';
3520 pSMB->FileName[name_len+3] = 0;
3521 name_len += 4; /* now the trailing null */
3522 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3523 pSMB->FileName[name_len+1] = 0;
3524 name_len += 2;
3525 } else { /* BB add check for overrun of SMB buf BB */
3526 name_len = strnlen(searchName, PATH_MAX);
3527 /* BB fix here and in unicode clause above ie
3528 if (name_len > buffersize-header)
3529 free buffer exit; BB */
3530 strncpy(pSMB->FileName, searchName, name_len);
3531 pSMB->FileName[name_len] = dirsep;
3532 pSMB->FileName[name_len+1] = '*';
3533 pSMB->FileName[name_len+2] = 0;
3534 name_len += 3;
3537 params = 12 + name_len /* includes null */ ;
3538 pSMB->TotalDataCount = 0; /* no EAs */
3539 pSMB->MaxParameterCount = cpu_to_le16(10);
3540 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3541 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3542 pSMB->MaxSetupCount = 0;
3543 pSMB->Reserved = 0;
3544 pSMB->Flags = 0;
3545 pSMB->Timeout = 0;
3546 pSMB->Reserved2 = 0;
3547 byte_count = params + 1 /* pad */ ;
3548 pSMB->TotalParameterCount = cpu_to_le16(params);
3549 pSMB->ParameterCount = pSMB->TotalParameterCount;
3550 pSMB->ParameterOffset = cpu_to_le16(
3551 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3552 - 4);
3553 pSMB->DataCount = 0;
3554 pSMB->DataOffset = 0;
3555 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3556 pSMB->Reserved3 = 0;
3557 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3558 pSMB->SearchAttributes =
3559 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3560 ATTR_DIRECTORY);
3561 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3562 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3563 CIFS_SEARCH_RETURN_RESUME);
3564 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3566 /* BB what should we set StorageType to? Does it matter? BB */
3567 pSMB->SearchStorageType = 0;
3568 pSMB->hdr.smb_buf_length += byte_count;
3569 pSMB->ByteCount = cpu_to_le16(byte_count);
3571 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3572 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3573 cifs_stats_inc(&tcon->num_ffirst);
3575 if (rc) {/* BB add logic to retry regular search if Unix search
3576 rejected unexpectedly by server */
3577 /* BB Add code to handle unsupported level rc */
3578 cFYI(1, ("Error in FindFirst = %d", rc));
3580 cifs_buf_release(pSMB);
3582 /* BB eventually could optimize out free and realloc of buf */
3583 /* for this case */
3584 if (rc == -EAGAIN)
3585 goto findFirstRetry;
3586 } else { /* decode response */
3587 /* BB remember to free buffer if error BB */
3588 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3589 if (rc == 0) {
3590 unsigned int lnoff;
3592 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3593 psrch_inf->unicode = true;
3594 else
3595 psrch_inf->unicode = false;
3597 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3598 psrch_inf->smallBuf = 0;
3599 psrch_inf->srch_entries_start =
3600 (char *) &pSMBr->hdr.Protocol +
3601 le16_to_cpu(pSMBr->t2.DataOffset);
3602 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3603 le16_to_cpu(pSMBr->t2.ParameterOffset));
3605 if (parms->EndofSearch)
3606 psrch_inf->endOfSearch = true;
3607 else
3608 psrch_inf->endOfSearch = false;
3610 psrch_inf->entries_in_buffer =
3611 le16_to_cpu(parms->SearchCount);
3612 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3613 psrch_inf->entries_in_buffer;
3614 lnoff = le16_to_cpu(parms->LastNameOffset);
3615 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3616 lnoff) {
3617 cERROR(1, ("ignoring corrupt resume name"));
3618 psrch_inf->last_entry = NULL;
3619 return rc;
3622 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3623 lnoff;
3625 *pnetfid = parms->SearchHandle;
3626 } else {
3627 cifs_buf_release(pSMB);
3631 return rc;
3634 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3635 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3637 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3638 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3639 T2_FNEXT_RSP_PARMS *parms;
3640 char *response_data;
3641 int rc = 0;
3642 int bytes_returned, name_len;
3643 __u16 params, byte_count;
3645 cFYI(1, ("In FindNext"));
3647 if (psrch_inf->endOfSearch)
3648 return -ENOENT;
3650 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3651 (void **) &pSMBr);
3652 if (rc)
3653 return rc;
3655 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3656 byte_count = 0;
3657 pSMB->TotalDataCount = 0; /* no EAs */
3658 pSMB->MaxParameterCount = cpu_to_le16(8);
3659 pSMB->MaxDataCount =
3660 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3661 0xFFFFFF00);
3662 pSMB->MaxSetupCount = 0;
3663 pSMB->Reserved = 0;
3664 pSMB->Flags = 0;
3665 pSMB->Timeout = 0;
3666 pSMB->Reserved2 = 0;
3667 pSMB->ParameterOffset = cpu_to_le16(
3668 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3669 pSMB->DataCount = 0;
3670 pSMB->DataOffset = 0;
3671 pSMB->SetupCount = 1;
3672 pSMB->Reserved3 = 0;
3673 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3674 pSMB->SearchHandle = searchHandle; /* always kept as le */
3675 pSMB->SearchCount =
3676 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3677 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3678 pSMB->ResumeKey = psrch_inf->resume_key;
3679 pSMB->SearchFlags =
3680 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3682 name_len = psrch_inf->resume_name_len;
3683 params += name_len;
3684 if (name_len < PATH_MAX) {
3685 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3686 byte_count += name_len;
3687 /* 14 byte parm len above enough for 2 byte null terminator */
3688 pSMB->ResumeFileName[name_len] = 0;
3689 pSMB->ResumeFileName[name_len+1] = 0;
3690 } else {
3691 rc = -EINVAL;
3692 goto FNext2_err_exit;
3694 byte_count = params + 1 /* pad */ ;
3695 pSMB->TotalParameterCount = cpu_to_le16(params);
3696 pSMB->ParameterCount = pSMB->TotalParameterCount;
3697 pSMB->hdr.smb_buf_length += byte_count;
3698 pSMB->ByteCount = cpu_to_le16(byte_count);
3700 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3701 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3702 cifs_stats_inc(&tcon->num_fnext);
3703 if (rc) {
3704 if (rc == -EBADF) {
3705 psrch_inf->endOfSearch = true;
3706 cifs_buf_release(pSMB);
3707 rc = 0; /* search probably was closed at end of search*/
3708 } else
3709 cFYI(1, ("FindNext returned = %d", rc));
3710 } else { /* decode response */
3711 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3713 if (rc == 0) {
3714 unsigned int lnoff;
3716 /* BB fixme add lock for file (srch_info) struct here */
3717 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3718 psrch_inf->unicode = true;
3719 else
3720 psrch_inf->unicode = false;
3721 response_data = (char *) &pSMBr->hdr.Protocol +
3722 le16_to_cpu(pSMBr->t2.ParameterOffset);
3723 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3724 response_data = (char *)&pSMBr->hdr.Protocol +
3725 le16_to_cpu(pSMBr->t2.DataOffset);
3726 if (psrch_inf->smallBuf)
3727 cifs_small_buf_release(
3728 psrch_inf->ntwrk_buf_start);
3729 else
3730 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3731 psrch_inf->srch_entries_start = response_data;
3732 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3733 psrch_inf->smallBuf = 0;
3734 if (parms->EndofSearch)
3735 psrch_inf->endOfSearch = true;
3736 else
3737 psrch_inf->endOfSearch = false;
3738 psrch_inf->entries_in_buffer =
3739 le16_to_cpu(parms->SearchCount);
3740 psrch_inf->index_of_last_entry +=
3741 psrch_inf->entries_in_buffer;
3742 lnoff = le16_to_cpu(parms->LastNameOffset);
3743 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3744 lnoff) {
3745 cERROR(1, ("ignoring corrupt resume name"));
3746 psrch_inf->last_entry = NULL;
3747 return rc;
3748 } else
3749 psrch_inf->last_entry =
3750 psrch_inf->srch_entries_start + lnoff;
3752 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3753 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3755 /* BB fixme add unlock here */
3760 /* BB On error, should we leave previous search buf (and count and
3761 last entry fields) intact or free the previous one? */
3763 /* Note: On -EAGAIN error only caller can retry on handle based calls
3764 since file handle passed in no longer valid */
3765 FNext2_err_exit:
3766 if (rc != 0)
3767 cifs_buf_release(pSMB);
3768 return rc;
3772 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3773 const __u16 searchHandle)
3775 int rc = 0;
3776 FINDCLOSE_REQ *pSMB = NULL;
3778 cFYI(1, ("In CIFSSMBFindClose"));
3779 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3781 /* no sense returning error if session restarted
3782 as file handle has been closed */
3783 if (rc == -EAGAIN)
3784 return 0;
3785 if (rc)
3786 return rc;
3788 pSMB->FileID = searchHandle;
3789 pSMB->ByteCount = 0;
3790 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3791 if (rc)
3792 cERROR(1, ("Send error in FindClose = %d", rc));
3794 cifs_stats_inc(&tcon->num_fclose);
3796 /* Since session is dead, search handle closed on server already */
3797 if (rc == -EAGAIN)
3798 rc = 0;
3800 return rc;
3804 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3805 const unsigned char *searchName,
3806 __u64 *inode_number,
3807 const struct nls_table *nls_codepage, int remap)
3809 int rc = 0;
3810 TRANSACTION2_QPI_REQ *pSMB = NULL;
3811 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3812 int name_len, bytes_returned;
3813 __u16 params, byte_count;
3815 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3816 if (tcon == NULL)
3817 return -ENODEV;
3819 GetInodeNumberRetry:
3820 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3821 (void **) &pSMBr);
3822 if (rc)
3823 return rc;
3825 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3826 name_len =
3827 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3828 PATH_MAX, nls_codepage, remap);
3829 name_len++; /* trailing null */
3830 name_len *= 2;
3831 } else { /* BB improve the check for buffer overruns BB */
3832 name_len = strnlen(searchName, PATH_MAX);
3833 name_len++; /* trailing null */
3834 strncpy(pSMB->FileName, searchName, name_len);
3837 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3838 pSMB->TotalDataCount = 0;
3839 pSMB->MaxParameterCount = cpu_to_le16(2);
3840 /* BB find exact max data count below from sess structure BB */
3841 pSMB->MaxDataCount = cpu_to_le16(4000);
3842 pSMB->MaxSetupCount = 0;
3843 pSMB->Reserved = 0;
3844 pSMB->Flags = 0;
3845 pSMB->Timeout = 0;
3846 pSMB->Reserved2 = 0;
3847 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3848 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3849 pSMB->DataCount = 0;
3850 pSMB->DataOffset = 0;
3851 pSMB->SetupCount = 1;
3852 pSMB->Reserved3 = 0;
3853 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3854 byte_count = params + 1 /* pad */ ;
3855 pSMB->TotalParameterCount = cpu_to_le16(params);
3856 pSMB->ParameterCount = pSMB->TotalParameterCount;
3857 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3858 pSMB->Reserved4 = 0;
3859 pSMB->hdr.smb_buf_length += byte_count;
3860 pSMB->ByteCount = cpu_to_le16(byte_count);
3862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3864 if (rc) {
3865 cFYI(1, ("error %d in QueryInternalInfo", rc));
3866 } else {
3867 /* decode response */
3868 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3869 if (rc || (pSMBr->ByteCount < 2))
3870 /* BB also check enough total bytes returned */
3871 /* If rc should we check for EOPNOSUPP and
3872 disable the srvino flag? or in caller? */
3873 rc = -EIO; /* bad smb */
3874 else {
3875 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3876 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3877 struct file_internal_info *pfinfo;
3878 /* BB Do we need a cast or hash here ? */
3879 if (count < 8) {
3880 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3881 rc = -EIO;
3882 goto GetInodeNumOut;
3884 pfinfo = (struct file_internal_info *)
3885 (data_offset + (char *) &pSMBr->hdr.Protocol);
3886 *inode_number = le64_to_cpu(pfinfo->UniqueId);
3889 GetInodeNumOut:
3890 cifs_buf_release(pSMB);
3891 if (rc == -EAGAIN)
3892 goto GetInodeNumberRetry;
3893 return rc;
3896 /* parses DFS refferal V3 structure
3897 * caller is responsible for freeing target_nodes
3898 * returns:
3899 * on success - 0
3900 * on failure - errno
3902 static int
3903 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3904 unsigned int *num_of_nodes,
3905 struct dfs_info3_param **target_nodes,
3906 const struct nls_table *nls_codepage, int remap,
3907 const char *searchName)
3909 int i, rc = 0;
3910 char *data_end;
3911 bool is_unicode;
3912 struct dfs_referral_level_3 *ref;
3914 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3915 is_unicode = true;
3916 else
3917 is_unicode = false;
3918 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3920 if (*num_of_nodes < 1) {
3921 cERROR(1, ("num_referrals: must be at least > 0,"
3922 "but we get num_referrals = %d\n", *num_of_nodes));
3923 rc = -EINVAL;
3924 goto parse_DFS_referrals_exit;
3927 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3928 if (ref->VersionNumber != cpu_to_le16(3)) {
3929 cERROR(1, ("Referrals of V%d version are not supported,"
3930 "should be V3", le16_to_cpu(ref->VersionNumber)));
3931 rc = -EINVAL;
3932 goto parse_DFS_referrals_exit;
3935 /* get the upper boundary of the resp buffer */
3936 data_end = (char *)(&(pSMBr->PathConsumed)) +
3937 le16_to_cpu(pSMBr->t2.DataCount);
3939 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3940 *num_of_nodes,
3941 le32_to_cpu(pSMBr->DFSFlags)));
3943 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3944 *num_of_nodes, GFP_KERNEL);
3945 if (*target_nodes == NULL) {
3946 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3947 rc = -ENOMEM;
3948 goto parse_DFS_referrals_exit;
3951 /* collect neccessary data from referrals */
3952 for (i = 0; i < *num_of_nodes; i++) {
3953 char *temp;
3954 int max_len;
3955 struct dfs_info3_param *node = (*target_nodes)+i;
3957 node->flags = le32_to_cpu(pSMBr->DFSFlags);
3958 if (is_unicode) {
3959 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3960 GFP_KERNEL);
3961 cifsConvertToUCS((__le16 *) tmp, searchName,
3962 PATH_MAX, nls_codepage, remap);
3963 node->path_consumed = cifs_ucs2_bytes(tmp,
3964 le16_to_cpu(pSMBr->PathConsumed),
3965 nls_codepage);
3966 kfree(tmp);
3967 } else
3968 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3970 node->server_type = le16_to_cpu(ref->ServerType);
3971 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3973 /* copy DfsPath */
3974 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3975 max_len = data_end - temp;
3976 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3977 is_unicode, nls_codepage);
3978 if (!node->path_name) {
3979 rc = -ENOMEM;
3980 goto parse_DFS_referrals_exit;
3983 /* copy link target UNC */
3984 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3985 max_len = data_end - temp;
3986 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3987 is_unicode, nls_codepage);
3988 if (!node->node_name)
3989 rc = -ENOMEM;
3992 parse_DFS_referrals_exit:
3993 if (rc) {
3994 free_dfs_info_array(*target_nodes, *num_of_nodes);
3995 *target_nodes = NULL;
3996 *num_of_nodes = 0;
3998 return rc;
4002 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4003 const unsigned char *searchName,
4004 struct dfs_info3_param **target_nodes,
4005 unsigned int *num_of_nodes,
4006 const struct nls_table *nls_codepage, int remap)
4008 /* TRANS2_GET_DFS_REFERRAL */
4009 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4010 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4011 int rc = 0;
4012 int bytes_returned;
4013 int name_len;
4014 __u16 params, byte_count;
4015 *num_of_nodes = 0;
4016 *target_nodes = NULL;
4018 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4019 if (ses == NULL)
4020 return -ENODEV;
4021 getDFSRetry:
4022 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4023 (void **) &pSMBr);
4024 if (rc)
4025 return rc;
4027 /* server pointer checked in called function,
4028 but should never be null here anyway */
4029 pSMB->hdr.Mid = GetNextMid(ses->server);
4030 pSMB->hdr.Tid = ses->ipc_tid;
4031 pSMB->hdr.Uid = ses->Suid;
4032 if (ses->capabilities & CAP_STATUS32)
4033 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4034 if (ses->capabilities & CAP_DFS)
4035 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4037 if (ses->capabilities & CAP_UNICODE) {
4038 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4039 name_len =
4040 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
4041 searchName, PATH_MAX, nls_codepage, remap);
4042 name_len++; /* trailing null */
4043 name_len *= 2;
4044 } else { /* BB improve the check for buffer overruns BB */
4045 name_len = strnlen(searchName, PATH_MAX);
4046 name_len++; /* trailing null */
4047 strncpy(pSMB->RequestFileName, searchName, name_len);
4050 if (ses->server) {
4051 if (ses->server->secMode &
4052 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4053 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4056 pSMB->hdr.Uid = ses->Suid;
4058 params = 2 /* level */ + name_len /*includes null */ ;
4059 pSMB->TotalDataCount = 0;
4060 pSMB->DataCount = 0;
4061 pSMB->DataOffset = 0;
4062 pSMB->MaxParameterCount = 0;
4063 /* BB find exact max SMB PDU from sess structure BB */
4064 pSMB->MaxDataCount = cpu_to_le16(4000);
4065 pSMB->MaxSetupCount = 0;
4066 pSMB->Reserved = 0;
4067 pSMB->Flags = 0;
4068 pSMB->Timeout = 0;
4069 pSMB->Reserved2 = 0;
4070 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4071 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4072 pSMB->SetupCount = 1;
4073 pSMB->Reserved3 = 0;
4074 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4075 byte_count = params + 3 /* pad */ ;
4076 pSMB->ParameterCount = cpu_to_le16(params);
4077 pSMB->TotalParameterCount = pSMB->ParameterCount;
4078 pSMB->MaxReferralLevel = cpu_to_le16(3);
4079 pSMB->hdr.smb_buf_length += byte_count;
4080 pSMB->ByteCount = cpu_to_le16(byte_count);
4082 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4084 if (rc) {
4085 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4086 goto GetDFSRefExit;
4088 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4090 /* BB Also check if enough total bytes returned? */
4091 if (rc || (pSMBr->ByteCount < 17)) {
4092 rc = -EIO; /* bad smb */
4093 goto GetDFSRefExit;
4096 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4097 pSMBr->ByteCount,
4098 le16_to_cpu(pSMBr->t2.DataOffset)));
4100 /* parse returned result into more usable form */
4101 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
4102 target_nodes, nls_codepage, remap,
4103 searchName);
4105 GetDFSRefExit:
4106 cifs_buf_release(pSMB);
4108 if (rc == -EAGAIN)
4109 goto getDFSRetry;
4111 return rc;
4114 /* Query File System Info such as free space to old servers such as Win 9x */
4116 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4118 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4119 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4120 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4121 FILE_SYSTEM_ALLOC_INFO *response_data;
4122 int rc = 0;
4123 int bytes_returned = 0;
4124 __u16 params, byte_count;
4126 cFYI(1, ("OldQFSInfo"));
4127 oldQFSInfoRetry:
4128 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4129 (void **) &pSMBr);
4130 if (rc)
4131 return rc;
4133 params = 2; /* level */
4134 pSMB->TotalDataCount = 0;
4135 pSMB->MaxParameterCount = cpu_to_le16(2);
4136 pSMB->MaxDataCount = cpu_to_le16(1000);
4137 pSMB->MaxSetupCount = 0;
4138 pSMB->Reserved = 0;
4139 pSMB->Flags = 0;
4140 pSMB->Timeout = 0;
4141 pSMB->Reserved2 = 0;
4142 byte_count = params + 1 /* pad */ ;
4143 pSMB->TotalParameterCount = cpu_to_le16(params);
4144 pSMB->ParameterCount = pSMB->TotalParameterCount;
4145 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4146 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4147 pSMB->DataCount = 0;
4148 pSMB->DataOffset = 0;
4149 pSMB->SetupCount = 1;
4150 pSMB->Reserved3 = 0;
4151 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4152 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4153 pSMB->hdr.smb_buf_length += byte_count;
4154 pSMB->ByteCount = cpu_to_le16(byte_count);
4156 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4157 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4158 if (rc) {
4159 cFYI(1, ("Send error in QFSInfo = %d", rc));
4160 } else { /* decode response */
4161 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4163 if (rc || (pSMBr->ByteCount < 18))
4164 rc = -EIO; /* bad smb */
4165 else {
4166 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4167 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4168 pSMBr->ByteCount, data_offset));
4170 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4171 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4172 FSData->f_bsize =
4173 le16_to_cpu(response_data->BytesPerSector) *
4174 le32_to_cpu(response_data->
4175 SectorsPerAllocationUnit);
4176 FSData->f_blocks =
4177 le32_to_cpu(response_data->TotalAllocationUnits);
4178 FSData->f_bfree = FSData->f_bavail =
4179 le32_to_cpu(response_data->FreeAllocationUnits);
4180 cFYI(1,
4181 ("Blocks: %lld Free: %lld Block size %ld",
4182 (unsigned long long)FSData->f_blocks,
4183 (unsigned long long)FSData->f_bfree,
4184 FSData->f_bsize));
4187 cifs_buf_release(pSMB);
4189 if (rc == -EAGAIN)
4190 goto oldQFSInfoRetry;
4192 return rc;
4196 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4198 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4199 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4200 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4201 FILE_SYSTEM_INFO *response_data;
4202 int rc = 0;
4203 int bytes_returned = 0;
4204 __u16 params, byte_count;
4206 cFYI(1, ("In QFSInfo"));
4207 QFSInfoRetry:
4208 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4209 (void **) &pSMBr);
4210 if (rc)
4211 return rc;
4213 params = 2; /* level */
4214 pSMB->TotalDataCount = 0;
4215 pSMB->MaxParameterCount = cpu_to_le16(2);
4216 pSMB->MaxDataCount = cpu_to_le16(1000);
4217 pSMB->MaxSetupCount = 0;
4218 pSMB->Reserved = 0;
4219 pSMB->Flags = 0;
4220 pSMB->Timeout = 0;
4221 pSMB->Reserved2 = 0;
4222 byte_count = params + 1 /* pad */ ;
4223 pSMB->TotalParameterCount = cpu_to_le16(params);
4224 pSMB->ParameterCount = pSMB->TotalParameterCount;
4225 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4226 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4227 pSMB->DataCount = 0;
4228 pSMB->DataOffset = 0;
4229 pSMB->SetupCount = 1;
4230 pSMB->Reserved3 = 0;
4231 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4232 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4233 pSMB->hdr.smb_buf_length += byte_count;
4234 pSMB->ByteCount = cpu_to_le16(byte_count);
4236 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4237 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4238 if (rc) {
4239 cFYI(1, ("Send error in QFSInfo = %d", rc));
4240 } else { /* decode response */
4241 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4243 if (rc || (pSMBr->ByteCount < 24))
4244 rc = -EIO; /* bad smb */
4245 else {
4246 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4248 response_data =
4249 (FILE_SYSTEM_INFO
4250 *) (((char *) &pSMBr->hdr.Protocol) +
4251 data_offset);
4252 FSData->f_bsize =
4253 le32_to_cpu(response_data->BytesPerSector) *
4254 le32_to_cpu(response_data->
4255 SectorsPerAllocationUnit);
4256 FSData->f_blocks =
4257 le64_to_cpu(response_data->TotalAllocationUnits);
4258 FSData->f_bfree = FSData->f_bavail =
4259 le64_to_cpu(response_data->FreeAllocationUnits);
4260 cFYI(1,
4261 ("Blocks: %lld Free: %lld Block size %ld",
4262 (unsigned long long)FSData->f_blocks,
4263 (unsigned long long)FSData->f_bfree,
4264 FSData->f_bsize));
4267 cifs_buf_release(pSMB);
4269 if (rc == -EAGAIN)
4270 goto QFSInfoRetry;
4272 return rc;
4276 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4278 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4279 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4280 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4281 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4282 int rc = 0;
4283 int bytes_returned = 0;
4284 __u16 params, byte_count;
4286 cFYI(1, ("In QFSAttributeInfo"));
4287 QFSAttributeRetry:
4288 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4289 (void **) &pSMBr);
4290 if (rc)
4291 return rc;
4293 params = 2; /* level */
4294 pSMB->TotalDataCount = 0;
4295 pSMB->MaxParameterCount = cpu_to_le16(2);
4296 /* BB find exact max SMB PDU from sess structure BB */
4297 pSMB->MaxDataCount = cpu_to_le16(1000);
4298 pSMB->MaxSetupCount = 0;
4299 pSMB->Reserved = 0;
4300 pSMB->Flags = 0;
4301 pSMB->Timeout = 0;
4302 pSMB->Reserved2 = 0;
4303 byte_count = params + 1 /* pad */ ;
4304 pSMB->TotalParameterCount = cpu_to_le16(params);
4305 pSMB->ParameterCount = pSMB->TotalParameterCount;
4306 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4307 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4308 pSMB->DataCount = 0;
4309 pSMB->DataOffset = 0;
4310 pSMB->SetupCount = 1;
4311 pSMB->Reserved3 = 0;
4312 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4313 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4314 pSMB->hdr.smb_buf_length += byte_count;
4315 pSMB->ByteCount = cpu_to_le16(byte_count);
4317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4318 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4319 if (rc) {
4320 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4321 } else { /* decode response */
4322 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4324 if (rc || (pSMBr->ByteCount < 13)) {
4325 /* BB also check if enough bytes returned */
4326 rc = -EIO; /* bad smb */
4327 } else {
4328 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4329 response_data =
4330 (FILE_SYSTEM_ATTRIBUTE_INFO
4331 *) (((char *) &pSMBr->hdr.Protocol) +
4332 data_offset);
4333 memcpy(&tcon->fsAttrInfo, response_data,
4334 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4337 cifs_buf_release(pSMB);
4339 if (rc == -EAGAIN)
4340 goto QFSAttributeRetry;
4342 return rc;
4346 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4348 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4349 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4350 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4351 FILE_SYSTEM_DEVICE_INFO *response_data;
4352 int rc = 0;
4353 int bytes_returned = 0;
4354 __u16 params, byte_count;
4356 cFYI(1, ("In QFSDeviceInfo"));
4357 QFSDeviceRetry:
4358 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4359 (void **) &pSMBr);
4360 if (rc)
4361 return rc;
4363 params = 2; /* level */
4364 pSMB->TotalDataCount = 0;
4365 pSMB->MaxParameterCount = cpu_to_le16(2);
4366 /* BB find exact max SMB PDU from sess structure BB */
4367 pSMB->MaxDataCount = cpu_to_le16(1000);
4368 pSMB->MaxSetupCount = 0;
4369 pSMB->Reserved = 0;
4370 pSMB->Flags = 0;
4371 pSMB->Timeout = 0;
4372 pSMB->Reserved2 = 0;
4373 byte_count = params + 1 /* pad */ ;
4374 pSMB->TotalParameterCount = cpu_to_le16(params);
4375 pSMB->ParameterCount = pSMB->TotalParameterCount;
4376 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4377 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4379 pSMB->DataCount = 0;
4380 pSMB->DataOffset = 0;
4381 pSMB->SetupCount = 1;
4382 pSMB->Reserved3 = 0;
4383 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4384 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4385 pSMB->hdr.smb_buf_length += byte_count;
4386 pSMB->ByteCount = cpu_to_le16(byte_count);
4388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4389 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4390 if (rc) {
4391 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4392 } else { /* decode response */
4393 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4395 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4396 rc = -EIO; /* bad smb */
4397 else {
4398 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4399 response_data =
4400 (FILE_SYSTEM_DEVICE_INFO *)
4401 (((char *) &pSMBr->hdr.Protocol) +
4402 data_offset);
4403 memcpy(&tcon->fsDevInfo, response_data,
4404 sizeof(FILE_SYSTEM_DEVICE_INFO));
4407 cifs_buf_release(pSMB);
4409 if (rc == -EAGAIN)
4410 goto QFSDeviceRetry;
4412 return rc;
4416 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4418 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4419 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4420 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4421 FILE_SYSTEM_UNIX_INFO *response_data;
4422 int rc = 0;
4423 int bytes_returned = 0;
4424 __u16 params, byte_count;
4426 cFYI(1, ("In QFSUnixInfo"));
4427 QFSUnixRetry:
4428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429 (void **) &pSMBr);
4430 if (rc)
4431 return rc;
4433 params = 2; /* level */
4434 pSMB->TotalDataCount = 0;
4435 pSMB->DataCount = 0;
4436 pSMB->DataOffset = 0;
4437 pSMB->MaxParameterCount = cpu_to_le16(2);
4438 /* BB find exact max SMB PDU from sess structure BB */
4439 pSMB->MaxDataCount = cpu_to_le16(100);
4440 pSMB->MaxSetupCount = 0;
4441 pSMB->Reserved = 0;
4442 pSMB->Flags = 0;
4443 pSMB->Timeout = 0;
4444 pSMB->Reserved2 = 0;
4445 byte_count = params + 1 /* pad */ ;
4446 pSMB->ParameterCount = cpu_to_le16(params);
4447 pSMB->TotalParameterCount = pSMB->ParameterCount;
4448 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4449 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4450 pSMB->SetupCount = 1;
4451 pSMB->Reserved3 = 0;
4452 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4453 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4454 pSMB->hdr.smb_buf_length += byte_count;
4455 pSMB->ByteCount = cpu_to_le16(byte_count);
4457 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4458 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4459 if (rc) {
4460 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4461 } else { /* decode response */
4462 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4464 if (rc || (pSMBr->ByteCount < 13)) {
4465 rc = -EIO; /* bad smb */
4466 } else {
4467 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4468 response_data =
4469 (FILE_SYSTEM_UNIX_INFO
4470 *) (((char *) &pSMBr->hdr.Protocol) +
4471 data_offset);
4472 memcpy(&tcon->fsUnixInfo, response_data,
4473 sizeof(FILE_SYSTEM_UNIX_INFO));
4476 cifs_buf_release(pSMB);
4478 if (rc == -EAGAIN)
4479 goto QFSUnixRetry;
4482 return rc;
4486 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4488 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4489 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4490 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4491 int rc = 0;
4492 int bytes_returned = 0;
4493 __u16 params, param_offset, offset, byte_count;
4495 cFYI(1, ("In SETFSUnixInfo"));
4496 SETFSUnixRetry:
4497 /* BB switch to small buf init to save memory */
4498 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4499 (void **) &pSMBr);
4500 if (rc)
4501 return rc;
4503 params = 4; /* 2 bytes zero followed by info level. */
4504 pSMB->MaxSetupCount = 0;
4505 pSMB->Reserved = 0;
4506 pSMB->Flags = 0;
4507 pSMB->Timeout = 0;
4508 pSMB->Reserved2 = 0;
4509 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4510 - 4;
4511 offset = param_offset + params;
4513 pSMB->MaxParameterCount = cpu_to_le16(4);
4514 /* BB find exact max SMB PDU from sess structure BB */
4515 pSMB->MaxDataCount = cpu_to_le16(100);
4516 pSMB->SetupCount = 1;
4517 pSMB->Reserved3 = 0;
4518 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4519 byte_count = 1 /* pad */ + params + 12;
4521 pSMB->DataCount = cpu_to_le16(12);
4522 pSMB->ParameterCount = cpu_to_le16(params);
4523 pSMB->TotalDataCount = pSMB->DataCount;
4524 pSMB->TotalParameterCount = pSMB->ParameterCount;
4525 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4526 pSMB->DataOffset = cpu_to_le16(offset);
4528 /* Params. */
4529 pSMB->FileNum = 0;
4530 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4532 /* Data. */
4533 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4534 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4535 pSMB->ClientUnixCap = cpu_to_le64(cap);
4537 pSMB->hdr.smb_buf_length += byte_count;
4538 pSMB->ByteCount = cpu_to_le16(byte_count);
4540 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4541 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4542 if (rc) {
4543 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4544 } else { /* decode response */
4545 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4546 if (rc)
4547 rc = -EIO; /* bad smb */
4549 cifs_buf_release(pSMB);
4551 if (rc == -EAGAIN)
4552 goto SETFSUnixRetry;
4554 return rc;
4560 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4561 struct kstatfs *FSData)
4563 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4564 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4565 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4566 FILE_SYSTEM_POSIX_INFO *response_data;
4567 int rc = 0;
4568 int bytes_returned = 0;
4569 __u16 params, byte_count;
4571 cFYI(1, ("In QFSPosixInfo"));
4572 QFSPosixRetry:
4573 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4574 (void **) &pSMBr);
4575 if (rc)
4576 return rc;
4578 params = 2; /* level */
4579 pSMB->TotalDataCount = 0;
4580 pSMB->DataCount = 0;
4581 pSMB->DataOffset = 0;
4582 pSMB->MaxParameterCount = cpu_to_le16(2);
4583 /* BB find exact max SMB PDU from sess structure BB */
4584 pSMB->MaxDataCount = cpu_to_le16(100);
4585 pSMB->MaxSetupCount = 0;
4586 pSMB->Reserved = 0;
4587 pSMB->Flags = 0;
4588 pSMB->Timeout = 0;
4589 pSMB->Reserved2 = 0;
4590 byte_count = params + 1 /* pad */ ;
4591 pSMB->ParameterCount = cpu_to_le16(params);
4592 pSMB->TotalParameterCount = pSMB->ParameterCount;
4593 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4594 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4595 pSMB->SetupCount = 1;
4596 pSMB->Reserved3 = 0;
4597 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4598 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4599 pSMB->hdr.smb_buf_length += byte_count;
4600 pSMB->ByteCount = cpu_to_le16(byte_count);
4602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4604 if (rc) {
4605 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4606 } else { /* decode response */
4607 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4609 if (rc || (pSMBr->ByteCount < 13)) {
4610 rc = -EIO; /* bad smb */
4611 } else {
4612 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4613 response_data =
4614 (FILE_SYSTEM_POSIX_INFO
4615 *) (((char *) &pSMBr->hdr.Protocol) +
4616 data_offset);
4617 FSData->f_bsize =
4618 le32_to_cpu(response_data->BlockSize);
4619 FSData->f_blocks =
4620 le64_to_cpu(response_data->TotalBlocks);
4621 FSData->f_bfree =
4622 le64_to_cpu(response_data->BlocksAvail);
4623 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4624 FSData->f_bavail = FSData->f_bfree;
4625 } else {
4626 FSData->f_bavail =
4627 le64_to_cpu(response_data->UserBlocksAvail);
4629 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4630 FSData->f_files =
4631 le64_to_cpu(response_data->TotalFileNodes);
4632 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4633 FSData->f_ffree =
4634 le64_to_cpu(response_data->FreeFileNodes);
4637 cifs_buf_release(pSMB);
4639 if (rc == -EAGAIN)
4640 goto QFSPosixRetry;
4642 return rc;
4646 /* We can not use write of zero bytes trick to
4647 set file size due to need for large file support. Also note that
4648 this SetPathInfo is preferred to SetFileInfo based method in next
4649 routine which is only needed to work around a sharing violation bug
4650 in Samba which this routine can run into */
4653 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4654 __u64 size, bool SetAllocation,
4655 const struct nls_table *nls_codepage, int remap)
4657 struct smb_com_transaction2_spi_req *pSMB = NULL;
4658 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4659 struct file_end_of_file_info *parm_data;
4660 int name_len;
4661 int rc = 0;
4662 int bytes_returned = 0;
4663 __u16 params, byte_count, data_count, param_offset, offset;
4665 cFYI(1, ("In SetEOF"));
4666 SetEOFRetry:
4667 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4668 (void **) &pSMBr);
4669 if (rc)
4670 return rc;
4672 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4673 name_len =
4674 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4675 PATH_MAX, nls_codepage, remap);
4676 name_len++; /* trailing null */
4677 name_len *= 2;
4678 } else { /* BB improve the check for buffer overruns BB */
4679 name_len = strnlen(fileName, PATH_MAX);
4680 name_len++; /* trailing null */
4681 strncpy(pSMB->FileName, fileName, name_len);
4683 params = 6 + name_len;
4684 data_count = sizeof(struct file_end_of_file_info);
4685 pSMB->MaxParameterCount = cpu_to_le16(2);
4686 pSMB->MaxDataCount = cpu_to_le16(4100);
4687 pSMB->MaxSetupCount = 0;
4688 pSMB->Reserved = 0;
4689 pSMB->Flags = 0;
4690 pSMB->Timeout = 0;
4691 pSMB->Reserved2 = 0;
4692 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4693 InformationLevel) - 4;
4694 offset = param_offset + params;
4695 if (SetAllocation) {
4696 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4697 pSMB->InformationLevel =
4698 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4699 else
4700 pSMB->InformationLevel =
4701 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4702 } else /* Set File Size */ {
4703 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4704 pSMB->InformationLevel =
4705 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4706 else
4707 pSMB->InformationLevel =
4708 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4711 parm_data =
4712 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4713 offset);
4714 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4715 pSMB->DataOffset = cpu_to_le16(offset);
4716 pSMB->SetupCount = 1;
4717 pSMB->Reserved3 = 0;
4718 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4719 byte_count = 3 /* pad */ + params + data_count;
4720 pSMB->DataCount = cpu_to_le16(data_count);
4721 pSMB->TotalDataCount = pSMB->DataCount;
4722 pSMB->ParameterCount = cpu_to_le16(params);
4723 pSMB->TotalParameterCount = pSMB->ParameterCount;
4724 pSMB->Reserved4 = 0;
4725 pSMB->hdr.smb_buf_length += byte_count;
4726 parm_data->FileSize = cpu_to_le64(size);
4727 pSMB->ByteCount = cpu_to_le16(byte_count);
4728 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4729 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4730 if (rc)
4731 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4733 cifs_buf_release(pSMB);
4735 if (rc == -EAGAIN)
4736 goto SetEOFRetry;
4738 return rc;
4742 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4743 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4745 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4746 char *data_offset;
4747 struct file_end_of_file_info *parm_data;
4748 int rc = 0;
4749 __u16 params, param_offset, offset, byte_count, count;
4751 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4752 (long long)size));
4753 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4755 if (rc)
4756 return rc;
4758 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4759 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4761 params = 6;
4762 pSMB->MaxSetupCount = 0;
4763 pSMB->Reserved = 0;
4764 pSMB->Flags = 0;
4765 pSMB->Timeout = 0;
4766 pSMB->Reserved2 = 0;
4767 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4768 offset = param_offset + params;
4770 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4772 count = sizeof(struct file_end_of_file_info);
4773 pSMB->MaxParameterCount = cpu_to_le16(2);
4774 /* BB find exact max SMB PDU from sess structure BB */
4775 pSMB->MaxDataCount = cpu_to_le16(1000);
4776 pSMB->SetupCount = 1;
4777 pSMB->Reserved3 = 0;
4778 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4779 byte_count = 3 /* pad */ + params + count;
4780 pSMB->DataCount = cpu_to_le16(count);
4781 pSMB->ParameterCount = cpu_to_le16(params);
4782 pSMB->TotalDataCount = pSMB->DataCount;
4783 pSMB->TotalParameterCount = pSMB->ParameterCount;
4784 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4785 parm_data =
4786 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4787 + offset);
4788 pSMB->DataOffset = cpu_to_le16(offset);
4789 parm_data->FileSize = cpu_to_le64(size);
4790 pSMB->Fid = fid;
4791 if (SetAllocation) {
4792 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4793 pSMB->InformationLevel =
4794 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4795 else
4796 pSMB->InformationLevel =
4797 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4798 } else /* Set File Size */ {
4799 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4800 pSMB->InformationLevel =
4801 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4802 else
4803 pSMB->InformationLevel =
4804 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4806 pSMB->Reserved4 = 0;
4807 pSMB->hdr.smb_buf_length += byte_count;
4808 pSMB->ByteCount = cpu_to_le16(byte_count);
4809 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4810 if (rc) {
4811 cFYI(1,
4812 ("Send error in SetFileInfo (SetFileSize) = %d",
4813 rc));
4816 /* Note: On -EAGAIN error only caller can retry on handle based calls
4817 since file handle passed in no longer valid */
4819 return rc;
4822 /* Some legacy servers such as NT4 require that the file times be set on
4823 an open handle, rather than by pathname - this is awkward due to
4824 potential access conflicts on the open, but it is unavoidable for these
4825 old servers since the only other choice is to go from 100 nanosecond DCE
4826 time and resort to the original setpathinfo level which takes the ancient
4827 DOS time format with 2 second granularity */
4829 CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4830 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4832 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4833 char *data_offset;
4834 int rc = 0;
4835 __u16 params, param_offset, offset, byte_count, count;
4837 cFYI(1, ("Set Times (via SetFileInfo)"));
4838 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4840 if (rc)
4841 return rc;
4843 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4844 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4846 params = 6;
4847 pSMB->MaxSetupCount = 0;
4848 pSMB->Reserved = 0;
4849 pSMB->Flags = 0;
4850 pSMB->Timeout = 0;
4851 pSMB->Reserved2 = 0;
4852 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4853 offset = param_offset + params;
4855 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4857 count = sizeof(FILE_BASIC_INFO);
4858 pSMB->MaxParameterCount = cpu_to_le16(2);
4859 /* BB find max SMB PDU from sess */
4860 pSMB->MaxDataCount = cpu_to_le16(1000);
4861 pSMB->SetupCount = 1;
4862 pSMB->Reserved3 = 0;
4863 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4864 byte_count = 3 /* pad */ + params + count;
4865 pSMB->DataCount = cpu_to_le16(count);
4866 pSMB->ParameterCount = cpu_to_le16(params);
4867 pSMB->TotalDataCount = pSMB->DataCount;
4868 pSMB->TotalParameterCount = pSMB->ParameterCount;
4869 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4870 pSMB->DataOffset = cpu_to_le16(offset);
4871 pSMB->Fid = fid;
4872 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4873 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4874 else
4875 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4876 pSMB->Reserved4 = 0;
4877 pSMB->hdr.smb_buf_length += byte_count;
4878 pSMB->ByteCount = cpu_to_le16(byte_count);
4879 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4880 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4881 if (rc)
4882 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4884 /* Note: On -EAGAIN error only caller can retry on handle based calls
4885 since file handle passed in no longer valid */
4887 return rc;
4891 CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4892 bool delete_file, __u16 fid, __u32 pid_of_opener)
4894 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4895 char *data_offset;
4896 int rc = 0;
4897 __u16 params, param_offset, offset, byte_count, count;
4899 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4900 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4902 if (rc)
4903 return rc;
4905 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4906 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4908 params = 6;
4909 pSMB->MaxSetupCount = 0;
4910 pSMB->Reserved = 0;
4911 pSMB->Flags = 0;
4912 pSMB->Timeout = 0;
4913 pSMB->Reserved2 = 0;
4914 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4915 offset = param_offset + params;
4917 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4919 count = 1;
4920 pSMB->MaxParameterCount = cpu_to_le16(2);
4921 /* BB find max SMB PDU from sess */
4922 pSMB->MaxDataCount = cpu_to_le16(1000);
4923 pSMB->SetupCount = 1;
4924 pSMB->Reserved3 = 0;
4925 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4926 byte_count = 3 /* pad */ + params + count;
4927 pSMB->DataCount = cpu_to_le16(count);
4928 pSMB->ParameterCount = cpu_to_le16(params);
4929 pSMB->TotalDataCount = pSMB->DataCount;
4930 pSMB->TotalParameterCount = pSMB->ParameterCount;
4931 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4932 pSMB->DataOffset = cpu_to_le16(offset);
4933 pSMB->Fid = fid;
4934 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4935 pSMB->Reserved4 = 0;
4936 pSMB->hdr.smb_buf_length += byte_count;
4937 pSMB->ByteCount = cpu_to_le16(byte_count);
4938 *data_offset = delete_file ? 1 : 0;
4939 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4940 if (rc)
4941 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4943 return rc;
4947 CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4948 const char *fileName, const FILE_BASIC_INFO *data,
4949 const struct nls_table *nls_codepage, int remap)
4951 TRANSACTION2_SPI_REQ *pSMB = NULL;
4952 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4953 int name_len;
4954 int rc = 0;
4955 int bytes_returned = 0;
4956 char *data_offset;
4957 __u16 params, param_offset, offset, byte_count, count;
4959 cFYI(1, ("In SetTimes"));
4961 SetTimesRetry:
4962 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4963 (void **) &pSMBr);
4964 if (rc)
4965 return rc;
4967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4968 name_len =
4969 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4970 PATH_MAX, nls_codepage, remap);
4971 name_len++; /* trailing null */
4972 name_len *= 2;
4973 } else { /* BB improve the check for buffer overruns BB */
4974 name_len = strnlen(fileName, PATH_MAX);
4975 name_len++; /* trailing null */
4976 strncpy(pSMB->FileName, fileName, name_len);
4979 params = 6 + name_len;
4980 count = sizeof(FILE_BASIC_INFO);
4981 pSMB->MaxParameterCount = cpu_to_le16(2);
4982 /* BB find max SMB PDU from sess structure BB */
4983 pSMB->MaxDataCount = cpu_to_le16(1000);
4984 pSMB->MaxSetupCount = 0;
4985 pSMB->Reserved = 0;
4986 pSMB->Flags = 0;
4987 pSMB->Timeout = 0;
4988 pSMB->Reserved2 = 0;
4989 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4990 InformationLevel) - 4;
4991 offset = param_offset + params;
4992 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4993 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4994 pSMB->DataOffset = cpu_to_le16(offset);
4995 pSMB->SetupCount = 1;
4996 pSMB->Reserved3 = 0;
4997 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4998 byte_count = 3 /* pad */ + params + count;
5000 pSMB->DataCount = cpu_to_le16(count);
5001 pSMB->ParameterCount = cpu_to_le16(params);
5002 pSMB->TotalDataCount = pSMB->DataCount;
5003 pSMB->TotalParameterCount = pSMB->ParameterCount;
5004 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5005 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5006 else
5007 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5008 pSMB->Reserved4 = 0;
5009 pSMB->hdr.smb_buf_length += byte_count;
5010 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5011 pSMB->ByteCount = cpu_to_le16(byte_count);
5012 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5013 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5014 if (rc)
5015 cFYI(1, ("SetPathInfo (times) returned %d", rc));
5017 cifs_buf_release(pSMB);
5019 if (rc == -EAGAIN)
5020 goto SetTimesRetry;
5022 return rc;
5025 /* Can not be used to set time stamps yet (due to old DOS time format) */
5026 /* Can be used to set attributes */
5027 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5028 handling it anyway and NT4 was what we thought it would be needed for
5029 Do not delete it until we prove whether needed for Win9x though */
5031 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5032 __u16 dos_attrs, const struct nls_table *nls_codepage)
5034 SETATTR_REQ *pSMB = NULL;
5035 SETATTR_RSP *pSMBr = NULL;
5036 int rc = 0;
5037 int bytes_returned;
5038 int name_len;
5040 cFYI(1, ("In SetAttrLegacy"));
5042 SetAttrLgcyRetry:
5043 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5044 (void **) &pSMBr);
5045 if (rc)
5046 return rc;
5048 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5049 name_len =
5050 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
5051 PATH_MAX, nls_codepage);
5052 name_len++; /* trailing null */
5053 name_len *= 2;
5054 } else { /* BB improve the check for buffer overruns BB */
5055 name_len = strnlen(fileName, PATH_MAX);
5056 name_len++; /* trailing null */
5057 strncpy(pSMB->fileName, fileName, name_len);
5059 pSMB->attr = cpu_to_le16(dos_attrs);
5060 pSMB->BufferFormat = 0x04;
5061 pSMB->hdr.smb_buf_length += name_len + 1;
5062 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5063 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5064 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5065 if (rc)
5066 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5068 cifs_buf_release(pSMB);
5070 if (rc == -EAGAIN)
5071 goto SetAttrLgcyRetry;
5073 return rc;
5075 #endif /* temporarily unneeded SetAttr legacy function */
5078 CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5079 const struct cifs_unix_set_info_args *args,
5080 const struct nls_table *nls_codepage, int remap)
5082 TRANSACTION2_SPI_REQ *pSMB = NULL;
5083 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5084 int name_len;
5085 int rc = 0;
5086 int bytes_returned = 0;
5087 FILE_UNIX_BASIC_INFO *data_offset;
5088 __u16 params, param_offset, offset, count, byte_count;
5089 __u64 mode = args->mode;
5091 cFYI(1, ("In SetUID/GID/Mode"));
5092 setPermsRetry:
5093 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5094 (void **) &pSMBr);
5095 if (rc)
5096 return rc;
5098 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5099 name_len =
5100 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5101 PATH_MAX, nls_codepage, remap);
5102 name_len++; /* trailing null */
5103 name_len *= 2;
5104 } else { /* BB improve the check for buffer overruns BB */
5105 name_len = strnlen(fileName, PATH_MAX);
5106 name_len++; /* trailing null */
5107 strncpy(pSMB->FileName, fileName, name_len);
5110 params = 6 + name_len;
5111 count = sizeof(FILE_UNIX_BASIC_INFO);
5112 pSMB->MaxParameterCount = cpu_to_le16(2);
5113 /* BB find max SMB PDU from sess structure BB */
5114 pSMB->MaxDataCount = cpu_to_le16(1000);
5115 pSMB->MaxSetupCount = 0;
5116 pSMB->Reserved = 0;
5117 pSMB->Flags = 0;
5118 pSMB->Timeout = 0;
5119 pSMB->Reserved2 = 0;
5120 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5121 InformationLevel) - 4;
5122 offset = param_offset + params;
5123 data_offset =
5124 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5125 offset);
5126 memset(data_offset, 0, count);
5127 pSMB->DataOffset = cpu_to_le16(offset);
5128 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5129 pSMB->SetupCount = 1;
5130 pSMB->Reserved3 = 0;
5131 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5132 byte_count = 3 /* pad */ + params + count;
5133 pSMB->ParameterCount = cpu_to_le16(params);
5134 pSMB->DataCount = cpu_to_le16(count);
5135 pSMB->TotalParameterCount = pSMB->ParameterCount;
5136 pSMB->TotalDataCount = pSMB->DataCount;
5137 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5138 pSMB->Reserved4 = 0;
5139 pSMB->hdr.smb_buf_length += byte_count;
5140 /* Samba server ignores set of file size to zero due to bugs in some
5141 older clients, but we should be precise - we use SetFileSize to
5142 set file size and do not want to truncate file size to zero
5143 accidently as happened on one Samba server beta by putting
5144 zero instead of -1 here */
5145 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5146 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5147 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5148 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5149 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5150 data_offset->Uid = cpu_to_le64(args->uid);
5151 data_offset->Gid = cpu_to_le64(args->gid);
5152 /* better to leave device as zero when it is */
5153 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5154 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5155 data_offset->Permissions = cpu_to_le64(mode);
5157 if (S_ISREG(mode))
5158 data_offset->Type = cpu_to_le32(UNIX_FILE);
5159 else if (S_ISDIR(mode))
5160 data_offset->Type = cpu_to_le32(UNIX_DIR);
5161 else if (S_ISLNK(mode))
5162 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5163 else if (S_ISCHR(mode))
5164 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5165 else if (S_ISBLK(mode))
5166 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5167 else if (S_ISFIFO(mode))
5168 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5169 else if (S_ISSOCK(mode))
5170 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5173 pSMB->ByteCount = cpu_to_le16(byte_count);
5174 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5175 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5176 if (rc)
5177 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5179 cifs_buf_release(pSMB);
5180 if (rc == -EAGAIN)
5181 goto setPermsRetry;
5182 return rc;
5185 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5186 const int notify_subdirs, const __u16 netfid,
5187 __u32 filter, struct file *pfile, int multishot,
5188 const struct nls_table *nls_codepage)
5190 int rc = 0;
5191 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5192 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5193 struct dir_notify_req *dnotify_req;
5194 int bytes_returned;
5196 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5197 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5198 (void **) &pSMBr);
5199 if (rc)
5200 return rc;
5202 pSMB->TotalParameterCount = 0 ;
5203 pSMB->TotalDataCount = 0;
5204 pSMB->MaxParameterCount = cpu_to_le32(2);
5205 /* BB find exact data count max from sess structure BB */
5206 pSMB->MaxDataCount = 0; /* same in little endian or be */
5207 /* BB VERIFY verify which is correct for above BB */
5208 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5209 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5211 pSMB->MaxSetupCount = 4;
5212 pSMB->Reserved = 0;
5213 pSMB->ParameterOffset = 0;
5214 pSMB->DataCount = 0;
5215 pSMB->DataOffset = 0;
5216 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5217 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5218 pSMB->ParameterCount = pSMB->TotalParameterCount;
5219 if (notify_subdirs)
5220 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5221 pSMB->Reserved2 = 0;
5222 pSMB->CompletionFilter = cpu_to_le32(filter);
5223 pSMB->Fid = netfid; /* file handle always le */
5224 pSMB->ByteCount = 0;
5226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5227 (struct smb_hdr *)pSMBr, &bytes_returned,
5228 CIFS_ASYNC_OP);
5229 if (rc) {
5230 cFYI(1, ("Error in Notify = %d", rc));
5231 } else {
5232 /* Add file to outstanding requests */
5233 /* BB change to kmem cache alloc */
5234 dnotify_req = kmalloc(
5235 sizeof(struct dir_notify_req),
5236 GFP_KERNEL);
5237 if (dnotify_req) {
5238 dnotify_req->Pid = pSMB->hdr.Pid;
5239 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5240 dnotify_req->Mid = pSMB->hdr.Mid;
5241 dnotify_req->Tid = pSMB->hdr.Tid;
5242 dnotify_req->Uid = pSMB->hdr.Uid;
5243 dnotify_req->netfid = netfid;
5244 dnotify_req->pfile = pfile;
5245 dnotify_req->filter = filter;
5246 dnotify_req->multishot = multishot;
5247 spin_lock(&GlobalMid_Lock);
5248 list_add_tail(&dnotify_req->lhead,
5249 &GlobalDnotifyReqList);
5250 spin_unlock(&GlobalMid_Lock);
5251 } else
5252 rc = -ENOMEM;
5254 cifs_buf_release(pSMB);
5255 return rc;
5257 #ifdef CONFIG_CIFS_XATTR
5258 ssize_t
5259 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5260 const unsigned char *searchName,
5261 char *EAData, size_t buf_size,
5262 const struct nls_table *nls_codepage, int remap)
5264 /* BB assumes one setup word */
5265 TRANSACTION2_QPI_REQ *pSMB = NULL;
5266 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5267 int rc = 0;
5268 int bytes_returned;
5269 int name_len;
5270 struct fea *temp_fea;
5271 char *temp_ptr;
5272 __u16 params, byte_count;
5274 cFYI(1, ("In Query All EAs path %s", searchName));
5275 QAllEAsRetry:
5276 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5277 (void **) &pSMBr);
5278 if (rc)
5279 return rc;
5281 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5282 name_len =
5283 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5284 PATH_MAX, nls_codepage, remap);
5285 name_len++; /* trailing null */
5286 name_len *= 2;
5287 } else { /* BB improve the check for buffer overruns BB */
5288 name_len = strnlen(searchName, PATH_MAX);
5289 name_len++; /* trailing null */
5290 strncpy(pSMB->FileName, searchName, name_len);
5293 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5294 pSMB->TotalDataCount = 0;
5295 pSMB->MaxParameterCount = cpu_to_le16(2);
5296 /* BB find exact max SMB PDU from sess structure BB */
5297 pSMB->MaxDataCount = cpu_to_le16(4000);
5298 pSMB->MaxSetupCount = 0;
5299 pSMB->Reserved = 0;
5300 pSMB->Flags = 0;
5301 pSMB->Timeout = 0;
5302 pSMB->Reserved2 = 0;
5303 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5304 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5305 pSMB->DataCount = 0;
5306 pSMB->DataOffset = 0;
5307 pSMB->SetupCount = 1;
5308 pSMB->Reserved3 = 0;
5309 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5310 byte_count = params + 1 /* pad */ ;
5311 pSMB->TotalParameterCount = cpu_to_le16(params);
5312 pSMB->ParameterCount = pSMB->TotalParameterCount;
5313 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5314 pSMB->Reserved4 = 0;
5315 pSMB->hdr.smb_buf_length += byte_count;
5316 pSMB->ByteCount = cpu_to_le16(byte_count);
5318 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5319 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5320 if (rc) {
5321 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5322 } else { /* decode response */
5323 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5325 /* BB also check enough total bytes returned */
5326 /* BB we need to improve the validity checking
5327 of these trans2 responses */
5328 if (rc || (pSMBr->ByteCount < 4))
5329 rc = -EIO; /* bad smb */
5330 /* else if (pFindData){
5331 memcpy((char *) pFindData,
5332 (char *) &pSMBr->hdr.Protocol +
5333 data_offset, kl);
5334 }*/ else {
5335 /* check that length of list is not more than bcc */
5336 /* check that each entry does not go beyond length
5337 of list */
5338 /* check that each element of each entry does not
5339 go beyond end of list */
5340 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5341 struct fealist *ea_response_data;
5342 rc = 0;
5343 /* validate_trans2_offsets() */
5344 /* BB check if start of smb + data_offset > &bcc+ bcc */
5345 ea_response_data = (struct fealist *)
5346 (((char *) &pSMBr->hdr.Protocol) +
5347 data_offset);
5348 name_len = le32_to_cpu(ea_response_data->list_len);
5349 cFYI(1, ("ea length %d", name_len));
5350 if (name_len <= 8) {
5351 /* returned EA size zeroed at top of function */
5352 cFYI(1, ("empty EA list returned from server"));
5353 } else {
5354 /* account for ea list len */
5355 name_len -= 4;
5356 temp_fea = ea_response_data->list;
5357 temp_ptr = (char *)temp_fea;
5358 while (name_len > 0) {
5359 __u16 value_len;
5360 name_len -= 4;
5361 temp_ptr += 4;
5362 rc += temp_fea->name_len;
5363 /* account for prefix user. and trailing null */
5364 rc = rc + 5 + 1;
5365 if (rc < (int)buf_size) {
5366 memcpy(EAData, "user.", 5);
5367 EAData += 5;
5368 memcpy(EAData, temp_ptr,
5369 temp_fea->name_len);
5370 EAData += temp_fea->name_len;
5371 /* null terminate name */
5372 *EAData = 0;
5373 EAData = EAData + 1;
5374 } else if (buf_size == 0) {
5375 /* skip copy - calc size only */
5376 } else {
5377 /* stop before overrun buffer */
5378 rc = -ERANGE;
5379 break;
5381 name_len -= temp_fea->name_len;
5382 temp_ptr += temp_fea->name_len;
5383 /* account for trailing null */
5384 name_len--;
5385 temp_ptr++;
5386 value_len =
5387 le16_to_cpu(temp_fea->value_len);
5388 name_len -= value_len;
5389 temp_ptr += value_len;
5390 /* BB check that temp_ptr is still
5391 within the SMB BB*/
5393 /* no trailing null to account for
5394 in value len */
5395 /* go on to next EA */
5396 temp_fea = (struct fea *)temp_ptr;
5401 cifs_buf_release(pSMB);
5402 if (rc == -EAGAIN)
5403 goto QAllEAsRetry;
5405 return (ssize_t)rc;
5408 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5409 const unsigned char *searchName, const unsigned char *ea_name,
5410 unsigned char *ea_value, size_t buf_size,
5411 const struct nls_table *nls_codepage, int remap)
5413 TRANSACTION2_QPI_REQ *pSMB = NULL;
5414 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5415 int rc = 0;
5416 int bytes_returned;
5417 int name_len;
5418 struct fea *temp_fea;
5419 char *temp_ptr;
5420 __u16 params, byte_count;
5422 cFYI(1, ("In Query EA path %s", searchName));
5423 QEARetry:
5424 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5425 (void **) &pSMBr);
5426 if (rc)
5427 return rc;
5429 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5430 name_len =
5431 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5432 PATH_MAX, nls_codepage, remap);
5433 name_len++; /* trailing null */
5434 name_len *= 2;
5435 } else { /* BB improve the check for buffer overruns BB */
5436 name_len = strnlen(searchName, PATH_MAX);
5437 name_len++; /* trailing null */
5438 strncpy(pSMB->FileName, searchName, name_len);
5441 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5442 pSMB->TotalDataCount = 0;
5443 pSMB->MaxParameterCount = cpu_to_le16(2);
5444 /* BB find exact max SMB PDU from sess structure BB */
5445 pSMB->MaxDataCount = cpu_to_le16(4000);
5446 pSMB->MaxSetupCount = 0;
5447 pSMB->Reserved = 0;
5448 pSMB->Flags = 0;
5449 pSMB->Timeout = 0;
5450 pSMB->Reserved2 = 0;
5451 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5452 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5453 pSMB->DataCount = 0;
5454 pSMB->DataOffset = 0;
5455 pSMB->SetupCount = 1;
5456 pSMB->Reserved3 = 0;
5457 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5458 byte_count = params + 1 /* pad */ ;
5459 pSMB->TotalParameterCount = cpu_to_le16(params);
5460 pSMB->ParameterCount = pSMB->TotalParameterCount;
5461 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5462 pSMB->Reserved4 = 0;
5463 pSMB->hdr.smb_buf_length += byte_count;
5464 pSMB->ByteCount = cpu_to_le16(byte_count);
5466 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5467 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5468 if (rc) {
5469 cFYI(1, ("Send error in Query EA = %d", rc));
5470 } else { /* decode response */
5471 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5473 /* BB also check enough total bytes returned */
5474 /* BB we need to improve the validity checking
5475 of these trans2 responses */
5476 if (rc || (pSMBr->ByteCount < 4))
5477 rc = -EIO; /* bad smb */
5478 /* else if (pFindData){
5479 memcpy((char *) pFindData,
5480 (char *) &pSMBr->hdr.Protocol +
5481 data_offset, kl);
5482 }*/ else {
5483 /* check that length of list is not more than bcc */
5484 /* check that each entry does not go beyond length
5485 of list */
5486 /* check that each element of each entry does not
5487 go beyond end of list */
5488 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5489 struct fealist *ea_response_data;
5490 rc = -ENODATA;
5491 /* validate_trans2_offsets() */
5492 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5493 ea_response_data = (struct fealist *)
5494 (((char *) &pSMBr->hdr.Protocol) +
5495 data_offset);
5496 name_len = le32_to_cpu(ea_response_data->list_len);
5497 cFYI(1, ("ea length %d", name_len));
5498 if (name_len <= 8) {
5499 /* returned EA size zeroed at top of function */
5500 cFYI(1, ("empty EA list returned from server"));
5501 } else {
5502 /* account for ea list len */
5503 name_len -= 4;
5504 temp_fea = ea_response_data->list;
5505 temp_ptr = (char *)temp_fea;
5506 /* loop through checking if we have a matching
5507 name and then return the associated value */
5508 while (name_len > 0) {
5509 __u16 value_len;
5510 name_len -= 4;
5511 temp_ptr += 4;
5512 value_len =
5513 le16_to_cpu(temp_fea->value_len);
5514 /* BB validate that value_len falls within SMB,
5515 even though maximum for name_len is 255 */
5516 if (memcmp(temp_fea->name, ea_name,
5517 temp_fea->name_len) == 0) {
5518 /* found a match */
5519 rc = value_len;
5520 /* account for prefix user. and trailing null */
5521 if (rc <= (int)buf_size) {
5522 memcpy(ea_value,
5523 temp_fea->name+temp_fea->name_len+1,
5524 rc);
5525 /* ea values, unlike ea
5526 names, are not null
5527 terminated */
5528 } else if (buf_size == 0) {
5529 /* skip copy - calc size only */
5530 } else {
5531 /* stop before overrun buffer */
5532 rc = -ERANGE;
5534 break;
5536 name_len -= temp_fea->name_len;
5537 temp_ptr += temp_fea->name_len;
5538 /* account for trailing null */
5539 name_len--;
5540 temp_ptr++;
5541 name_len -= value_len;
5542 temp_ptr += value_len;
5543 /* No trailing null to account for in
5544 value_len. Go on to next EA */
5545 temp_fea = (struct fea *)temp_ptr;
5550 cifs_buf_release(pSMB);
5551 if (rc == -EAGAIN)
5552 goto QEARetry;
5554 return (ssize_t)rc;
5558 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5559 const char *ea_name, const void *ea_value,
5560 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5561 int remap)
5563 struct smb_com_transaction2_spi_req *pSMB = NULL;
5564 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5565 struct fealist *parm_data;
5566 int name_len;
5567 int rc = 0;
5568 int bytes_returned = 0;
5569 __u16 params, param_offset, byte_count, offset, count;
5571 cFYI(1, ("In SetEA"));
5572 SetEARetry:
5573 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5574 (void **) &pSMBr);
5575 if (rc)
5576 return rc;
5578 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5579 name_len =
5580 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5581 PATH_MAX, nls_codepage, remap);
5582 name_len++; /* trailing null */
5583 name_len *= 2;
5584 } else { /* BB improve the check for buffer overruns BB */
5585 name_len = strnlen(fileName, PATH_MAX);
5586 name_len++; /* trailing null */
5587 strncpy(pSMB->FileName, fileName, name_len);
5590 params = 6 + name_len;
5592 /* done calculating parms using name_len of file name,
5593 now use name_len to calculate length of ea name
5594 we are going to create in the inode xattrs */
5595 if (ea_name == NULL)
5596 name_len = 0;
5597 else
5598 name_len = strnlen(ea_name, 255);
5600 count = sizeof(*parm_data) + ea_value_len + name_len;
5601 pSMB->MaxParameterCount = cpu_to_le16(2);
5602 /* BB find max SMB PDU from sess */
5603 pSMB->MaxDataCount = cpu_to_le16(1000);
5604 pSMB->MaxSetupCount = 0;
5605 pSMB->Reserved = 0;
5606 pSMB->Flags = 0;
5607 pSMB->Timeout = 0;
5608 pSMB->Reserved2 = 0;
5609 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5610 InformationLevel) - 4;
5611 offset = param_offset + params;
5612 pSMB->InformationLevel =
5613 cpu_to_le16(SMB_SET_FILE_EA);
5615 parm_data =
5616 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5617 offset);
5618 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5619 pSMB->DataOffset = cpu_to_le16(offset);
5620 pSMB->SetupCount = 1;
5621 pSMB->Reserved3 = 0;
5622 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5623 byte_count = 3 /* pad */ + params + count;
5624 pSMB->DataCount = cpu_to_le16(count);
5625 parm_data->list_len = cpu_to_le32(count);
5626 parm_data->list[0].EA_flags = 0;
5627 /* we checked above that name len is less than 255 */
5628 parm_data->list[0].name_len = (__u8)name_len;
5629 /* EA names are always ASCII */
5630 if (ea_name)
5631 strncpy(parm_data->list[0].name, ea_name, name_len);
5632 parm_data->list[0].name[name_len] = 0;
5633 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5634 /* caller ensures that ea_value_len is less than 64K but
5635 we need to ensure that it fits within the smb */
5637 /*BB add length check to see if it would fit in
5638 negotiated SMB buffer size BB */
5639 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5640 if (ea_value_len)
5641 memcpy(parm_data->list[0].name+name_len+1,
5642 ea_value, ea_value_len);
5644 pSMB->TotalDataCount = pSMB->DataCount;
5645 pSMB->ParameterCount = cpu_to_le16(params);
5646 pSMB->TotalParameterCount = pSMB->ParameterCount;
5647 pSMB->Reserved4 = 0;
5648 pSMB->hdr.smb_buf_length += byte_count;
5649 pSMB->ByteCount = cpu_to_le16(byte_count);
5650 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5651 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5652 if (rc)
5653 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5655 cifs_buf_release(pSMB);
5657 if (rc == -EAGAIN)
5658 goto SetEARetry;
5660 return rc;
5663 #endif