RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / fs / cifs / cifssmb.c
blob3d93eeb58432952737724677644c00293fa103ea
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2007
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 */
85 /* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
87 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
89 struct cifsFileInfo *open_file = NULL;
90 struct list_head *tmp;
91 struct list_head *tmp1;
93 /* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
96 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
97 if (open_file)
98 open_file->invalidHandle = TRUE;
100 write_unlock(&GlobalSMBSeslock);
101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
105 /* If the return code is zero, this function must fill in request_buf pointer */
106 static int
107 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108 void **request_buf /* returned */)
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 == FALSE) ||
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->status == CifsNeedReconnect)
159 rc = cifs_setup_session(0, tcon->ses,
160 nls_codepage);
161 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
162 mark_open_files_invalid(tcon);
163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
164 tcon, nls_codepage);
165 up(&tcon->ses->sesSem);
166 /* tell server which Unix caps we support */
167 if (tcon->ses->capabilities & CAP_UNIX)
168 reset_cifs_unix_caps(0 /* no xid */,
169 tcon,
170 NULL /* we do not know sb */,
171 NULL /* no vol info */);
172 /* BB FIXME add code to check if wsize needs
173 update due to negotiated smb buffer size
174 shrinking */
175 if (rc == 0)
176 atomic_inc(&tconInfoReconnectCount);
178 cFYI(1, ("reconnect tcon rc = %d", rc));
179 /* Removed call to reopen open files here.
180 It is safer (and faster) to reopen files
181 one at a time as needed in read and write */
183 /* Check if handle based operation so we
184 know whether we can continue or not without
185 returning to caller to reset file handle */
186 switch (smb_command) {
187 case SMB_COM_READ_ANDX:
188 case SMB_COM_WRITE_ANDX:
189 case SMB_COM_CLOSE:
190 case SMB_COM_FIND_CLOSE2:
191 case SMB_COM_LOCKING_ANDX: {
192 unload_nls(nls_codepage);
193 return -EAGAIN;
196 } else {
197 up(&tcon->ses->sesSem);
199 unload_nls(nls_codepage);
201 } else {
202 return -EIO;
205 if (rc)
206 return rc;
208 *request_buf = cifs_small_buf_get();
209 if (*request_buf == NULL) {
210 /* BB should we add a retry in here if not a writepage? */
211 return -ENOMEM;
214 header_assemble((struct smb_hdr *) *request_buf, smb_command,
215 tcon, wct);
217 if (tcon != NULL)
218 cifs_stats_inc(&tcon->num_smbs_sent);
220 return rc;
224 small_smb_init_no_tc(const int smb_command, const int wct,
225 struct cifsSesInfo *ses, void **request_buf)
227 int rc;
228 struct smb_hdr *buffer;
230 rc = small_smb_init(smb_command, wct, NULL, request_buf);
231 if (rc)
232 return rc;
234 buffer = (struct smb_hdr *)*request_buf;
235 buffer->Mid = GetNextMid(ses->server);
236 if (ses->capabilities & CAP_UNICODE)
237 buffer->Flags2 |= SMBFLG2_UNICODE;
238 if (ses->capabilities & CAP_STATUS32)
239 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
241 /* uid, tid can stay at zero as set in header assemble */
243 /* BB add support for turning on the signing when
244 this function is used after 1st of session setup requests */
246 return rc;
249 /* If the return code is zero, this function must fill in request_buf pointer */
250 static int
251 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
252 void **request_buf /* returned */ ,
253 void **response_buf /* returned */ )
255 int rc = 0;
257 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
258 check for tcp and smb session status done differently
259 for those three - in the calling routine */
260 if (tcon) {
261 if (tcon->tidStatus == CifsExiting) {
262 /* only tree disconnect, open, and write,
263 (and ulogoff which does not have tcon)
264 are allowed as we start force umount */
265 if ((smb_command != SMB_COM_WRITE_ANDX) &&
266 (smb_command != SMB_COM_OPEN_ANDX) &&
267 (smb_command != SMB_COM_TREE_DISCONNECT)) {
268 cFYI(1, ("can not send cmd %d while umounting",
269 smb_command));
270 return -ENODEV;
274 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
275 (tcon->ses->server)) {
276 struct nls_table *nls_codepage;
277 /* Give Demultiplex thread up to 10 seconds to
278 reconnect, should be greater than cifs socket
279 timeout which is 7 seconds */
280 while (tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
282 wait_event_interruptible_timeout(tcon->ses->server->response_q,
283 (tcon->ses->server->tcpStatus ==
284 CifsGood), 10 * HZ);
285 if (tcon->ses->server->tcpStatus ==
286 CifsNeedReconnect) {
287 /* on "soft" mounts we wait once */
288 if ((tcon->retry == FALSE) ||
289 (tcon->ses->status == CifsExiting)) {
290 cFYI(1, ("gave up waiting on "
291 "reconnect in smb_init"));
292 return -EHOSTDOWN;
293 } /* else "hard" mount - keep retrying
294 until process is killed or server
295 comes on-line */
296 } else /* TCP session is reestablished now */
297 break;
299 nls_codepage = load_nls_default();
300 /* need to prevent multiple threads trying to
301 simultaneously reconnect the same SMB session */
302 down(&tcon->ses->sesSem);
303 if (tcon->ses->status == CifsNeedReconnect)
304 rc = cifs_setup_session(0, tcon->ses,
305 nls_codepage);
306 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
307 mark_open_files_invalid(tcon);
308 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
309 tcon, nls_codepage);
310 up(&tcon->ses->sesSem);
311 /* tell server which Unix caps we support */
312 if (tcon->ses->capabilities & CAP_UNIX)
313 reset_cifs_unix_caps(0 /* no xid */,
314 tcon,
315 NULL /* do not know sb */,
316 NULL /* no vol info */);
317 /* BB FIXME add code to check if wsize needs
318 update due to negotiated smb buffer size
319 shrinking */
320 if (rc == 0)
321 atomic_inc(&tconInfoReconnectCount);
323 cFYI(1, ("reconnect tcon rc = %d", rc));
324 /* Removed call to reopen open files here.
325 It is safer (and faster) to reopen files
326 one at a time as needed in read and write */
328 /* Check if handle based operation so we
329 know whether we can continue or not without
330 returning to caller to reset file handle */
331 switch (smb_command) {
332 case SMB_COM_READ_ANDX:
333 case SMB_COM_WRITE_ANDX:
334 case SMB_COM_CLOSE:
335 case SMB_COM_FIND_CLOSE2:
336 case SMB_COM_LOCKING_ANDX: {
337 unload_nls(nls_codepage);
338 return -EAGAIN;
341 } else {
342 up(&tcon->ses->sesSem);
344 unload_nls(nls_codepage);
346 } else {
347 return -EIO;
350 if (rc)
351 return rc;
353 *request_buf = cifs_buf_get();
354 if (*request_buf == NULL) {
355 /* BB should we add a retry in here if not a writepage? */
356 return -ENOMEM;
358 /* Although the original thought was we needed the response buf for */
359 /* potential retries of smb operations it turns out we can determine */
360 /* from the mid flags when the request buffer can be resent without */
361 /* having to use a second distinct buffer for the response */
362 if (response_buf)
363 *response_buf = *request_buf;
365 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
366 wct /*wct */ );
368 if (tcon != NULL)
369 cifs_stats_inc(&tcon->num_smbs_sent);
371 return rc;
374 static int validate_t2(struct smb_t2_rsp *pSMB)
376 int rc = -EINVAL;
377 int total_size;
378 char *pBCC;
380 /* check for plausible wct, bcc and t2 data and parm sizes */
381 /* check for parm and data offset going beyond end of smb */
382 if (pSMB->hdr.WordCount >= 10) {
383 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
384 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
385 /* check that bcc is at least as big as parms + data */
386 /* check that bcc is less than negotiated smb buffer */
387 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
388 if (total_size < 512) {
389 total_size +=
390 le16_to_cpu(pSMB->t2_rsp.DataCount);
391 /* BCC le converted in SendReceive */
392 pBCC = (pSMB->hdr.WordCount * 2) +
393 sizeof(struct smb_hdr) +
394 (char *)pSMB;
395 if ((total_size <= (*(u16 *)pBCC)) &&
396 (total_size <
397 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
398 return 0;
403 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
404 sizeof(struct smb_t2_rsp) + 16);
405 return rc;
408 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
410 NEGOTIATE_REQ *pSMB;
411 NEGOTIATE_RSP *pSMBr;
412 int rc = 0;
413 int bytes_returned;
414 int i;
415 struct TCP_Server_Info *server;
416 u16 count;
417 unsigned int secFlags;
418 u16 dialect;
420 if (ses->server)
421 server = ses->server;
422 else {
423 rc = -EIO;
424 return rc;
426 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
427 (void **) &pSMB, (void **) &pSMBr);
428 if (rc)
429 return rc;
431 /* if any of auth flags (ie not sign or seal) are overriden use them */
432 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
433 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
434 else /* if override flags set only sign/seal OR them with global auth */
435 secFlags = extended_security | ses->overrideSecFlg;
437 cFYI(1, ("secFlags 0x%x", secFlags));
439 pSMB->hdr.Mid = GetNextMid(server);
440 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
442 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
443 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
444 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
445 cFYI(1, ("Kerberos only mechanism, enable extended security"));
446 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
449 count = 0;
450 for (i = 0; i < CIFS_NUM_PROT; i++) {
451 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
452 count += strlen(protocols[i].name) + 1;
453 /* null at end of source and target buffers anyway */
455 pSMB->hdr.smb_buf_length += count;
456 pSMB->ByteCount = cpu_to_le16(count);
458 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
460 if (rc != 0)
461 goto neg_err_exit;
463 dialect = le16_to_cpu(pSMBr->DialectIndex);
464 cFYI(1, ("Dialect: %d", dialect));
465 /* Check wct = 1 error case */
466 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
467 /* core returns wct = 1, but we do not ask for core - otherwise
468 small wct just comes when dialect index is -1 indicating we
469 could not negotiate a common dialect */
470 rc = -EOPNOTSUPP;
471 goto neg_err_exit;
472 #ifdef CONFIG_CIFS_WEAK_PW_HASH
473 } else if ((pSMBr->hdr.WordCount == 13)
474 && ((dialect == LANMAN_PROT)
475 || (dialect == LANMAN2_PROT))) {
476 __s16 tmp;
477 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
479 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
480 (secFlags & CIFSSEC_MAY_PLNTXT))
481 server->secType = LANMAN;
482 else {
483 cERROR(1, ("mount failed weak security disabled"
484 " in /proc/fs/cifs/SecurityFlags"));
485 rc = -EOPNOTSUPP;
486 goto neg_err_exit;
488 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
489 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
490 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
491 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
492 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
493 /* even though we do not use raw we might as well set this
494 accurately, in case we ever find a need for it */
495 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
496 server->maxRw = 0xFF00;
497 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
498 } else {
499 server->maxRw = 0;/* we do not need to use raw anyway */
500 server->capabilities = CAP_MPX_MODE;
502 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
503 if (tmp == -1) {
504 /* OS/2 often does not set timezone therefore
505 * we must use server time to calc time zone.
506 * Could deviate slightly from the right zone.
507 * Smallest defined timezone difference is 15 minutes
508 * (i.e. Nepal). Rounding up/down is done to match
509 * this requirement.
511 int val, seconds, remain, result;
512 struct timespec ts, utc;
513 utc = CURRENT_TIME;
514 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
515 le16_to_cpu(rsp->SrvTime.Time));
516 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
517 (int)ts.tv_sec, (int)utc.tv_sec,
518 (int)(utc.tv_sec - ts.tv_sec)));
519 val = (int)(utc.tv_sec - ts.tv_sec);
520 seconds = abs(val);
521 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
522 remain = seconds % MIN_TZ_ADJ;
523 if (remain >= (MIN_TZ_ADJ / 2))
524 result += MIN_TZ_ADJ;
525 if (val < 0)
526 result = - result;
527 server->timeAdj = result;
528 } else {
529 server->timeAdj = (int)tmp;
530 server->timeAdj *= 60; /* also in seconds */
532 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
535 /* BB get server time for time conversions and add
536 code to use it and timezone since this is not UTC */
538 if (rsp->EncryptionKeyLength ==
539 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
540 memcpy(server->cryptKey, rsp->EncryptionKey,
541 CIFS_CRYPTO_KEY_SIZE);
542 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
543 rc = -EIO; /* need cryptkey unless plain text */
544 goto neg_err_exit;
547 cFYI(1, ("LANMAN negotiated"));
548 /* we will not end up setting signing flags - as no signing
549 was in LANMAN and server did not return the flags on */
550 goto signing_check;
551 #else /* weak security disabled */
552 } else if (pSMBr->hdr.WordCount == 13) {
553 cERROR(1, ("mount failed, cifs module not built "
554 "with CIFS_WEAK_PW_HASH support"));
555 rc = -EOPNOTSUPP;
556 #endif /* WEAK_PW_HASH */
557 goto neg_err_exit;
558 } else if (pSMBr->hdr.WordCount != 17) {
559 /* unknown wct */
560 rc = -EOPNOTSUPP;
561 goto neg_err_exit;
563 /* else wct == 17 NTLM */
564 server->secMode = pSMBr->SecurityMode;
565 if ((server->secMode & SECMODE_USER) == 0)
566 cFYI(1, ("share mode security"));
568 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
569 #ifdef CONFIG_CIFS_WEAK_PW_HASH
570 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
571 #endif /* CIFS_WEAK_PW_HASH */
572 cERROR(1, ("Server requests plain text password"
573 " but client support disabled"));
575 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
576 server->secType = NTLMv2;
577 else if (secFlags & CIFSSEC_MAY_NTLM)
578 server->secType = NTLM;
579 else if (secFlags & CIFSSEC_MAY_NTLMV2)
580 server->secType = NTLMv2;
581 else if (secFlags & CIFSSEC_MAY_KRB5)
582 server->secType = Kerberos;
583 else if (secFlags & CIFSSEC_MAY_LANMAN)
584 server->secType = LANMAN;
585 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
586 else if (secFlags & CIFSSEC_MAY_PLNTXT)
587 server->secType = ??
588 #endif */
589 else {
590 rc = -EOPNOTSUPP;
591 cERROR(1, ("Invalid security type"));
592 goto neg_err_exit;
594 /* else ... any others ...? */
596 /* one byte, so no need to convert this or EncryptionKeyLen from
597 little endian */
598 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
599 /* probably no need to store and check maxvcs */
600 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
601 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
602 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
603 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
604 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
605 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
606 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
607 server->timeAdj *= 60;
608 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
609 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
610 CIFS_CRYPTO_KEY_SIZE);
611 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
612 && (pSMBr->EncryptionKeyLength == 0)) {
613 /* decode security blob */
614 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
615 rc = -EIO; /* no crypt key only if plain text pwd */
616 goto neg_err_exit;
619 /* BB might be helpful to save off the domain of server here */
621 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
622 (server->capabilities & CAP_EXTENDED_SECURITY)) {
623 count = pSMBr->ByteCount;
624 if (count < 16) {
625 rc = -EIO;
626 goto neg_err_exit;
629 if (server->socketUseCount.counter > 1) {
630 if (memcmp(server->server_GUID,
631 pSMBr->u.extended_response.
632 GUID, 16) != 0) {
633 cFYI(1, ("server UID changed"));
634 memcpy(server->server_GUID,
635 pSMBr->u.extended_response.GUID,
636 16);
638 } else
639 memcpy(server->server_GUID,
640 pSMBr->u.extended_response.GUID, 16);
642 if (count == 16) {
643 server->secType = RawNTLMSSP;
644 } else {
645 rc = decode_negTokenInit(pSMBr->u.extended_response.
646 SecurityBlob,
647 count - 16,
648 &server->secType);
649 if (rc == 1) {
650 rc = 0;
651 } else {
652 rc = -EINVAL;
655 } else
656 server->capabilities &= ~CAP_EXTENDED_SECURITY;
658 #ifdef CONFIG_CIFS_WEAK_PW_HASH
659 signing_check:
660 #endif
661 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
662 /* MUST_SIGN already includes the MAY_SIGN FLAG
663 so if this is zero it means that signing is disabled */
664 cFYI(1, ("Signing disabled"));
665 if (server->secMode & SECMODE_SIGN_REQUIRED) {
666 cERROR(1, ("Server requires "
667 "packet signing to be enabled in "
668 "/proc/fs/cifs/SecurityFlags."));
669 rc = -EOPNOTSUPP;
671 server->secMode &=
672 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
673 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
674 /* signing required */
675 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
676 if ((server->secMode &
677 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
678 cERROR(1,
679 ("signing required but server lacks support"));
680 rc = -EOPNOTSUPP;
681 } else
682 server->secMode |= SECMODE_SIGN_REQUIRED;
683 } else {
684 /* signing optional ie CIFSSEC_MAY_SIGN */
685 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
686 server->secMode &=
687 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
690 neg_err_exit:
691 cifs_buf_release(pSMB);
693 cFYI(1, ("negprot rc %d", rc));
694 return rc;
698 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
700 struct smb_hdr *smb_buffer;
701 int rc = 0;
703 cFYI(1, ("In tree disconnect"));
705 * If last user of the connection and
706 * connection alive - disconnect it
707 * If this is the last connection on the server session disconnect it
708 * (and inside session disconnect we should check if tcp socket needs
709 * to be freed and kernel thread woken up).
711 if (tcon)
712 down(&tcon->tconSem);
713 else
714 return -EIO;
716 atomic_dec(&tcon->useCount);
717 if (atomic_read(&tcon->useCount) > 0) {
718 up(&tcon->tconSem);
719 return -EBUSY;
722 /* No need to return error on this operation if tid invalidated and
723 closed on server already e.g. due to tcp session crashing */
724 if (tcon->tidStatus == CifsNeedReconnect) {
725 up(&tcon->tconSem);
726 return 0;
729 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
730 up(&tcon->tconSem);
731 return -EIO;
733 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
734 (void **)&smb_buffer);
735 if (rc) {
736 up(&tcon->tconSem);
737 return rc;
740 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
741 if (rc)
742 cFYI(1, ("Tree disconnect failed %d", rc));
744 up(&tcon->tconSem);
746 /* No need to return error on this operation if tid invalidated and
747 closed on server already e.g. due to tcp session crashing */
748 if (rc == -EAGAIN)
749 rc = 0;
751 return rc;
755 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
757 LOGOFF_ANDX_REQ *pSMB;
758 int rc = 0;
760 cFYI(1, ("In SMBLogoff for session disconnect"));
761 if (ses)
762 down(&ses->sesSem);
763 else
764 return -EIO;
766 atomic_dec(&ses->inUse);
767 if (atomic_read(&ses->inUse) > 0) {
768 up(&ses->sesSem);
769 return -EBUSY;
771 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
772 if (rc) {
773 up(&ses->sesSem);
774 return rc;
777 if (ses->server) {
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;
785 pSMB->hdr.Uid = ses->Suid;
787 pSMB->AndXCommand = 0xFF;
788 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
789 if (ses->server) {
790 atomic_dec(&ses->server->socketUseCount);
791 if (atomic_read(&ses->server->socketUseCount) == 0) {
792 spin_lock(&GlobalMid_Lock);
793 ses->server->tcpStatus = CifsExiting;
794 spin_unlock(&GlobalMid_Lock);
795 rc = -ESHUTDOWN;
798 up(&ses->sesSem);
800 /* if session dead then we do not need to do ulogoff,
801 since server closed smb session, no sense reporting
802 error */
803 if (rc == -EAGAIN)
804 rc = 0;
805 return rc;
809 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
810 __u16 type, const struct nls_table *nls_codepage, int remap)
812 TRANSACTION2_SPI_REQ *pSMB = NULL;
813 TRANSACTION2_SPI_RSP *pSMBr = NULL;
814 struct unlink_psx_rq *pRqD;
815 int name_len;
816 int rc = 0;
817 int bytes_returned = 0;
818 __u16 params, param_offset, offset, byte_count;
820 cFYI(1, ("In POSIX delete"));
821 PsxDelete:
822 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
823 (void **) &pSMBr);
824 if (rc)
825 return rc;
827 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
828 name_len =
829 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
830 PATH_MAX, nls_codepage, remap);
831 name_len++; /* trailing null */
832 name_len *= 2;
833 } else { /* BB add path length overrun check */
834 name_len = strnlen(fileName, PATH_MAX);
835 name_len++; /* trailing null */
836 strncpy(pSMB->FileName, fileName, name_len);
839 params = 6 + name_len;
840 pSMB->MaxParameterCount = cpu_to_le16(2);
841 pSMB->MaxDataCount = 0; /* BB double check this with jra */
842 pSMB->MaxSetupCount = 0;
843 pSMB->Reserved = 0;
844 pSMB->Flags = 0;
845 pSMB->Timeout = 0;
846 pSMB->Reserved2 = 0;
847 param_offset = offsetof(struct smb_com_transaction2_spi_req,
848 InformationLevel) - 4;
849 offset = param_offset + params;
851 /* Setup pointer to Request Data (inode type) */
852 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
853 pRqD->type = cpu_to_le16(type);
854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
855 pSMB->DataOffset = cpu_to_le16(offset);
856 pSMB->SetupCount = 1;
857 pSMB->Reserved3 = 0;
858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
859 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
861 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
862 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
863 pSMB->ParameterCount = cpu_to_le16(params);
864 pSMB->TotalParameterCount = pSMB->ParameterCount;
865 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
866 pSMB->Reserved4 = 0;
867 pSMB->hdr.smb_buf_length += byte_count;
868 pSMB->ByteCount = cpu_to_le16(byte_count);
869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
871 if (rc) {
872 cFYI(1, ("Posix delete returned %d", rc));
874 cifs_buf_release(pSMB);
876 cifs_stats_inc(&tcon->num_deletes);
878 if (rc == -EAGAIN)
879 goto PsxDelete;
881 return rc;
885 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
886 const struct nls_table *nls_codepage, int remap)
888 DELETE_FILE_REQ *pSMB = NULL;
889 DELETE_FILE_RSP *pSMBr = NULL;
890 int rc = 0;
891 int bytes_returned;
892 int name_len;
894 DelFileRetry:
895 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
896 (void **) &pSMBr);
897 if (rc)
898 return rc;
900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
901 name_len =
902 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
903 PATH_MAX, nls_codepage, remap);
904 name_len++; /* trailing null */
905 name_len *= 2;
906 } else { /* BB improve check for buffer overruns BB */
907 name_len = strnlen(fileName, PATH_MAX);
908 name_len++; /* trailing null */
909 strncpy(pSMB->fileName, fileName, name_len);
911 pSMB->SearchAttributes =
912 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
913 pSMB->BufferFormat = 0x04;
914 pSMB->hdr.smb_buf_length += name_len + 1;
915 pSMB->ByteCount = cpu_to_le16(name_len + 1);
916 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
917 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
918 cifs_stats_inc(&tcon->num_deletes);
919 if (rc) {
920 cFYI(1, ("Error in RMFile = %d", rc));
923 cifs_buf_release(pSMB);
924 if (rc == -EAGAIN)
925 goto DelFileRetry;
927 return rc;
931 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
932 const struct nls_table *nls_codepage, int remap)
934 DELETE_DIRECTORY_REQ *pSMB = NULL;
935 DELETE_DIRECTORY_RSP *pSMBr = NULL;
936 int rc = 0;
937 int bytes_returned;
938 int name_len;
940 cFYI(1, ("In CIFSSMBRmDir"));
941 RmDirRetry:
942 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
943 (void **) &pSMBr);
944 if (rc)
945 return rc;
947 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
948 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
949 PATH_MAX, nls_codepage, remap);
950 name_len++; /* trailing null */
951 name_len *= 2;
952 } else { /* BB improve check for buffer overruns BB */
953 name_len = strnlen(dirName, PATH_MAX);
954 name_len++; /* trailing null */
955 strncpy(pSMB->DirName, dirName, name_len);
958 pSMB->BufferFormat = 0x04;
959 pSMB->hdr.smb_buf_length += name_len + 1;
960 pSMB->ByteCount = cpu_to_le16(name_len + 1);
961 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
962 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
963 cifs_stats_inc(&tcon->num_rmdirs);
964 if (rc) {
965 cFYI(1, ("Error in RMDir = %d", rc));
968 cifs_buf_release(pSMB);
969 if (rc == -EAGAIN)
970 goto RmDirRetry;
971 return rc;
975 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
976 const char *name, const struct nls_table *nls_codepage, int remap)
978 int rc = 0;
979 CREATE_DIRECTORY_REQ *pSMB = NULL;
980 CREATE_DIRECTORY_RSP *pSMBr = NULL;
981 int bytes_returned;
982 int name_len;
984 cFYI(1, ("In CIFSSMBMkDir"));
985 MkDirRetry:
986 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
987 (void **) &pSMBr);
988 if (rc)
989 return rc;
991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
992 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
993 PATH_MAX, nls_codepage, remap);
994 name_len++; /* trailing null */
995 name_len *= 2;
996 } else { /* BB improve check for buffer overruns BB */
997 name_len = strnlen(name, PATH_MAX);
998 name_len++; /* trailing null */
999 strncpy(pSMB->DirName, name, name_len);
1002 pSMB->BufferFormat = 0x04;
1003 pSMB->hdr.smb_buf_length += name_len + 1;
1004 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1007 cifs_stats_inc(&tcon->num_mkdirs);
1008 if (rc) {
1009 cFYI(1, ("Error in Mkdir = %d", rc));
1012 cifs_buf_release(pSMB);
1013 if (rc == -EAGAIN)
1014 goto MkDirRetry;
1015 return rc;
1019 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1020 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
1021 __u32 *pOplock, const char *name,
1022 const struct nls_table *nls_codepage, int remap)
1024 TRANSACTION2_SPI_REQ *pSMB = NULL;
1025 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1026 int name_len;
1027 int rc = 0;
1028 int bytes_returned = 0;
1029 __u16 params, param_offset, offset, byte_count, count;
1030 OPEN_PSX_REQ * pdata;
1031 OPEN_PSX_RSP * psx_rsp;
1033 cFYI(1, ("In POSIX Create"));
1034 PsxCreat:
1035 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1036 (void **) &pSMBr);
1037 if (rc)
1038 return rc;
1040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1041 name_len =
1042 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1043 PATH_MAX, nls_codepage, remap);
1044 name_len++; /* trailing null */
1045 name_len *= 2;
1046 } else { /* BB improve the check for buffer overruns BB */
1047 name_len = strnlen(name, PATH_MAX);
1048 name_len++; /* trailing null */
1049 strncpy(pSMB->FileName, name, name_len);
1052 params = 6 + name_len;
1053 count = sizeof(OPEN_PSX_REQ);
1054 pSMB->MaxParameterCount = cpu_to_le16(2);
1055 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1056 pSMB->MaxSetupCount = 0;
1057 pSMB->Reserved = 0;
1058 pSMB->Flags = 0;
1059 pSMB->Timeout = 0;
1060 pSMB->Reserved2 = 0;
1061 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1062 InformationLevel) - 4;
1063 offset = param_offset + params;
1064 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1065 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1066 pdata->Permissions = cpu_to_le64(mode);
1067 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1068 pdata->OpenFlags = cpu_to_le32(*pOplock);
1069 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1070 pSMB->DataOffset = cpu_to_le16(offset);
1071 pSMB->SetupCount = 1;
1072 pSMB->Reserved3 = 0;
1073 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1074 byte_count = 3 /* pad */ + params + count;
1076 pSMB->DataCount = cpu_to_le16(count);
1077 pSMB->ParameterCount = cpu_to_le16(params);
1078 pSMB->TotalDataCount = pSMB->DataCount;
1079 pSMB->TotalParameterCount = pSMB->ParameterCount;
1080 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1081 pSMB->Reserved4 = 0;
1082 pSMB->hdr.smb_buf_length += byte_count;
1083 pSMB->ByteCount = cpu_to_le16(byte_count);
1084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1086 if (rc) {
1087 cFYI(1, ("Posix create returned %d", rc));
1088 goto psx_create_err;
1091 cFYI(1, ("copying inode info"));
1092 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1094 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1095 rc = -EIO; /* bad smb */
1096 goto psx_create_err;
1099 /* copy return information to pRetData */
1100 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1101 + le16_to_cpu(pSMBr->t2.DataOffset));
1103 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1104 if (netfid)
1105 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1106 /* Let caller know file was created so we can set the mode. */
1107 /* Do we care about the CreateAction in any other cases? */
1108 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1109 *pOplock |= CIFS_CREATE_ACTION;
1110 /* check to make sure response data is there */
1111 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1112 pRetData->Type = cpu_to_le32(-1); /* unknown */
1113 #ifdef CONFIG_CIFS_DEBUG2
1114 cFYI(1, ("unknown type"));
1115 #endif
1116 } else {
1117 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1118 + sizeof(FILE_UNIX_BASIC_INFO)) {
1119 cERROR(1, ("Open response data too small"));
1120 pRetData->Type = cpu_to_le32(-1);
1121 goto psx_create_err;
1123 memcpy((char *) pRetData,
1124 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1125 sizeof(FILE_UNIX_BASIC_INFO));
1128 psx_create_err:
1129 cifs_buf_release(pSMB);
1131 cifs_stats_inc(&tcon->num_mkdirs);
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1136 return rc;
1139 static __u16 convert_disposition(int disposition)
1141 __u16 ofun = 0;
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
1163 cFYI(1, ("unknown disposition %d", disposition));
1164 ofun = SMBOPEN_OAPPEND; /* regular open */
1166 return ofun;
1170 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1171 const char *fileName, const int openDisposition,
1172 const int access_flags, const int create_options, __u16 * netfid,
1173 int *pOplock, FILE_ALL_INFO * pfile_info,
1174 const struct nls_table *nls_codepage, int remap)
1176 int rc = -EACCES;
1177 OPENX_REQ *pSMB = NULL;
1178 OPENX_RSP *pSMBr = NULL;
1179 int bytes_returned;
1180 int name_len;
1181 __u16 count;
1183 OldOpenRetry:
1184 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1185 (void **) &pSMBr);
1186 if (rc)
1187 return rc;
1189 pSMB->AndXCommand = 0xFF; /* none */
1191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1192 count = 1; /* account for one byte pad to word boundary */
1193 name_len =
1194 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1195 fileName, PATH_MAX, nls_codepage, remap);
1196 name_len++; /* trailing null */
1197 name_len *= 2;
1198 } else { /* BB improve check for buffer overruns BB */
1199 count = 0; /* no pad */
1200 name_len = strnlen(fileName, PATH_MAX);
1201 name_len++; /* trailing null */
1202 strncpy(pSMB->fileName, fileName, name_len);
1204 if (*pOplock & REQ_OPLOCK)
1205 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1206 else if (*pOplock & REQ_BATCHOPLOCK)
1207 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1209 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1210 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1211 /* 0 = read
1212 1 = write
1213 2 = rw
1214 3 = execute
1216 pSMB->Mode = cpu_to_le16(2);
1217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1224 else
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
1227 /* if ((omode & S_IWUGO) == 0)
1228 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1229 /* Above line causes problems due to vfs splitting create into two
1230 pieces - need to set mode after file created not while it is
1231 being created */
1233 /* BB FIXME BB */
1234 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1235 CREATE_OPTIONS_MASK); */
1236 /* BB FIXME END BB */
1238 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1239 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1240 count += name_len;
1241 pSMB->hdr.smb_buf_length += count;
1243 pSMB->ByteCount = cpu_to_le16(count);
1244 /* long_op set to 1 to allow for oplock break timeouts */
1245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1246 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1247 cifs_stats_inc(&tcon->num_opens);
1248 if (rc) {
1249 cFYI(1, ("Error in Open = %d", rc));
1250 } else {
1251 /* BB verify if wct == 15 */
1253 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1255 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1256 /* Let caller know file was created so we can set the mode. */
1257 /* Do we care about the CreateAction in any other cases? */
1258 /* BB FIXME BB */
1259 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1260 *pOplock |= CIFS_CREATE_ACTION; */
1261 /* BB FIXME END */
1263 if (pfile_info) {
1264 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1265 pfile_info->LastAccessTime = 0; /* BB fixme */
1266 pfile_info->LastWriteTime = 0; /* BB fixme */
1267 pfile_info->ChangeTime = 0; /* BB fixme */
1268 pfile_info->Attributes =
1269 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1270 /* the file_info buf is endian converted by caller */
1271 pfile_info->AllocationSize =
1272 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1273 pfile_info->EndOfFile = pfile_info->AllocationSize;
1274 pfile_info->NumberOfLinks = cpu_to_le32(1);
1278 cifs_buf_release(pSMB);
1279 if (rc == -EAGAIN)
1280 goto OldOpenRetry;
1281 return rc;
1285 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1286 const char *fileName, const int openDisposition,
1287 const int access_flags, const int create_options, __u16 * netfid,
1288 int *pOplock, FILE_ALL_INFO * pfile_info,
1289 const struct nls_table *nls_codepage, int remap)
1291 int rc = -EACCES;
1292 OPEN_REQ *pSMB = NULL;
1293 OPEN_RSP *pSMBr = NULL;
1294 int bytes_returned;
1295 int name_len;
1296 __u16 count;
1298 openRetry:
1299 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1300 (void **) &pSMBr);
1301 if (rc)
1302 return rc;
1304 pSMB->AndXCommand = 0xFF; /* none */
1306 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1307 count = 1; /* account for one byte pad to word boundary */
1308 name_len =
1309 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1310 fileName, PATH_MAX, nls_codepage, remap);
1311 name_len++; /* trailing null */
1312 name_len *= 2;
1313 pSMB->NameLength = cpu_to_le16(name_len);
1314 } else { /* BB improve check for buffer overruns BB */
1315 count = 0; /* no pad */
1316 name_len = strnlen(fileName, PATH_MAX);
1317 name_len++; /* trailing null */
1318 pSMB->NameLength = cpu_to_le16(name_len);
1319 strncpy(pSMB->fileName, fileName, name_len);
1321 if (*pOplock & REQ_OPLOCK)
1322 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1323 else if (*pOplock & REQ_BATCHOPLOCK)
1324 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1325 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1326 pSMB->AllocationSize = 0;
1327 /* set file as system file if special file such
1328 as fifo and server expecting SFU style and
1329 no Unix extensions */
1330 if (create_options & CREATE_OPTION_SPECIAL)
1331 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1332 else
1333 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1334 /* XP does not handle ATTR_POSIX_SEMANTICS */
1335 /* but it helps speed up case sensitive checks for other
1336 servers such as Samba */
1337 if (tcon->ses->capabilities & CAP_UNIX)
1338 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1340 /* if ((omode & S_IWUGO) == 0)
1341 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1342 /* Above line causes problems due to vfs splitting create into two
1343 pieces - need to set mode after file created not while it is
1344 being created */
1345 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1346 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1347 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1348 /* BB Expirement with various impersonation levels and verify */
1349 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1350 pSMB->SecurityFlags =
1351 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1353 count += name_len;
1354 pSMB->hdr.smb_buf_length += count;
1356 pSMB->ByteCount = cpu_to_le16(count);
1357 /* long_op set to 1 to allow for oplock break timeouts */
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1359 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1360 cifs_stats_inc(&tcon->num_opens);
1361 if (rc) {
1362 cFYI(1, ("Error in Open = %d", rc));
1363 } else {
1364 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1365 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1366 /* Let caller know file was created so we can set the mode. */
1367 /* Do we care about the CreateAction in any other cases? */
1368 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1369 *pOplock |= CIFS_CREATE_ACTION;
1370 if (pfile_info) {
1371 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1372 36 /* CreationTime to Attributes */);
1373 /* the file_info buf is endian converted by caller */
1374 pfile_info->AllocationSize = pSMBr->AllocationSize;
1375 pfile_info->EndOfFile = pSMBr->EndOfFile;
1376 pfile_info->NumberOfLinks = cpu_to_le32(1);
1380 cifs_buf_release(pSMB);
1381 if (rc == -EAGAIN)
1382 goto openRetry;
1383 return rc;
1387 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1388 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1389 char **buf, int *pbuf_type)
1391 int rc = -EACCES;
1392 READ_REQ *pSMB = NULL;
1393 READ_RSP *pSMBr = NULL;
1394 char *pReadData = NULL;
1395 int wct;
1396 int resp_buf_type = 0;
1397 struct kvec iov[1];
1399 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1400 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1401 wct = 12;
1402 else
1403 wct = 10; /* old style read */
1405 *nbytes = 0;
1406 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1407 if (rc)
1408 return rc;
1410 /* tcon and ses pointer are checked in smb_init */
1411 if (tcon->ses->server == NULL)
1412 return -ECONNABORTED;
1414 pSMB->AndXCommand = 0xFF; /* none */
1415 pSMB->Fid = netfid;
1416 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1417 if (wct == 12)
1418 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1419 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
1420 return -EIO;
1422 pSMB->Remaining = 0;
1423 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1424 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1425 if (wct == 12)
1426 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1427 else {
1428 /* old style read */
1429 struct smb_com_readx_req *pSMBW =
1430 (struct smb_com_readx_req *)pSMB;
1431 pSMBW->ByteCount = 0;
1434 iov[0].iov_base = (char *)pSMB;
1435 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1436 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1437 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1438 cifs_stats_inc(&tcon->num_reads);
1439 pSMBr = (READ_RSP *)iov[0].iov_base;
1440 if (rc) {
1441 cERROR(1, ("Send error in read = %d", rc));
1442 } else {
1443 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1444 data_length = data_length << 16;
1445 data_length += le16_to_cpu(pSMBr->DataLength);
1446 *nbytes = data_length;
1448 /*check that DataLength would not go beyond end of SMB */
1449 if ((data_length > CIFSMaxBufSize)
1450 || (data_length > count)) {
1451 cFYI(1, ("bad length %d for count %d",
1452 data_length, count));
1453 rc = -EIO;
1454 *nbytes = 0;
1455 } else {
1456 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1457 le16_to_cpu(pSMBr->DataOffset);
1458 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1459 cERROR(1,("Faulting on read rc = %d",rc));
1460 rc = -EFAULT;
1461 }*/ /* can not use copy_to_user when using page cache*/
1462 if (*buf)
1463 memcpy(*buf, pReadData, data_length);
1467 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1468 if (*buf) {
1469 if (resp_buf_type == CIFS_SMALL_BUFFER)
1470 cifs_small_buf_release(iov[0].iov_base);
1471 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1472 cifs_buf_release(iov[0].iov_base);
1473 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1474 /* return buffer to caller to free */
1475 *buf = iov[0].iov_base;
1476 if (resp_buf_type == CIFS_SMALL_BUFFER)
1477 *pbuf_type = CIFS_SMALL_BUFFER;
1478 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1479 *pbuf_type = CIFS_LARGE_BUFFER;
1480 } /* else no valid buffer on return - leave as null */
1482 /* Note: On -EAGAIN error only caller can retry on handle based calls
1483 since file handle passed in no longer valid */
1484 return rc;
1489 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1490 const int netfid, const unsigned int count,
1491 const __u64 offset, unsigned int *nbytes, const char *buf,
1492 const char __user *ubuf, const int long_op)
1494 int rc = -EACCES;
1495 WRITE_REQ *pSMB = NULL;
1496 WRITE_RSP *pSMBr = NULL;
1497 int bytes_returned, wct;
1498 __u32 bytes_sent;
1499 __u16 byte_count;
1501 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1502 if (tcon->ses == NULL)
1503 return -ECONNABORTED;
1505 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1506 wct = 14;
1507 else
1508 wct = 12;
1510 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1511 (void **) &pSMBr);
1512 if (rc)
1513 return rc;
1514 /* tcon and ses pointer are checked in smb_init */
1515 if (tcon->ses->server == NULL)
1516 return -ECONNABORTED;
1518 pSMB->AndXCommand = 0xFF; /* none */
1519 pSMB->Fid = netfid;
1520 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1521 if (wct == 14)
1522 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1523 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1524 return -EIO;
1526 pSMB->Reserved = 0xFFFFFFFF;
1527 pSMB->WriteMode = 0;
1528 pSMB->Remaining = 0;
1530 /* Can increase buffer size if buffer is big enough in some cases ie we
1531 can send more if LARGE_WRITE_X capability returned by the server and if
1532 our buffer is big enough or if we convert to iovecs on socket writes
1533 and eliminate the copy to the CIFS buffer */
1534 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1535 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1536 } else {
1537 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1538 & ~0xFF;
1541 if (bytes_sent > count)
1542 bytes_sent = count;
1543 pSMB->DataOffset =
1544 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1545 if (buf)
1546 memcpy(pSMB->Data, buf, bytes_sent);
1547 else if (ubuf) {
1548 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1549 cifs_buf_release(pSMB);
1550 return -EFAULT;
1552 } else if (count != 0) {
1553 /* No buffer */
1554 cifs_buf_release(pSMB);
1555 return -EINVAL;
1556 } /* else setting file size with write of zero bytes */
1557 if (wct == 14)
1558 byte_count = bytes_sent + 1; /* pad */
1559 else /* wct == 12 */ {
1560 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1562 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1563 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1564 pSMB->hdr.smb_buf_length += byte_count;
1566 if (wct == 14)
1567 pSMB->ByteCount = cpu_to_le16(byte_count);
1568 else { /* old style write has byte count 4 bytes earlier
1569 so 4 bytes pad */
1570 struct smb_com_writex_req *pSMBW =
1571 (struct smb_com_writex_req *)pSMB;
1572 pSMBW->ByteCount = cpu_to_le16(byte_count);
1575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1576 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1577 cifs_stats_inc(&tcon->num_writes);
1578 if (rc) {
1579 cFYI(1, ("Send error in write = %d", rc));
1580 *nbytes = 0;
1581 } else {
1582 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1583 *nbytes = (*nbytes) << 16;
1584 *nbytes += le16_to_cpu(pSMBr->Count);
1587 * Mask off high 16 bits when bytes written as returned by the
1588 * server is greater than bytes requested by the client. Some
1589 * OS/2 servers are known to set incorrect CountHigh values.
1591 if (*nbytes > count)
1592 *nbytes &= 0xFFFF;
1595 cifs_buf_release(pSMB);
1597 /* Note: On -EAGAIN error only caller can retry on handle based calls
1598 since file handle passed in no longer valid */
1600 return rc;
1604 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1605 const int netfid, const unsigned int count,
1606 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1607 int n_vec, const int long_op)
1609 int rc = -EACCES;
1610 WRITE_REQ *pSMB = NULL;
1611 int wct;
1612 int smb_hdr_len;
1613 int resp_buf_type = 0;
1615 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1617 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1618 wct = 14;
1619 else
1620 wct = 12;
1621 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1622 if (rc)
1623 return rc;
1624 /* tcon and ses pointer are checked in smb_init */
1625 if (tcon->ses->server == NULL)
1626 return -ECONNABORTED;
1628 pSMB->AndXCommand = 0xFF; /* none */
1629 pSMB->Fid = netfid;
1630 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1631 if (wct == 14)
1632 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1633 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1634 return -EIO;
1635 pSMB->Reserved = 0xFFFFFFFF;
1636 pSMB->WriteMode = 0;
1637 pSMB->Remaining = 0;
1639 pSMB->DataOffset =
1640 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1642 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1643 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1644 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1645 if (wct == 14)
1646 pSMB->hdr.smb_buf_length += count+1;
1647 else /* wct == 12 */
1648 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1649 if (wct == 14)
1650 pSMB->ByteCount = cpu_to_le16(count + 1);
1651 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1652 struct smb_com_writex_req *pSMBW =
1653 (struct smb_com_writex_req *)pSMB;
1654 pSMBW->ByteCount = cpu_to_le16(count + 5);
1656 iov[0].iov_base = pSMB;
1657 if (wct == 14)
1658 iov[0].iov_len = smb_hdr_len + 4;
1659 else /* wct == 12 pad bigger by four bytes */
1660 iov[0].iov_len = smb_hdr_len + 8;
1663 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1664 long_op);
1665 cifs_stats_inc(&tcon->num_writes);
1666 if (rc) {
1667 cFYI(1, ("Send error Write2 = %d", rc));
1668 *nbytes = 0;
1669 } else if (resp_buf_type == 0) {
1670 /* presumably this can not happen, but best to be safe */
1671 rc = -EIO;
1672 *nbytes = 0;
1673 } else {
1674 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1675 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1676 *nbytes = (*nbytes) << 16;
1677 *nbytes += le16_to_cpu(pSMBr->Count);
1680 * Mask off high 16 bits when bytes written as returned by the
1681 * server is greater than bytes requested by the client. OS/2
1682 * servers are known to set incorrect CountHigh values.
1684 if (*nbytes > count)
1685 *nbytes &= 0xFFFF;
1688 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1689 if (resp_buf_type == CIFS_SMALL_BUFFER)
1690 cifs_small_buf_release(iov[0].iov_base);
1691 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1692 cifs_buf_release(iov[0].iov_base);
1694 /* Note: On -EAGAIN error only caller can retry on handle based calls
1695 since file handle passed in no longer valid */
1697 return rc;
1702 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1703 const __u16 smb_file_id, const __u64 len,
1704 const __u64 offset, const __u32 numUnlock,
1705 const __u32 numLock, const __u8 lockType, const int waitFlag)
1707 int rc = 0;
1708 LOCK_REQ *pSMB = NULL;
1709 LOCK_RSP *pSMBr = NULL;
1710 int bytes_returned;
1711 int timeout = 0;
1712 __u16 count;
1714 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock));
1715 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1717 if (rc)
1718 return rc;
1720 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1722 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1723 timeout = CIFS_ASYNC_OP; /* no response expected */
1724 pSMB->Timeout = 0;
1725 } else if (waitFlag == TRUE) {
1726 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1727 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1728 } else {
1729 pSMB->Timeout = 0;
1732 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1733 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1734 pSMB->LockType = lockType;
1735 pSMB->AndXCommand = 0xFF; /* none */
1736 pSMB->Fid = smb_file_id; /* netfid stays le */
1738 if ((numLock != 0) || (numUnlock != 0)) {
1739 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1740 /* BB where to store pid high? */
1741 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1742 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1743 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1744 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1745 count = sizeof(LOCKING_ANDX_RANGE);
1746 } else {
1747 /* oplock break */
1748 count = 0;
1750 pSMB->hdr.smb_buf_length += count;
1751 pSMB->ByteCount = cpu_to_le16(count);
1753 if (waitFlag) {
1754 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1755 (struct smb_hdr *) pSMBr, &bytes_returned);
1756 cifs_small_buf_release(pSMB);
1757 } else {
1758 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1759 timeout);
1760 /* SMB buffer freed by function above */
1762 cifs_stats_inc(&tcon->num_locks);
1763 if (rc) {
1764 cFYI(1, ("Send error in Lock = %d", rc));
1767 /* Note: On -EAGAIN error only caller can retry on handle based calls
1768 since file handle passed in no longer valid */
1769 return rc;
1773 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1774 const __u16 smb_file_id, const int get_flag, const __u64 len,
1775 struct file_lock *pLockData, const __u16 lock_type,
1776 const int waitFlag)
1778 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1779 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1780 struct cifs_posix_lock *parm_data;
1781 int rc = 0;
1782 int timeout = 0;
1783 int bytes_returned = 0;
1784 int resp_buf_type = 0;
1785 __u16 params, param_offset, offset, byte_count, count;
1786 struct kvec iov[1];
1788 cFYI(1, ("Posix Lock"));
1790 if (pLockData == NULL)
1791 return EINVAL;
1793 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1795 if (rc)
1796 return rc;
1798 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1800 params = 6;
1801 pSMB->MaxSetupCount = 0;
1802 pSMB->Reserved = 0;
1803 pSMB->Flags = 0;
1804 pSMB->Reserved2 = 0;
1805 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1806 offset = param_offset + params;
1808 count = sizeof(struct cifs_posix_lock);
1809 pSMB->MaxParameterCount = cpu_to_le16(2);
1810 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1811 pSMB->SetupCount = 1;
1812 pSMB->Reserved3 = 0;
1813 if (get_flag)
1814 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1815 else
1816 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1817 byte_count = 3 /* pad */ + params + count;
1818 pSMB->DataCount = cpu_to_le16(count);
1819 pSMB->ParameterCount = cpu_to_le16(params);
1820 pSMB->TotalDataCount = pSMB->DataCount;
1821 pSMB->TotalParameterCount = pSMB->ParameterCount;
1822 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1823 parm_data = (struct cifs_posix_lock *)
1824 (((char *) &pSMB->hdr.Protocol) + offset);
1826 parm_data->lock_type = cpu_to_le16(lock_type);
1827 if (waitFlag) {
1828 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1829 parm_data->lock_flags = cpu_to_le16(1);
1830 pSMB->Timeout = cpu_to_le32(-1);
1831 } else
1832 pSMB->Timeout = 0;
1834 parm_data->pid = cpu_to_le32(current->tgid);
1835 parm_data->start = cpu_to_le64(pLockData->fl_start);
1836 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1838 pSMB->DataOffset = cpu_to_le16(offset);
1839 pSMB->Fid = smb_file_id;
1840 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1841 pSMB->Reserved4 = 0;
1842 pSMB->hdr.smb_buf_length += byte_count;
1843 pSMB->ByteCount = cpu_to_le16(byte_count);
1844 if (waitFlag) {
1845 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1846 (struct smb_hdr *) pSMBr, &bytes_returned);
1847 } else {
1848 iov[0].iov_base = (char *)pSMB;
1849 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1850 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1851 &resp_buf_type, timeout);
1852 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1853 not try to free it twice below on exit */
1854 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1857 if (rc) {
1858 cFYI(1, ("Send error in Posix Lock = %d", rc));
1859 } else if (get_flag) {
1860 /* lock structure can be returned on get */
1861 __u16 data_offset;
1862 __u16 data_count;
1863 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1865 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1866 rc = -EIO; /* bad smb */
1867 goto plk_err_exit;
1869 if (pLockData == NULL) {
1870 rc = -EINVAL;
1871 goto plk_err_exit;
1873 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1874 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1875 if (data_count < sizeof(struct cifs_posix_lock)) {
1876 rc = -EIO;
1877 goto plk_err_exit;
1879 parm_data = (struct cifs_posix_lock *)
1880 ((char *)&pSMBr->hdr.Protocol + data_offset);
1881 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1882 pLockData->fl_type = F_UNLCK;
1885 plk_err_exit:
1886 if (pSMB)
1887 cifs_small_buf_release(pSMB);
1889 if (resp_buf_type == CIFS_SMALL_BUFFER)
1890 cifs_small_buf_release(iov[0].iov_base);
1891 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1892 cifs_buf_release(iov[0].iov_base);
1894 /* Note: On -EAGAIN error only caller can retry on handle based calls
1895 since file handle passed in no longer valid */
1897 return rc;
1902 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1904 int rc = 0;
1905 CLOSE_REQ *pSMB = NULL;
1906 cFYI(1, ("In CIFSSMBClose"));
1908 /* do not retry on dead session on close */
1909 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1910 if (rc == -EAGAIN)
1911 return 0;
1912 if (rc)
1913 return rc;
1915 pSMB->FileID = (__u16) smb_file_id;
1916 pSMB->LastWriteTime = 0xFFFFFFFF;
1917 pSMB->ByteCount = 0;
1918 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1919 cifs_stats_inc(&tcon->num_closes);
1920 if (rc) {
1921 if (rc != -EINTR) {
1922 /* EINTR is expected when user ctl-c to kill app */
1923 cERROR(1, ("Send error in Close = %d", rc));
1927 /* Since session is dead, file will be closed on server already */
1928 if (rc == -EAGAIN)
1929 rc = 0;
1931 return rc;
1935 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1936 const char *fromName, const char *toName,
1937 const struct nls_table *nls_codepage, int remap)
1939 int rc = 0;
1940 RENAME_REQ *pSMB = NULL;
1941 RENAME_RSP *pSMBr = NULL;
1942 int bytes_returned;
1943 int name_len, name_len2;
1944 __u16 count;
1946 cFYI(1, ("In CIFSSMBRename"));
1947 renameRetry:
1948 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1949 (void **) &pSMBr);
1950 if (rc)
1951 return rc;
1953 pSMB->BufferFormat = 0x04;
1954 pSMB->SearchAttributes =
1955 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1956 ATTR_DIRECTORY);
1958 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1959 name_len =
1960 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1961 PATH_MAX, nls_codepage, remap);
1962 name_len++; /* trailing null */
1963 name_len *= 2;
1964 pSMB->OldFileName[name_len] = 0x04; /* pad */
1965 /* protocol requires ASCII signature byte on Unicode string */
1966 pSMB->OldFileName[name_len + 1] = 0x00;
1967 name_len2 =
1968 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1969 toName, PATH_MAX, nls_codepage, remap);
1970 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1971 name_len2 *= 2; /* convert to bytes */
1972 } else { /* BB improve the check for buffer overruns BB */
1973 name_len = strnlen(fromName, PATH_MAX);
1974 name_len++; /* trailing null */
1975 strncpy(pSMB->OldFileName, fromName, name_len);
1976 name_len2 = strnlen(toName, PATH_MAX);
1977 name_len2++; /* trailing null */
1978 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1979 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1980 name_len2++; /* trailing null */
1981 name_len2++; /* signature byte */
1984 count = 1 /* 1st signature byte */ + name_len + name_len2;
1985 pSMB->hdr.smb_buf_length += count;
1986 pSMB->ByteCount = cpu_to_le16(count);
1988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1990 cifs_stats_inc(&tcon->num_renames);
1991 if (rc) {
1992 cFYI(1, ("Send error in rename = %d", rc));
1995 cifs_buf_release(pSMB);
1997 if (rc == -EAGAIN)
1998 goto renameRetry;
2000 return rc;
2003 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2004 int netfid, char *target_name,
2005 const struct nls_table *nls_codepage, int remap)
2007 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2008 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2009 struct set_file_rename *rename_info;
2010 char *data_offset;
2011 char dummy_string[30];
2012 int rc = 0;
2013 int bytes_returned = 0;
2014 int len_of_str;
2015 __u16 params, param_offset, offset, count, byte_count;
2017 cFYI(1, ("Rename to File by handle"));
2018 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2019 (void **) &pSMBr);
2020 if (rc)
2021 return rc;
2023 params = 6;
2024 pSMB->MaxSetupCount = 0;
2025 pSMB->Reserved = 0;
2026 pSMB->Flags = 0;
2027 pSMB->Timeout = 0;
2028 pSMB->Reserved2 = 0;
2029 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2030 offset = param_offset + params;
2032 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2033 rename_info = (struct set_file_rename *) data_offset;
2034 pSMB->MaxParameterCount = cpu_to_le16(2);
2035 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2036 pSMB->SetupCount = 1;
2037 pSMB->Reserved3 = 0;
2038 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2039 byte_count = 3 /* pad */ + params;
2040 pSMB->ParameterCount = cpu_to_le16(params);
2041 pSMB->TotalParameterCount = pSMB->ParameterCount;
2042 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2043 pSMB->DataOffset = cpu_to_le16(offset);
2044 /* construct random name ".cifs_tmp<inodenum><mid>" */
2045 rename_info->overwrite = cpu_to_le32(1);
2046 rename_info->root_fid = 0;
2047 /* unicode only call */
2048 if (target_name == NULL) {
2049 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2050 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2051 dummy_string, 24, nls_codepage, remap);
2052 } else {
2053 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2054 target_name, PATH_MAX, nls_codepage,
2055 remap);
2057 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2058 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2059 byte_count += count;
2060 pSMB->DataCount = cpu_to_le16(count);
2061 pSMB->TotalDataCount = pSMB->DataCount;
2062 pSMB->Fid = netfid;
2063 pSMB->InformationLevel =
2064 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2065 pSMB->Reserved4 = 0;
2066 pSMB->hdr.smb_buf_length += byte_count;
2067 pSMB->ByteCount = cpu_to_le16(byte_count);
2068 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2070 cifs_stats_inc(&pTcon->num_t2renames);
2071 if (rc) {
2072 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2075 cifs_buf_release(pSMB);
2077 /* Note: On -EAGAIN error only caller can retry on handle based calls
2078 since file handle passed in no longer valid */
2080 return rc;
2084 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2085 const __u16 target_tid, const char *toName, const int flags,
2086 const struct nls_table *nls_codepage, int remap)
2088 int rc = 0;
2089 COPY_REQ *pSMB = NULL;
2090 COPY_RSP *pSMBr = NULL;
2091 int bytes_returned;
2092 int name_len, name_len2;
2093 __u16 count;
2095 cFYI(1, ("In CIFSSMBCopy"));
2096 copyRetry:
2097 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2098 (void **) &pSMBr);
2099 if (rc)
2100 return rc;
2102 pSMB->BufferFormat = 0x04;
2103 pSMB->Tid2 = target_tid;
2105 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2107 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2108 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2109 fromName, PATH_MAX, nls_codepage,
2110 remap);
2111 name_len++; /* trailing null */
2112 name_len *= 2;
2113 pSMB->OldFileName[name_len] = 0x04; /* pad */
2114 /* protocol requires ASCII signature byte on Unicode string */
2115 pSMB->OldFileName[name_len + 1] = 0x00;
2116 name_len2 =
2117 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2118 toName, PATH_MAX, nls_codepage, remap);
2119 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2120 name_len2 *= 2; /* convert to bytes */
2121 } else { /* BB improve the check for buffer overruns BB */
2122 name_len = strnlen(fromName, PATH_MAX);
2123 name_len++; /* trailing null */
2124 strncpy(pSMB->OldFileName, fromName, name_len);
2125 name_len2 = strnlen(toName, PATH_MAX);
2126 name_len2++; /* trailing null */
2127 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2128 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2129 name_len2++; /* trailing null */
2130 name_len2++; /* signature byte */
2133 count = 1 /* 1st signature byte */ + name_len + name_len2;
2134 pSMB->hdr.smb_buf_length += count;
2135 pSMB->ByteCount = cpu_to_le16(count);
2137 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2138 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2139 if (rc) {
2140 cFYI(1, ("Send error in copy = %d with %d files copied",
2141 rc, le16_to_cpu(pSMBr->CopyCount)));
2143 if (pSMB)
2144 cifs_buf_release(pSMB);
2146 if (rc == -EAGAIN)
2147 goto copyRetry;
2149 return rc;
2153 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2154 const char *fromName, const char *toName,
2155 const struct nls_table *nls_codepage)
2157 TRANSACTION2_SPI_REQ *pSMB = NULL;
2158 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2159 char *data_offset;
2160 int name_len;
2161 int name_len_target;
2162 int rc = 0;
2163 int bytes_returned = 0;
2164 __u16 params, param_offset, offset, byte_count;
2166 cFYI(1, ("In Symlink Unix style"));
2167 createSymLinkRetry:
2168 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2169 (void **) &pSMBr);
2170 if (rc)
2171 return rc;
2173 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2174 name_len =
2175 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2176 /* find define for this maxpathcomponent */
2177 , nls_codepage);
2178 name_len++; /* trailing null */
2179 name_len *= 2;
2181 } else { /* BB improve the check for buffer overruns BB */
2182 name_len = strnlen(fromName, PATH_MAX);
2183 name_len++; /* trailing null */
2184 strncpy(pSMB->FileName, fromName, name_len);
2186 params = 6 + name_len;
2187 pSMB->MaxSetupCount = 0;
2188 pSMB->Reserved = 0;
2189 pSMB->Flags = 0;
2190 pSMB->Timeout = 0;
2191 pSMB->Reserved2 = 0;
2192 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2193 InformationLevel) - 4;
2194 offset = param_offset + params;
2196 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2198 name_len_target =
2199 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2200 /* find define for this maxpathcomponent */
2201 , nls_codepage);
2202 name_len_target++; /* trailing null */
2203 name_len_target *= 2;
2204 } else { /* BB improve the check for buffer overruns BB */
2205 name_len_target = strnlen(toName, PATH_MAX);
2206 name_len_target++; /* trailing null */
2207 strncpy(data_offset, toName, name_len_target);
2210 pSMB->MaxParameterCount = cpu_to_le16(2);
2211 /* BB find exact max on data count below from sess */
2212 pSMB->MaxDataCount = cpu_to_le16(1000);
2213 pSMB->SetupCount = 1;
2214 pSMB->Reserved3 = 0;
2215 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2216 byte_count = 3 /* pad */ + params + name_len_target;
2217 pSMB->DataCount = cpu_to_le16(name_len_target);
2218 pSMB->ParameterCount = cpu_to_le16(params);
2219 pSMB->TotalDataCount = pSMB->DataCount;
2220 pSMB->TotalParameterCount = pSMB->ParameterCount;
2221 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2222 pSMB->DataOffset = cpu_to_le16(offset);
2223 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2224 pSMB->Reserved4 = 0;
2225 pSMB->hdr.smb_buf_length += byte_count;
2226 pSMB->ByteCount = cpu_to_le16(byte_count);
2227 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2228 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2229 cifs_stats_inc(&tcon->num_symlinks);
2230 if (rc) {
2231 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2234 if (pSMB)
2235 cifs_buf_release(pSMB);
2237 if (rc == -EAGAIN)
2238 goto createSymLinkRetry;
2240 return rc;
2244 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2245 const char *fromName, const char *toName,
2246 const struct nls_table *nls_codepage, int remap)
2248 TRANSACTION2_SPI_REQ *pSMB = NULL;
2249 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2250 char *data_offset;
2251 int name_len;
2252 int name_len_target;
2253 int rc = 0;
2254 int bytes_returned = 0;
2255 __u16 params, param_offset, offset, byte_count;
2257 cFYI(1, ("In Create Hard link Unix style"));
2258 createHardLinkRetry:
2259 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2260 (void **) &pSMBr);
2261 if (rc)
2262 return rc;
2264 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2265 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2266 PATH_MAX, nls_codepage, remap);
2267 name_len++; /* trailing null */
2268 name_len *= 2;
2270 } else { /* BB improve the check for buffer overruns BB */
2271 name_len = strnlen(toName, PATH_MAX);
2272 name_len++; /* trailing null */
2273 strncpy(pSMB->FileName, toName, name_len);
2275 params = 6 + name_len;
2276 pSMB->MaxSetupCount = 0;
2277 pSMB->Reserved = 0;
2278 pSMB->Flags = 0;
2279 pSMB->Timeout = 0;
2280 pSMB->Reserved2 = 0;
2281 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2282 InformationLevel) - 4;
2283 offset = param_offset + params;
2285 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2286 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2287 name_len_target =
2288 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2289 nls_codepage, remap);
2290 name_len_target++; /* trailing null */
2291 name_len_target *= 2;
2292 } else { /* BB improve the check for buffer overruns BB */
2293 name_len_target = strnlen(fromName, PATH_MAX);
2294 name_len_target++; /* trailing null */
2295 strncpy(data_offset, fromName, name_len_target);
2298 pSMB->MaxParameterCount = cpu_to_le16(2);
2299 /* BB find exact max on data count below from sess*/
2300 pSMB->MaxDataCount = cpu_to_le16(1000);
2301 pSMB->SetupCount = 1;
2302 pSMB->Reserved3 = 0;
2303 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2304 byte_count = 3 /* pad */ + params + name_len_target;
2305 pSMB->ParameterCount = cpu_to_le16(params);
2306 pSMB->TotalParameterCount = pSMB->ParameterCount;
2307 pSMB->DataCount = cpu_to_le16(name_len_target);
2308 pSMB->TotalDataCount = pSMB->DataCount;
2309 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2310 pSMB->DataOffset = cpu_to_le16(offset);
2311 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2312 pSMB->Reserved4 = 0;
2313 pSMB->hdr.smb_buf_length += byte_count;
2314 pSMB->ByteCount = cpu_to_le16(byte_count);
2315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2317 cifs_stats_inc(&tcon->num_hardlinks);
2318 if (rc) {
2319 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2322 cifs_buf_release(pSMB);
2323 if (rc == -EAGAIN)
2324 goto createHardLinkRetry;
2326 return rc;
2330 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2331 const char *fromName, const char *toName,
2332 const struct nls_table *nls_codepage, int remap)
2334 int rc = 0;
2335 NT_RENAME_REQ *pSMB = NULL;
2336 RENAME_RSP *pSMBr = NULL;
2337 int bytes_returned;
2338 int name_len, name_len2;
2339 __u16 count;
2341 cFYI(1, ("In CIFSCreateHardLink"));
2342 winCreateHardLinkRetry:
2344 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2345 (void **) &pSMBr);
2346 if (rc)
2347 return rc;
2349 pSMB->SearchAttributes =
2350 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2351 ATTR_DIRECTORY);
2352 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2353 pSMB->ClusterCount = 0;
2355 pSMB->BufferFormat = 0x04;
2357 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2358 name_len =
2359 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2360 PATH_MAX, nls_codepage, remap);
2361 name_len++; /* trailing null */
2362 name_len *= 2;
2363 pSMB->OldFileName[name_len] = 0; /* pad */
2364 pSMB->OldFileName[name_len + 1] = 0x04;
2365 name_len2 =
2366 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2367 toName, PATH_MAX, nls_codepage, remap);
2368 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2369 name_len2 *= 2; /* convert to bytes */
2370 } else { /* BB improve the check for buffer overruns BB */
2371 name_len = strnlen(fromName, PATH_MAX);
2372 name_len++; /* trailing null */
2373 strncpy(pSMB->OldFileName, fromName, name_len);
2374 name_len2 = strnlen(toName, PATH_MAX);
2375 name_len2++; /* trailing null */
2376 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2377 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2378 name_len2++; /* trailing null */
2379 name_len2++; /* signature byte */
2382 count = 1 /* string type byte */ + name_len + name_len2;
2383 pSMB->hdr.smb_buf_length += count;
2384 pSMB->ByteCount = cpu_to_le16(count);
2386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2387 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2388 cifs_stats_inc(&tcon->num_hardlinks);
2389 if (rc) {
2390 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2392 cifs_buf_release(pSMB);
2393 if (rc == -EAGAIN)
2394 goto winCreateHardLinkRetry;
2396 return rc;
2400 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2401 const unsigned char *searchName,
2402 char *symlinkinfo, const int buflen,
2403 const struct nls_table *nls_codepage)
2405 /* SMB_QUERY_FILE_UNIX_LINK */
2406 TRANSACTION2_QPI_REQ *pSMB = NULL;
2407 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2408 int rc = 0;
2409 int bytes_returned;
2410 int name_len;
2411 __u16 params, byte_count;
2413 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2415 querySymLinkRetry:
2416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2417 (void **) &pSMBr);
2418 if (rc)
2419 return rc;
2421 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2422 name_len =
2423 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2424 PATH_MAX, nls_codepage);
2425 name_len++; /* trailing null */
2426 name_len *= 2;
2427 } else { /* BB improve the check for buffer overruns BB */
2428 name_len = strnlen(searchName, PATH_MAX);
2429 name_len++; /* trailing null */
2430 strncpy(pSMB->FileName, searchName, name_len);
2433 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2434 pSMB->TotalDataCount = 0;
2435 pSMB->MaxParameterCount = cpu_to_le16(2);
2436 /* BB find exact max data count below from sess structure BB */
2437 pSMB->MaxDataCount = cpu_to_le16(4000);
2438 pSMB->MaxSetupCount = 0;
2439 pSMB->Reserved = 0;
2440 pSMB->Flags = 0;
2441 pSMB->Timeout = 0;
2442 pSMB->Reserved2 = 0;
2443 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2444 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2445 pSMB->DataCount = 0;
2446 pSMB->DataOffset = 0;
2447 pSMB->SetupCount = 1;
2448 pSMB->Reserved3 = 0;
2449 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2450 byte_count = params + 1 /* pad */ ;
2451 pSMB->TotalParameterCount = cpu_to_le16(params);
2452 pSMB->ParameterCount = pSMB->TotalParameterCount;
2453 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2454 pSMB->Reserved4 = 0;
2455 pSMB->hdr.smb_buf_length += byte_count;
2456 pSMB->ByteCount = cpu_to_le16(byte_count);
2458 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2460 if (rc) {
2461 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2462 } else {
2463 /* decode response */
2465 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2466 if (rc || (pSMBr->ByteCount < 2))
2467 /* BB also check enough total bytes returned */
2468 rc = -EIO; /* bad smb */
2469 else {
2470 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2471 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2473 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2474 name_len = UniStrnlen((wchar_t *) ((char *)
2475 &pSMBr->hdr.Protocol + data_offset),
2476 min_t(const int, buflen, count) / 2);
2477 /* BB FIXME investigate remapping reserved chars here */
2478 cifs_strfromUCS_le(symlinkinfo,
2479 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2480 + data_offset),
2481 name_len, nls_codepage);
2482 } else {
2483 strncpy(symlinkinfo,
2484 (char *) &pSMBr->hdr.Protocol +
2485 data_offset,
2486 min_t(const int, buflen, count));
2488 symlinkinfo[buflen] = 0;
2489 /* just in case so calling code does not go off the end of buffer */
2492 cifs_buf_release(pSMB);
2493 if (rc == -EAGAIN)
2494 goto querySymLinkRetry;
2495 return rc;
2498 #ifdef CONFIG_CIFS_EXPERIMENTAL
2499 /* Initialize NT TRANSACT SMB into small smb request buffer.
2500 This assumes that all NT TRANSACTS that we init here have
2501 total parm and data under about 400 bytes (to fit in small cifs
2502 buffer size), which is the case so far, it easily fits. NB:
2503 Setup words themselves and ByteCount
2504 MaxSetupCount (size of returned setup area) and
2505 MaxParameterCount (returned parms size) must be set by caller */
2506 static int
2507 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2508 const int parm_len, struct cifsTconInfo *tcon,
2509 void **ret_buf)
2511 int rc;
2512 __u32 temp_offset;
2513 struct smb_com_ntransact_req *pSMB;
2515 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2516 (void **)&pSMB);
2517 if (rc)
2518 return rc;
2519 *ret_buf = (void *)pSMB;
2520 pSMB->Reserved = 0;
2521 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2522 pSMB->TotalDataCount = 0;
2523 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2524 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2525 pSMB->ParameterCount = pSMB->TotalParameterCount;
2526 pSMB->DataCount = pSMB->TotalDataCount;
2527 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2528 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2529 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2530 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2531 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2532 pSMB->SubCommand = cpu_to_le16(sub_command);
2533 return 0;
2536 static int
2537 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2538 __u32 *pparmlen, __u32 *pdatalen)
2540 char *end_of_smb;
2541 __u32 data_count, data_offset, parm_count, parm_offset;
2542 struct smb_com_ntransact_rsp *pSMBr;
2544 *pdatalen = 0;
2545 *pparmlen = 0;
2547 if (buf == NULL)
2548 return -EINVAL;
2550 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2552 /* ByteCount was converted from little endian in SendReceive */
2553 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2554 (char *)&pSMBr->ByteCount;
2556 data_offset = le32_to_cpu(pSMBr->DataOffset);
2557 data_count = le32_to_cpu(pSMBr->DataCount);
2558 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2559 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2561 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2562 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2564 /* should we also check that parm and data areas do not overlap? */
2565 if (*ppparm > end_of_smb) {
2566 cFYI(1, ("parms start after end of smb"));
2567 return -EINVAL;
2568 } else if (parm_count + *ppparm > end_of_smb) {
2569 cFYI(1, ("parm end after end of smb"));
2570 return -EINVAL;
2571 } else if (*ppdata > end_of_smb) {
2572 cFYI(1, ("data starts after end of smb"));
2573 return -EINVAL;
2574 } else if (data_count + *ppdata > end_of_smb) {
2575 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2576 *ppdata, data_count, (data_count + *ppdata),
2577 end_of_smb, pSMBr));
2578 return -EINVAL;
2579 } else if (parm_count + data_count > pSMBr->ByteCount) {
2580 cFYI(1, ("parm count and data count larger than SMB"));
2581 return -EINVAL;
2583 *pdatalen = data_count;
2584 *pparmlen = parm_count;
2585 return 0;
2587 #endif /* CIFS_EXPERIMENTAL */
2590 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2591 const unsigned char *searchName,
2592 char *symlinkinfo, const int buflen, __u16 fid,
2593 const struct nls_table *nls_codepage)
2595 int rc = 0;
2596 int bytes_returned;
2597 int name_len;
2598 struct smb_com_transaction_ioctl_req *pSMB;
2599 struct smb_com_transaction_ioctl_rsp *pSMBr;
2601 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2602 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2603 (void **) &pSMBr);
2604 if (rc)
2605 return rc;
2607 pSMB->TotalParameterCount = 0 ;
2608 pSMB->TotalDataCount = 0;
2609 pSMB->MaxParameterCount = cpu_to_le32(2);
2610 /* BB find exact data count max from sess structure BB */
2611 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2612 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2613 pSMB->MaxSetupCount = 4;
2614 pSMB->Reserved = 0;
2615 pSMB->ParameterOffset = 0;
2616 pSMB->DataCount = 0;
2617 pSMB->DataOffset = 0;
2618 pSMB->SetupCount = 4;
2619 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2620 pSMB->ParameterCount = pSMB->TotalParameterCount;
2621 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2622 pSMB->IsFsctl = 1; /* FSCTL */
2623 pSMB->IsRootFlag = 0;
2624 pSMB->Fid = fid; /* file handle always le */
2625 pSMB->ByteCount = 0;
2627 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2628 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2629 if (rc) {
2630 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2631 } else { /* decode response */
2632 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2633 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2634 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2635 /* BB also check enough total bytes returned */
2636 rc = -EIO; /* bad smb */
2637 else {
2638 if (data_count && (data_count < 2048)) {
2639 char *end_of_smb = 2 /* sizeof byte count */ +
2640 pSMBr->ByteCount +
2641 (char *)&pSMBr->ByteCount;
2643 struct reparse_data *reparse_buf =
2644 (struct reparse_data *)
2645 ((char *)&pSMBr->hdr.Protocol
2646 + data_offset);
2647 if ((char *)reparse_buf >= end_of_smb) {
2648 rc = -EIO;
2649 goto qreparse_out;
2651 if ((reparse_buf->LinkNamesBuf +
2652 reparse_buf->TargetNameOffset +
2653 reparse_buf->TargetNameLen) >
2654 end_of_smb) {
2655 cFYI(1, ("reparse buf beyond SMB"));
2656 rc = -EIO;
2657 goto qreparse_out;
2660 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2661 name_len = UniStrnlen((wchar_t *)
2662 (reparse_buf->LinkNamesBuf +
2663 reparse_buf->TargetNameOffset),
2664 min(buflen/2,
2665 reparse_buf->TargetNameLen / 2));
2666 cifs_strfromUCS_le(symlinkinfo,
2667 (__le16 *) (reparse_buf->LinkNamesBuf +
2668 reparse_buf->TargetNameOffset),
2669 name_len, nls_codepage);
2670 } else { /* ASCII names */
2671 strncpy(symlinkinfo,
2672 reparse_buf->LinkNamesBuf +
2673 reparse_buf->TargetNameOffset,
2674 min_t(const int, buflen,
2675 reparse_buf->TargetNameLen));
2677 } else {
2678 rc = -EIO;
2679 cFYI(1, ("Invalid return data count on "
2680 "get reparse info ioctl"));
2682 symlinkinfo[buflen] = 0; /* just in case so the caller
2683 does not go off the end of the buffer */
2684 cFYI(1, ("readlink result - %s", symlinkinfo));
2687 qreparse_out:
2688 cifs_buf_release(pSMB);
2690 /* Note: On -EAGAIN error only caller can retry on handle based calls
2691 since file handle passed in no longer valid */
2693 return rc;
2696 #ifdef CONFIG_CIFS_POSIX
2698 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2699 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2700 struct cifs_posix_ace *cifs_ace)
2702 /* u8 cifs fields do not need le conversion */
2703 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2704 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2705 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2706 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2708 return;
2711 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2712 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2713 const int acl_type, const int size_of_data_area)
2715 int size = 0;
2716 int i;
2717 __u16 count;
2718 struct cifs_posix_ace *pACE;
2719 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2720 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2722 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2723 return -EOPNOTSUPP;
2725 if (acl_type & ACL_TYPE_ACCESS) {
2726 count = le16_to_cpu(cifs_acl->access_entry_count);
2727 pACE = &cifs_acl->ace_array[0];
2728 size = sizeof(struct cifs_posix_acl);
2729 size += sizeof(struct cifs_posix_ace) * count;
2730 /* check if we would go beyond end of SMB */
2731 if (size_of_data_area < size) {
2732 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2733 size_of_data_area, size));
2734 return -EINVAL;
2736 } else if (acl_type & ACL_TYPE_DEFAULT) {
2737 count = le16_to_cpu(cifs_acl->access_entry_count);
2738 size = sizeof(struct cifs_posix_acl);
2739 size += sizeof(struct cifs_posix_ace) * count;
2740 /* skip past access ACEs to get to default ACEs */
2741 pACE = &cifs_acl->ace_array[count];
2742 count = le16_to_cpu(cifs_acl->default_entry_count);
2743 size += sizeof(struct cifs_posix_ace) * count;
2744 /* check if we would go beyond end of SMB */
2745 if (size_of_data_area < size)
2746 return -EINVAL;
2747 } else {
2748 /* illegal type */
2749 return -EINVAL;
2752 size = posix_acl_xattr_size(count);
2753 if ((buflen == 0) || (local_acl == NULL)) {
2754 /* used to query ACL EA size */
2755 } else if (size > buflen) {
2756 return -ERANGE;
2757 } else /* buffer big enough */ {
2758 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2759 for (i = 0; i < count ; i++) {
2760 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2761 pACE++;
2764 return size;
2767 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2768 const posix_acl_xattr_entry *local_ace)
2770 __u16 rc = 0; /* 0 = ACL converted ok */
2772 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2773 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2774 /* BB is there a better way to handle the large uid? */
2775 if (local_ace->e_id == cpu_to_le32(-1)) {
2776 /* Probably no need to le convert -1 on any arch but can not hurt */
2777 cifs_ace->cifs_uid = cpu_to_le64(-1);
2778 } else
2779 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2780 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2781 return rc;
2784 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2785 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2786 const int buflen, const int acl_type)
2788 __u16 rc = 0;
2789 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2790 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2791 int count;
2792 int i;
2794 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2795 return 0;
2797 count = posix_acl_xattr_count((size_t)buflen);
2798 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2799 "version of %d",
2800 count, buflen, le32_to_cpu(local_acl->a_version)));
2801 if (le32_to_cpu(local_acl->a_version) != 2) {
2802 cFYI(1, ("unknown POSIX ACL version %d",
2803 le32_to_cpu(local_acl->a_version)));
2804 return 0;
2806 cifs_acl->version = cpu_to_le16(1);
2807 if (acl_type == ACL_TYPE_ACCESS)
2808 cifs_acl->access_entry_count = cpu_to_le16(count);
2809 else if (acl_type == ACL_TYPE_DEFAULT)
2810 cifs_acl->default_entry_count = cpu_to_le16(count);
2811 else {
2812 cFYI(1, ("unknown ACL type %d", acl_type));
2813 return 0;
2815 for (i = 0; i < count; i++) {
2816 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2817 &local_acl->a_entries[i]);
2818 if (rc != 0) {
2819 /* ACE not converted */
2820 break;
2823 if (rc == 0) {
2824 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2825 rc += sizeof(struct cifs_posix_acl);
2826 /* BB add check to make sure ACL does not overflow SMB */
2828 return rc;
2832 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2833 const unsigned char *searchName,
2834 char *acl_inf, const int buflen, const int acl_type,
2835 const struct nls_table *nls_codepage, int remap)
2837 /* SMB_QUERY_POSIX_ACL */
2838 TRANSACTION2_QPI_REQ *pSMB = NULL;
2839 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2840 int rc = 0;
2841 int bytes_returned;
2842 int name_len;
2843 __u16 params, byte_count;
2845 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2847 queryAclRetry:
2848 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2849 (void **) &pSMBr);
2850 if (rc)
2851 return rc;
2853 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2854 name_len =
2855 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2856 PATH_MAX, nls_codepage, remap);
2857 name_len++; /* trailing null */
2858 name_len *= 2;
2859 pSMB->FileName[name_len] = 0;
2860 pSMB->FileName[name_len+1] = 0;
2861 } else { /* BB improve the check for buffer overruns BB */
2862 name_len = strnlen(searchName, PATH_MAX);
2863 name_len++; /* trailing null */
2864 strncpy(pSMB->FileName, searchName, name_len);
2867 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2868 pSMB->TotalDataCount = 0;
2869 pSMB->MaxParameterCount = cpu_to_le16(2);
2870 /* BB find exact max data count below from sess structure BB */
2871 pSMB->MaxDataCount = cpu_to_le16(4000);
2872 pSMB->MaxSetupCount = 0;
2873 pSMB->Reserved = 0;
2874 pSMB->Flags = 0;
2875 pSMB->Timeout = 0;
2876 pSMB->Reserved2 = 0;
2877 pSMB->ParameterOffset = cpu_to_le16(
2878 offsetof(struct smb_com_transaction2_qpi_req,
2879 InformationLevel) - 4);
2880 pSMB->DataCount = 0;
2881 pSMB->DataOffset = 0;
2882 pSMB->SetupCount = 1;
2883 pSMB->Reserved3 = 0;
2884 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2885 byte_count = params + 1 /* pad */ ;
2886 pSMB->TotalParameterCount = cpu_to_le16(params);
2887 pSMB->ParameterCount = pSMB->TotalParameterCount;
2888 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2889 pSMB->Reserved4 = 0;
2890 pSMB->hdr.smb_buf_length += byte_count;
2891 pSMB->ByteCount = cpu_to_le16(byte_count);
2893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2895 cifs_stats_inc(&tcon->num_acl_get);
2896 if (rc) {
2897 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2898 } else {
2899 /* decode response */
2901 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2902 if (rc || (pSMBr->ByteCount < 2))
2903 /* BB also check enough total bytes returned */
2904 rc = -EIO; /* bad smb */
2905 else {
2906 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2907 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2908 rc = cifs_copy_posix_acl(acl_inf,
2909 (char *)&pSMBr->hdr.Protocol+data_offset,
2910 buflen, acl_type, count);
2913 cifs_buf_release(pSMB);
2914 if (rc == -EAGAIN)
2915 goto queryAclRetry;
2916 return rc;
2920 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2921 const unsigned char *fileName,
2922 const char *local_acl, const int buflen,
2923 const int acl_type,
2924 const struct nls_table *nls_codepage, int remap)
2926 struct smb_com_transaction2_spi_req *pSMB = NULL;
2927 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2928 char *parm_data;
2929 int name_len;
2930 int rc = 0;
2931 int bytes_returned = 0;
2932 __u16 params, byte_count, data_count, param_offset, offset;
2934 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2935 setAclRetry:
2936 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2937 (void **) &pSMBr);
2938 if (rc)
2939 return rc;
2940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2941 name_len =
2942 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2943 PATH_MAX, nls_codepage, remap);
2944 name_len++; /* trailing null */
2945 name_len *= 2;
2946 } else { /* BB improve the check for buffer overruns BB */
2947 name_len = strnlen(fileName, PATH_MAX);
2948 name_len++; /* trailing null */
2949 strncpy(pSMB->FileName, fileName, name_len);
2951 params = 6 + name_len;
2952 pSMB->MaxParameterCount = cpu_to_le16(2);
2953 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2954 pSMB->MaxSetupCount = 0;
2955 pSMB->Reserved = 0;
2956 pSMB->Flags = 0;
2957 pSMB->Timeout = 0;
2958 pSMB->Reserved2 = 0;
2959 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2960 InformationLevel) - 4;
2961 offset = param_offset + params;
2962 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2963 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2965 /* convert to on the wire format for POSIX ACL */
2966 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2968 if (data_count == 0) {
2969 rc = -EOPNOTSUPP;
2970 goto setACLerrorExit;
2972 pSMB->DataOffset = cpu_to_le16(offset);
2973 pSMB->SetupCount = 1;
2974 pSMB->Reserved3 = 0;
2975 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2976 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2977 byte_count = 3 /* pad */ + params + data_count;
2978 pSMB->DataCount = cpu_to_le16(data_count);
2979 pSMB->TotalDataCount = pSMB->DataCount;
2980 pSMB->ParameterCount = cpu_to_le16(params);
2981 pSMB->TotalParameterCount = pSMB->ParameterCount;
2982 pSMB->Reserved4 = 0;
2983 pSMB->hdr.smb_buf_length += byte_count;
2984 pSMB->ByteCount = cpu_to_le16(byte_count);
2985 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2986 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2987 if (rc) {
2988 cFYI(1, ("Set POSIX ACL returned %d", rc));
2991 setACLerrorExit:
2992 cifs_buf_release(pSMB);
2993 if (rc == -EAGAIN)
2994 goto setAclRetry;
2995 return rc;
2998 /* BB fix tabs in this function FIXME BB */
3000 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
3001 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
3003 int rc = 0;
3004 struct smb_t2_qfi_req *pSMB = NULL;
3005 struct smb_t2_qfi_rsp *pSMBr = NULL;
3006 int bytes_returned;
3007 __u16 params, byte_count;
3009 cFYI(1, ("In GetExtAttr"));
3010 if (tcon == NULL)
3011 return -ENODEV;
3013 GetExtAttrRetry:
3014 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3015 (void **) &pSMBr);
3016 if (rc)
3017 return rc;
3019 params = 2 /* level */ +2 /* fid */;
3020 pSMB->t2.TotalDataCount = 0;
3021 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3022 /* BB find exact max data count below from sess structure BB */
3023 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3024 pSMB->t2.MaxSetupCount = 0;
3025 pSMB->t2.Reserved = 0;
3026 pSMB->t2.Flags = 0;
3027 pSMB->t2.Timeout = 0;
3028 pSMB->t2.Reserved2 = 0;
3029 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3030 Fid) - 4);
3031 pSMB->t2.DataCount = 0;
3032 pSMB->t2.DataOffset = 0;
3033 pSMB->t2.SetupCount = 1;
3034 pSMB->t2.Reserved3 = 0;
3035 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3036 byte_count = params + 1 /* pad */ ;
3037 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3038 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3039 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3040 pSMB->Pad = 0;
3041 pSMB->Fid = netfid;
3042 pSMB->hdr.smb_buf_length += byte_count;
3043 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3047 if (rc) {
3048 cFYI(1, ("error %d in GetExtAttr", rc));
3049 } else {
3050 /* decode response */
3051 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3052 if (rc || (pSMBr->ByteCount < 2))
3053 /* BB also check enough total bytes returned */
3054 /* If rc should we check for EOPNOSUPP and
3055 disable the srvino flag? or in caller? */
3056 rc = -EIO; /* bad smb */
3057 else {
3058 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3059 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3060 struct file_chattr_info *pfinfo;
3061 /* BB Do we need a cast or hash here ? */
3062 if (count != 16) {
3063 cFYI(1, ("Illegal size ret in GetExtAttr"));
3064 rc = -EIO;
3065 goto GetExtAttrOut;
3067 pfinfo = (struct file_chattr_info *)
3068 (data_offset + (char *) &pSMBr->hdr.Protocol);
3069 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3070 *pMask = le64_to_cpu(pfinfo->mask);
3073 GetExtAttrOut:
3074 cifs_buf_release(pSMB);
3075 if (rc == -EAGAIN)
3076 goto GetExtAttrRetry;
3077 return rc;
3080 #endif /* CONFIG_POSIX */
3082 #ifdef CONFIG_CIFS_EXPERIMENTAL
3083 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3085 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3086 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3088 int rc = 0;
3089 int buf_type = 0;
3090 QUERY_SEC_DESC_REQ * pSMB;
3091 struct kvec iov[1];
3093 cFYI(1, ("GetCifsACL"));
3095 *pbuflen = 0;
3096 *acl_inf = NULL;
3098 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3099 8 /* parm len */, tcon, (void **) &pSMB);
3100 if (rc)
3101 return rc;
3103 pSMB->MaxParameterCount = cpu_to_le32(4);
3104 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3105 pSMB->MaxSetupCount = 0;
3106 pSMB->Fid = fid; /* file handle always le */
3107 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3108 CIFS_ACL_DACL);
3109 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3110 pSMB->hdr.smb_buf_length += 11;
3111 iov[0].iov_base = (char *)pSMB;
3112 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3114 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3115 CIFS_STD_OP);
3116 cifs_stats_inc(&tcon->num_acl_get);
3117 if (rc) {
3118 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3119 } else { /* decode response */
3120 __le32 * parm;
3121 __u32 parm_len;
3122 __u32 acl_len;
3123 struct smb_com_ntransact_rsp *pSMBr;
3124 char *pdata;
3126 /* validate_nttransact */
3127 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3128 &pdata, &parm_len, pbuflen);
3129 if (rc)
3130 goto qsec_out;
3131 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3133 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3135 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3136 rc = -EIO; /* bad smb */
3137 *pbuflen = 0;
3138 goto qsec_out;
3141 /* BB check that data area is minimum length and as big as acl_len */
3143 acl_len = le32_to_cpu(*parm);
3144 if (acl_len != *pbuflen) {
3145 cERROR(1, ("acl length %d does not match %d",
3146 acl_len, *pbuflen));
3147 if (*pbuflen > acl_len)
3148 *pbuflen = acl_len;
3151 /* check if buffer is big enough for the acl
3152 header followed by the smallest SID */
3153 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3154 (*pbuflen >= 64 * 1024)) {
3155 cERROR(1, ("bad acl length %d", *pbuflen));
3156 rc = -EINVAL;
3157 *pbuflen = 0;
3158 } else {
3159 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3160 if (*acl_inf == NULL) {
3161 *pbuflen = 0;
3162 rc = -ENOMEM;
3164 memcpy(*acl_inf, pdata, *pbuflen);
3167 qsec_out:
3168 if (buf_type == CIFS_SMALL_BUFFER)
3169 cifs_small_buf_release(iov[0].iov_base);
3170 else if (buf_type == CIFS_LARGE_BUFFER)
3171 cifs_buf_release(iov[0].iov_base);
3172 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3173 return rc;
3175 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3177 /* Legacy Query Path Information call for lookup to old servers such
3178 as Win9x/WinME */
3179 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3180 const unsigned char *searchName,
3181 FILE_ALL_INFO *pFinfo,
3182 const struct nls_table *nls_codepage, int remap)
3184 QUERY_INFORMATION_REQ * pSMB;
3185 QUERY_INFORMATION_RSP * pSMBr;
3186 int rc = 0;
3187 int bytes_returned;
3188 int name_len;
3190 cFYI(1, ("In SMBQPath path %s", searchName));
3191 QInfRetry:
3192 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3193 (void **) &pSMBr);
3194 if (rc)
3195 return rc;
3197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3198 name_len =
3199 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3200 PATH_MAX, nls_codepage, remap);
3201 name_len++; /* trailing null */
3202 name_len *= 2;
3203 } else {
3204 name_len = strnlen(searchName, PATH_MAX);
3205 name_len++; /* trailing null */
3206 strncpy(pSMB->FileName, searchName, name_len);
3208 pSMB->BufferFormat = 0x04;
3209 name_len++; /* account for buffer type byte */
3210 pSMB->hdr.smb_buf_length += (__u16) name_len;
3211 pSMB->ByteCount = cpu_to_le16(name_len);
3213 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3214 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3215 if (rc) {
3216 cFYI(1, ("Send error in QueryInfo = %d", rc));
3217 } else if (pFinfo) { /* decode response */
3218 struct timespec ts;
3219 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3220 /* BB FIXME - add time zone adjustment BB */
3221 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3222 ts.tv_nsec = 0;
3223 ts.tv_sec = time;
3224 /* decode time fields */
3225 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3226 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3227 pFinfo->LastAccessTime = 0;
3228 pFinfo->AllocationSize =
3229 cpu_to_le64(le32_to_cpu(pSMBr->size));
3230 pFinfo->EndOfFile = pFinfo->AllocationSize;
3231 pFinfo->Attributes =
3232 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3233 } else
3234 rc = -EIO; /* bad buffer passed in */
3236 cifs_buf_release(pSMB);
3238 if (rc == -EAGAIN)
3239 goto QInfRetry;
3241 return rc;
3248 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3249 const unsigned char *searchName,
3250 FILE_ALL_INFO * pFindData,
3251 int legacy /* old style infolevel */,
3252 const struct nls_table *nls_codepage, int remap)
3254 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3255 TRANSACTION2_QPI_REQ *pSMB = NULL;
3256 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3257 int rc = 0;
3258 int bytes_returned;
3259 int name_len;
3260 __u16 params, byte_count;
3262 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3263 QPathInfoRetry:
3264 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3265 (void **) &pSMBr);
3266 if (rc)
3267 return rc;
3269 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3270 name_len =
3271 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3272 PATH_MAX, nls_codepage, remap);
3273 name_len++; /* trailing null */
3274 name_len *= 2;
3275 } else { /* BB improve the check for buffer overruns BB */
3276 name_len = strnlen(searchName, PATH_MAX);
3277 name_len++; /* trailing null */
3278 strncpy(pSMB->FileName, searchName, name_len);
3281 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3282 pSMB->TotalDataCount = 0;
3283 pSMB->MaxParameterCount = cpu_to_le16(2);
3284 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3285 pSMB->MaxSetupCount = 0;
3286 pSMB->Reserved = 0;
3287 pSMB->Flags = 0;
3288 pSMB->Timeout = 0;
3289 pSMB->Reserved2 = 0;
3290 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3291 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3292 pSMB->DataCount = 0;
3293 pSMB->DataOffset = 0;
3294 pSMB->SetupCount = 1;
3295 pSMB->Reserved3 = 0;
3296 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3297 byte_count = params + 1 /* pad */ ;
3298 pSMB->TotalParameterCount = cpu_to_le16(params);
3299 pSMB->ParameterCount = pSMB->TotalParameterCount;
3300 if (legacy)
3301 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3302 else
3303 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3304 pSMB->Reserved4 = 0;
3305 pSMB->hdr.smb_buf_length += byte_count;
3306 pSMB->ByteCount = cpu_to_le16(byte_count);
3308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3309 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3310 if (rc) {
3311 cFYI(1, ("Send error in QPathInfo = %d", rc));
3312 } else { /* decode response */
3313 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3315 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3316 rc = -EIO;
3317 else if (!legacy && (pSMBr->ByteCount < 40))
3318 rc = -EIO; /* bad smb */
3319 else if (legacy && (pSMBr->ByteCount < 24))
3320 rc = -EIO; /* 24 or 26 expected but we do not read
3321 last field */
3322 else if (pFindData) {
3323 int size;
3324 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3325 if (legacy) /* we do not read the last field, EAsize,
3326 fortunately since it varies by subdialect
3327 and on Set vs. Get, is two bytes or 4
3328 bytes depending but we don't care here */
3329 size = sizeof(FILE_INFO_STANDARD);
3330 else
3331 size = sizeof(FILE_ALL_INFO);
3332 memcpy((char *) pFindData,
3333 (char *) &pSMBr->hdr.Protocol +
3334 data_offset, size);
3335 } else
3336 rc = -ENOMEM;
3338 cifs_buf_release(pSMB);
3339 if (rc == -EAGAIN)
3340 goto QPathInfoRetry;
3342 return rc;
3346 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3347 const unsigned char *searchName,
3348 FILE_UNIX_BASIC_INFO * pFindData,
3349 const struct nls_table *nls_codepage, int remap)
3351 /* SMB_QUERY_FILE_UNIX_BASIC */
3352 TRANSACTION2_QPI_REQ *pSMB = NULL;
3353 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3354 int rc = 0;
3355 int bytes_returned = 0;
3356 int name_len;
3357 __u16 params, byte_count;
3359 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3360 UnixQPathInfoRetry:
3361 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3362 (void **) &pSMBr);
3363 if (rc)
3364 return rc;
3366 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3367 name_len =
3368 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3369 PATH_MAX, nls_codepage, remap);
3370 name_len++; /* trailing null */
3371 name_len *= 2;
3372 } else { /* BB improve the check for buffer overruns BB */
3373 name_len = strnlen(searchName, PATH_MAX);
3374 name_len++; /* trailing null */
3375 strncpy(pSMB->FileName, searchName, name_len);
3378 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3379 pSMB->TotalDataCount = 0;
3380 pSMB->MaxParameterCount = cpu_to_le16(2);
3381 /* BB find exact max SMB PDU from sess structure BB */
3382 pSMB->MaxDataCount = cpu_to_le16(4000);
3383 pSMB->MaxSetupCount = 0;
3384 pSMB->Reserved = 0;
3385 pSMB->Flags = 0;
3386 pSMB->Timeout = 0;
3387 pSMB->Reserved2 = 0;
3388 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3389 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3390 pSMB->DataCount = 0;
3391 pSMB->DataOffset = 0;
3392 pSMB->SetupCount = 1;
3393 pSMB->Reserved3 = 0;
3394 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3395 byte_count = params + 1 /* pad */ ;
3396 pSMB->TotalParameterCount = cpu_to_le16(params);
3397 pSMB->ParameterCount = pSMB->TotalParameterCount;
3398 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3399 pSMB->Reserved4 = 0;
3400 pSMB->hdr.smb_buf_length += byte_count;
3401 pSMB->ByteCount = cpu_to_le16(byte_count);
3403 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3404 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3405 if (rc) {
3406 cFYI(1, ("Send error in QPathInfo = %d", rc));
3407 } else { /* decode response */
3408 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3410 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3411 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3412 "Unix Extensions can be disabled on mount "
3413 "by specifying the nosfu mount option."));
3414 rc = -EIO; /* bad smb */
3415 } else {
3416 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3417 memcpy((char *) pFindData,
3418 (char *) &pSMBr->hdr.Protocol +
3419 data_offset,
3420 sizeof(FILE_UNIX_BASIC_INFO));
3423 cifs_buf_release(pSMB);
3424 if (rc == -EAGAIN)
3425 goto UnixQPathInfoRetry;
3427 return rc;
3430 #if 0 /* function unused at present */
3431 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3432 const char *searchName, FILE_ALL_INFO * findData,
3433 const struct nls_table *nls_codepage)
3435 /* level 257 SMB_ */
3436 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3437 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3438 int rc = 0;
3439 int bytes_returned;
3440 int name_len;
3441 __u16 params, byte_count;
3443 cFYI(1, ("In FindUnique"));
3444 findUniqueRetry:
3445 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3446 (void **) &pSMBr);
3447 if (rc)
3448 return rc;
3450 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3451 name_len =
3452 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3453 PATH_MAX, nls_codepage);
3454 name_len++; /* trailing null */
3455 name_len *= 2;
3456 } else { /* BB improve the check for buffer overruns BB */
3457 name_len = strnlen(searchName, PATH_MAX);
3458 name_len++; /* trailing null */
3459 strncpy(pSMB->FileName, searchName, name_len);
3462 params = 12 + name_len /* includes null */ ;
3463 pSMB->TotalDataCount = 0; /* no EAs */
3464 pSMB->MaxParameterCount = cpu_to_le16(2);
3465 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3466 pSMB->MaxSetupCount = 0;
3467 pSMB->Reserved = 0;
3468 pSMB->Flags = 0;
3469 pSMB->Timeout = 0;
3470 pSMB->Reserved2 = 0;
3471 pSMB->ParameterOffset = cpu_to_le16(
3472 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
3473 pSMB->DataCount = 0;
3474 pSMB->DataOffset = 0;
3475 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3476 pSMB->Reserved3 = 0;
3477 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3478 byte_count = params + 1 /* pad */ ;
3479 pSMB->TotalParameterCount = cpu_to_le16(params);
3480 pSMB->ParameterCount = pSMB->TotalParameterCount;
3481 pSMB->SearchAttributes =
3482 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3483 ATTR_DIRECTORY);
3484 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3485 pSMB->SearchFlags = cpu_to_le16(1);
3486 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3487 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3488 pSMB->hdr.smb_buf_length += byte_count;
3489 pSMB->ByteCount = cpu_to_le16(byte_count);
3491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3494 if (rc) {
3495 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3496 } else { /* decode response */
3497 cifs_stats_inc(&tcon->num_ffirst);
3498 /* BB fill in */
3501 cifs_buf_release(pSMB);
3502 if (rc == -EAGAIN)
3503 goto findUniqueRetry;
3505 return rc;
3507 #endif /* end unused (temporarily) function */
3509 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3511 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3512 const char *searchName,
3513 const struct nls_table *nls_codepage,
3514 __u16 *pnetfid,
3515 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3517 /* level 257 SMB_ */
3518 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3519 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3520 T2_FFIRST_RSP_PARMS * parms;
3521 int rc = 0;
3522 int bytes_returned = 0;
3523 int name_len;
3524 __u16 params, byte_count;
3526 cFYI(1, ("In FindFirst for %s", searchName));
3528 findFirstRetry:
3529 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3530 (void **) &pSMBr);
3531 if (rc)
3532 return rc;
3534 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3535 name_len =
3536 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3537 PATH_MAX, nls_codepage, remap);
3538 /* We can not add the asterik earlier in case
3539 it got remapped to 0xF03A as if it were part of the
3540 directory name instead of a wildcard */
3541 name_len *= 2;
3542 pSMB->FileName[name_len] = dirsep;
3543 pSMB->FileName[name_len+1] = 0;
3544 pSMB->FileName[name_len+2] = '*';
3545 pSMB->FileName[name_len+3] = 0;
3546 name_len += 4; /* now the trailing null */
3547 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3548 pSMB->FileName[name_len+1] = 0;
3549 name_len += 2;
3550 } else { /* BB add check for overrun of SMB buf BB */
3551 name_len = strnlen(searchName, PATH_MAX);
3552 /* BB fix here and in unicode clause above ie
3553 if (name_len > buffersize-header)
3554 free buffer exit; BB */
3555 strncpy(pSMB->FileName, searchName, name_len);
3556 pSMB->FileName[name_len] = dirsep;
3557 pSMB->FileName[name_len+1] = '*';
3558 pSMB->FileName[name_len+2] = 0;
3559 name_len += 3;
3562 params = 12 + name_len /* includes null */ ;
3563 pSMB->TotalDataCount = 0; /* no EAs */
3564 pSMB->MaxParameterCount = cpu_to_le16(10);
3565 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3566 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3567 pSMB->MaxSetupCount = 0;
3568 pSMB->Reserved = 0;
3569 pSMB->Flags = 0;
3570 pSMB->Timeout = 0;
3571 pSMB->Reserved2 = 0;
3572 byte_count = params + 1 /* pad */ ;
3573 pSMB->TotalParameterCount = cpu_to_le16(params);
3574 pSMB->ParameterCount = pSMB->TotalParameterCount;
3575 pSMB->ParameterOffset = cpu_to_le16(
3576 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3577 - 4);
3578 pSMB->DataCount = 0;
3579 pSMB->DataOffset = 0;
3580 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3581 pSMB->Reserved3 = 0;
3582 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3583 pSMB->SearchAttributes =
3584 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3585 ATTR_DIRECTORY);
3586 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3587 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3588 CIFS_SEARCH_RETURN_RESUME);
3589 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3591 /* BB what should we set StorageType to? Does it matter? BB */
3592 pSMB->SearchStorageType = 0;
3593 pSMB->hdr.smb_buf_length += byte_count;
3594 pSMB->ByteCount = cpu_to_le16(byte_count);
3596 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3597 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3598 cifs_stats_inc(&tcon->num_ffirst);
3600 if (rc) {/* BB add logic to retry regular search if Unix search
3601 rejected unexpectedly by server */
3602 /* BB Add code to handle unsupported level rc */
3603 cFYI(1, ("Error in FindFirst = %d", rc));
3605 cifs_buf_release(pSMB);
3607 /* BB eventually could optimize out free and realloc of buf */
3608 /* for this case */
3609 if (rc == -EAGAIN)
3610 goto findFirstRetry;
3611 } else { /* decode response */
3612 /* BB remember to free buffer if error BB */
3613 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3614 if (rc == 0) {
3615 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3616 psrch_inf->unicode = TRUE;
3617 else
3618 psrch_inf->unicode = FALSE;
3620 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3621 psrch_inf->smallBuf = 0;
3622 psrch_inf->srch_entries_start =
3623 (char *) &pSMBr->hdr.Protocol +
3624 le16_to_cpu(pSMBr->t2.DataOffset);
3625 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3626 le16_to_cpu(pSMBr->t2.ParameterOffset));
3628 if (parms->EndofSearch)
3629 psrch_inf->endOfSearch = TRUE;
3630 else
3631 psrch_inf->endOfSearch = FALSE;
3633 psrch_inf->entries_in_buffer =
3634 le16_to_cpu(parms->SearchCount);
3635 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3636 psrch_inf->entries_in_buffer;
3637 *pnetfid = parms->SearchHandle;
3638 } else {
3639 cifs_buf_release(pSMB);
3643 return rc;
3646 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3647 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3649 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3650 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3651 T2_FNEXT_RSP_PARMS * parms;
3652 char *response_data;
3653 int rc = 0;
3654 int bytes_returned, name_len;
3655 __u16 params, byte_count;
3657 cFYI(1, ("In FindNext"));
3659 if (psrch_inf->endOfSearch == TRUE)
3660 return -ENOENT;
3662 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3663 (void **) &pSMBr);
3664 if (rc)
3665 return rc;
3667 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3668 byte_count = 0;
3669 pSMB->TotalDataCount = 0; /* no EAs */
3670 pSMB->MaxParameterCount = cpu_to_le16(8);
3671 pSMB->MaxDataCount =
3672 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3673 0xFFFFFF00);
3674 pSMB->MaxSetupCount = 0;
3675 pSMB->Reserved = 0;
3676 pSMB->Flags = 0;
3677 pSMB->Timeout = 0;
3678 pSMB->Reserved2 = 0;
3679 pSMB->ParameterOffset = cpu_to_le16(
3680 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3681 pSMB->DataCount = 0;
3682 pSMB->DataOffset = 0;
3683 pSMB->SetupCount = 1;
3684 pSMB->Reserved3 = 0;
3685 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3686 pSMB->SearchHandle = searchHandle; /* always kept as le */
3687 pSMB->SearchCount =
3688 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3689 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3690 pSMB->ResumeKey = psrch_inf->resume_key;
3691 pSMB->SearchFlags =
3692 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3694 name_len = psrch_inf->resume_name_len;
3695 params += name_len;
3696 if (name_len < PATH_MAX) {
3697 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3698 byte_count += name_len;
3699 /* 14 byte parm len above enough for 2 byte null terminator */
3700 pSMB->ResumeFileName[name_len] = 0;
3701 pSMB->ResumeFileName[name_len+1] = 0;
3702 } else {
3703 rc = -EINVAL;
3704 goto FNext2_err_exit;
3706 byte_count = params + 1 /* pad */ ;
3707 pSMB->TotalParameterCount = cpu_to_le16(params);
3708 pSMB->ParameterCount = pSMB->TotalParameterCount;
3709 pSMB->hdr.smb_buf_length += byte_count;
3710 pSMB->ByteCount = cpu_to_le16(byte_count);
3712 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3713 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3714 cifs_stats_inc(&tcon->num_fnext);
3715 if (rc) {
3716 if (rc == -EBADF) {
3717 psrch_inf->endOfSearch = TRUE;
3718 rc = 0; /* search probably was closed at end of search*/
3719 } else
3720 cFYI(1, ("FindNext returned = %d", rc));
3721 } else { /* decode response */
3722 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3724 if (rc == 0) {
3725 /* BB fixme add lock for file (srch_info) struct here */
3726 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3727 psrch_inf->unicode = TRUE;
3728 else
3729 psrch_inf->unicode = FALSE;
3730 response_data = (char *) &pSMBr->hdr.Protocol +
3731 le16_to_cpu(pSMBr->t2.ParameterOffset);
3732 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3733 response_data = (char *)&pSMBr->hdr.Protocol +
3734 le16_to_cpu(pSMBr->t2.DataOffset);
3735 if (psrch_inf->smallBuf)
3736 cifs_small_buf_release(
3737 psrch_inf->ntwrk_buf_start);
3738 else
3739 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3740 psrch_inf->srch_entries_start = response_data;
3741 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3742 psrch_inf->smallBuf = 0;
3743 if (parms->EndofSearch)
3744 psrch_inf->endOfSearch = TRUE;
3745 else
3746 psrch_inf->endOfSearch = FALSE;
3747 psrch_inf->entries_in_buffer =
3748 le16_to_cpu(parms->SearchCount);
3749 psrch_inf->index_of_last_entry +=
3750 psrch_inf->entries_in_buffer;
3751 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3752 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3754 /* BB fixme add unlock here */
3759 /* BB On error, should we leave previous search buf (and count and
3760 last entry fields) intact or free the previous one? */
3762 /* Note: On -EAGAIN error only caller can retry on handle based calls
3763 since file handle passed in no longer valid */
3764 FNext2_err_exit:
3765 if (rc != 0)
3766 cifs_buf_release(pSMB);
3767 return rc;
3771 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3772 const __u16 searchHandle)
3774 int rc = 0;
3775 FINDCLOSE_REQ *pSMB = NULL;
3777 cFYI(1, ("In CIFSSMBFindClose"));
3778 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3780 /* no sense returning error if session restarted
3781 as file handle has been closed */
3782 if (rc == -EAGAIN)
3783 return 0;
3784 if (rc)
3785 return rc;
3787 pSMB->FileID = searchHandle;
3788 pSMB->ByteCount = 0;
3789 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3790 if (rc) {
3791 cERROR(1, ("Send error in FindClose = %d", rc));
3793 cifs_stats_inc(&tcon->num_fclose);
3795 /* Since session is dead, search handle closed on server already */
3796 if (rc == -EAGAIN)
3797 rc = 0;
3799 return rc;
3803 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3804 const unsigned char *searchName,
3805 __u64 * inode_number,
3806 const struct nls_table *nls_codepage, int remap)
3808 int rc = 0;
3809 TRANSACTION2_QPI_REQ *pSMB = NULL;
3810 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3811 int name_len, bytes_returned;
3812 __u16 params, byte_count;
3814 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3815 if (tcon == NULL)
3816 return -ENODEV;
3818 GetInodeNumberRetry:
3819 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3820 (void **) &pSMBr);
3821 if (rc)
3822 return rc;
3824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3825 name_len =
3826 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3827 PATH_MAX, nls_codepage, remap);
3828 name_len++; /* trailing null */
3829 name_len *= 2;
3830 } else { /* BB improve the check for buffer overruns BB */
3831 name_len = strnlen(searchName, PATH_MAX);
3832 name_len++; /* trailing null */
3833 strncpy(pSMB->FileName, searchName, name_len);
3836 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3837 pSMB->TotalDataCount = 0;
3838 pSMB->MaxParameterCount = cpu_to_le16(2);
3839 /* BB find exact max data count below from sess structure BB */
3840 pSMB->MaxDataCount = cpu_to_le16(4000);
3841 pSMB->MaxSetupCount = 0;
3842 pSMB->Reserved = 0;
3843 pSMB->Flags = 0;
3844 pSMB->Timeout = 0;
3845 pSMB->Reserved2 = 0;
3846 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3847 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3848 pSMB->DataCount = 0;
3849 pSMB->DataOffset = 0;
3850 pSMB->SetupCount = 1;
3851 pSMB->Reserved3 = 0;
3852 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3853 byte_count = params + 1 /* pad */ ;
3854 pSMB->TotalParameterCount = cpu_to_le16(params);
3855 pSMB->ParameterCount = pSMB->TotalParameterCount;
3856 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3857 pSMB->Reserved4 = 0;
3858 pSMB->hdr.smb_buf_length += byte_count;
3859 pSMB->ByteCount = cpu_to_le16(byte_count);
3861 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3862 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3863 if (rc) {
3864 cFYI(1, ("error %d in QueryInternalInfo", rc));
3865 } else {
3866 /* decode response */
3867 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3868 if (rc || (pSMBr->ByteCount < 2))
3869 /* BB also check enough total bytes returned */
3870 /* If rc should we check for EOPNOSUPP and
3871 disable the srvino flag? or in caller? */
3872 rc = -EIO; /* bad smb */
3873 else {
3874 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3875 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3876 struct file_internal_info *pfinfo;
3877 /* BB Do we need a cast or hash here ? */
3878 if (count < 8) {
3879 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3880 rc = -EIO;
3881 goto GetInodeNumOut;
3883 pfinfo = (struct file_internal_info *)
3884 (data_offset + (char *) &pSMBr->hdr.Protocol);
3885 *inode_number = pfinfo->UniqueId;
3888 GetInodeNumOut:
3889 cifs_buf_release(pSMB);
3890 if (rc == -EAGAIN)
3891 goto GetInodeNumberRetry;
3892 return rc;
3896 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3897 const unsigned char *searchName,
3898 unsigned char **targetUNCs,
3899 unsigned int *number_of_UNC_in_array,
3900 const struct nls_table *nls_codepage, int remap)
3902 /* TRANS2_GET_DFS_REFERRAL */
3903 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3904 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3905 struct dfs_referral_level_3 *referrals = NULL;
3906 int rc = 0;
3907 int bytes_returned;
3908 int name_len;
3909 unsigned int i;
3910 char *temp;
3911 __u16 params, byte_count;
3912 *number_of_UNC_in_array = 0;
3913 *targetUNCs = NULL;
3915 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3916 if (ses == NULL)
3917 return -ENODEV;
3918 getDFSRetry:
3919 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3920 (void **) &pSMBr);
3921 if (rc)
3922 return rc;
3924 /* server pointer checked in called function,
3925 but should never be null here anyway */
3926 pSMB->hdr.Mid = GetNextMid(ses->server);
3927 pSMB->hdr.Tid = ses->ipc_tid;
3928 pSMB->hdr.Uid = ses->Suid;
3929 if (ses->capabilities & CAP_STATUS32)
3930 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3931 if (ses->capabilities & CAP_DFS)
3932 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3934 if (ses->capabilities & CAP_UNICODE) {
3935 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3936 name_len =
3937 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3938 searchName, PATH_MAX, nls_codepage, remap);
3939 name_len++; /* trailing null */
3940 name_len *= 2;
3941 } else { /* BB improve the check for buffer overruns BB */
3942 name_len = strnlen(searchName, PATH_MAX);
3943 name_len++; /* trailing null */
3944 strncpy(pSMB->RequestFileName, searchName, name_len);
3947 if (ses->server) {
3948 if (ses->server->secMode &
3949 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3950 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3953 pSMB->hdr.Uid = ses->Suid;
3955 params = 2 /* level */ + name_len /*includes null */ ;
3956 pSMB->TotalDataCount = 0;
3957 pSMB->DataCount = 0;
3958 pSMB->DataOffset = 0;
3959 pSMB->MaxParameterCount = 0;
3960 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3961 pSMB->MaxSetupCount = 0;
3962 pSMB->Reserved = 0;
3963 pSMB->Flags = 0;
3964 pSMB->Timeout = 0;
3965 pSMB->Reserved2 = 0;
3966 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3967 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3968 pSMB->SetupCount = 1;
3969 pSMB->Reserved3 = 0;
3970 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3971 byte_count = params + 3 /* pad */ ;
3972 pSMB->ParameterCount = cpu_to_le16(params);
3973 pSMB->TotalParameterCount = pSMB->ParameterCount;
3974 pSMB->MaxReferralLevel = cpu_to_le16(3);
3975 pSMB->hdr.smb_buf_length += byte_count;
3976 pSMB->ByteCount = cpu_to_le16(byte_count);
3978 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3980 if (rc) {
3981 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3982 } else { /* decode response */
3983 /* BB Add logic to parse referrals here */
3984 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3986 /* BB Also check if enough total bytes returned? */
3987 if (rc || (pSMBr->ByteCount < 17))
3988 rc = -EIO; /* bad smb */
3989 else {
3990 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3991 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3993 cFYI(1,
3994 ("Decoding GetDFSRefer response BCC: %d Offset %d",
3995 pSMBr->ByteCount, data_offset));
3996 referrals =
3997 (struct dfs_referral_level_3 *)
3998 (8 /* sizeof start of data block */ +
3999 data_offset +
4000 (char *) &pSMBr->hdr.Protocol);
4001 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
4002 "for referral one refer size: 0x%x srv "
4003 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
4004 le16_to_cpu(pSMBr->NumberOfReferrals),
4005 le16_to_cpu(pSMBr->DFSFlags),
4006 le16_to_cpu(referrals->ReferralSize),
4007 le16_to_cpu(referrals->ServerType),
4008 le16_to_cpu(referrals->ReferralFlags),
4009 le16_to_cpu(referrals->TimeToLive)));
4010 /* BB This field is actually two bytes in from start of
4011 data block so we could do safety check that DataBlock
4012 begins at address of pSMBr->NumberOfReferrals */
4013 *number_of_UNC_in_array =
4014 le16_to_cpu(pSMBr->NumberOfReferrals);
4016 /* BB Fix below so can return more than one referral */
4017 if (*number_of_UNC_in_array > 1)
4018 *number_of_UNC_in_array = 1;
4020 /* get the length of the strings describing refs */
4021 name_len = 0;
4022 for (i = 0; i < *number_of_UNC_in_array; i++) {
4023 /* make sure that DfsPathOffset not past end */
4024 __u16 offset =
4025 le16_to_cpu(referrals->DfsPathOffset);
4026 if (offset > data_count) {
4027 /* if invalid referral, stop here and do
4028 not try to copy any more */
4029 *number_of_UNC_in_array = i;
4030 break;
4032 temp = ((char *)referrals) + offset;
4034 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4035 name_len += UniStrnlen((wchar_t *)temp,
4036 data_count);
4037 } else {
4038 name_len += strnlen(temp, data_count);
4040 referrals++;
4041 /* BB add check that referral pointer does
4042 not fall off end PDU */
4044 /* BB add check for name_len bigger than bcc */
4045 *targetUNCs =
4046 kmalloc(name_len+1+(*number_of_UNC_in_array),
4047 GFP_KERNEL);
4048 if (*targetUNCs == NULL) {
4049 rc = -ENOMEM;
4050 goto GetDFSRefExit;
4052 /* copy the ref strings */
4053 referrals = (struct dfs_referral_level_3 *)
4054 (8 /* sizeof data hdr */ + data_offset +
4055 (char *) &pSMBr->hdr.Protocol);
4057 for (i = 0; i < *number_of_UNC_in_array; i++) {
4058 temp = ((char *)referrals) +
4059 le16_to_cpu(referrals->DfsPathOffset);
4060 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4061 cifs_strfromUCS_le(*targetUNCs,
4062 (__le16 *) temp,
4063 name_len,
4064 nls_codepage);
4065 } else {
4066 strncpy(*targetUNCs, temp, name_len);
4068 /* BB update target_uncs pointers */
4069 referrals++;
4071 temp = *targetUNCs;
4072 temp[name_len] = 0;
4076 GetDFSRefExit:
4077 if (pSMB)
4078 cifs_buf_release(pSMB);
4080 if (rc == -EAGAIN)
4081 goto getDFSRetry;
4083 return rc;
4086 /* Query File System Info such as free space to old servers such as Win 9x */
4088 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4090 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4091 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4092 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4093 FILE_SYSTEM_ALLOC_INFO *response_data;
4094 int rc = 0;
4095 int bytes_returned = 0;
4096 __u16 params, byte_count;
4098 cFYI(1, ("OldQFSInfo"));
4099 oldQFSInfoRetry:
4100 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4101 (void **) &pSMBr);
4102 if (rc)
4103 return rc;
4105 params = 2; /* level */
4106 pSMB->TotalDataCount = 0;
4107 pSMB->MaxParameterCount = cpu_to_le16(2);
4108 pSMB->MaxDataCount = cpu_to_le16(1000);
4109 pSMB->MaxSetupCount = 0;
4110 pSMB->Reserved = 0;
4111 pSMB->Flags = 0;
4112 pSMB->Timeout = 0;
4113 pSMB->Reserved2 = 0;
4114 byte_count = params + 1 /* pad */ ;
4115 pSMB->TotalParameterCount = cpu_to_le16(params);
4116 pSMB->ParameterCount = pSMB->TotalParameterCount;
4117 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4118 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4119 pSMB->DataCount = 0;
4120 pSMB->DataOffset = 0;
4121 pSMB->SetupCount = 1;
4122 pSMB->Reserved3 = 0;
4123 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4124 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4125 pSMB->hdr.smb_buf_length += byte_count;
4126 pSMB->ByteCount = cpu_to_le16(byte_count);
4128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4130 if (rc) {
4131 cFYI(1, ("Send error in QFSInfo = %d", rc));
4132 } else { /* decode response */
4133 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4135 if (rc || (pSMBr->ByteCount < 18))
4136 rc = -EIO; /* bad smb */
4137 else {
4138 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4139 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4140 pSMBr->ByteCount, data_offset));
4142 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4143 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4144 FSData->f_bsize =
4145 le16_to_cpu(response_data->BytesPerSector) *
4146 le32_to_cpu(response_data->
4147 SectorsPerAllocationUnit);
4148 FSData->f_blocks =
4149 le32_to_cpu(response_data->TotalAllocationUnits);
4150 FSData->f_bfree = FSData->f_bavail =
4151 le32_to_cpu(response_data->FreeAllocationUnits);
4152 cFYI(1,
4153 ("Blocks: %lld Free: %lld Block size %ld",
4154 (unsigned long long)FSData->f_blocks,
4155 (unsigned long long)FSData->f_bfree,
4156 FSData->f_bsize));
4159 cifs_buf_release(pSMB);
4161 if (rc == -EAGAIN)
4162 goto oldQFSInfoRetry;
4164 return rc;
4168 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4170 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4171 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4172 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4173 FILE_SYSTEM_INFO *response_data;
4174 int rc = 0;
4175 int bytes_returned = 0;
4176 __u16 params, byte_count;
4178 cFYI(1, ("In QFSInfo"));
4179 QFSInfoRetry:
4180 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4181 (void **) &pSMBr);
4182 if (rc)
4183 return rc;
4185 params = 2; /* level */
4186 pSMB->TotalDataCount = 0;
4187 pSMB->MaxParameterCount = cpu_to_le16(2);
4188 pSMB->MaxDataCount = cpu_to_le16(1000);
4189 pSMB->MaxSetupCount = 0;
4190 pSMB->Reserved = 0;
4191 pSMB->Flags = 0;
4192 pSMB->Timeout = 0;
4193 pSMB->Reserved2 = 0;
4194 byte_count = params + 1 /* pad */ ;
4195 pSMB->TotalParameterCount = cpu_to_le16(params);
4196 pSMB->ParameterCount = pSMB->TotalParameterCount;
4197 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4198 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4199 pSMB->DataCount = 0;
4200 pSMB->DataOffset = 0;
4201 pSMB->SetupCount = 1;
4202 pSMB->Reserved3 = 0;
4203 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4204 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4205 pSMB->hdr.smb_buf_length += byte_count;
4206 pSMB->ByteCount = cpu_to_le16(byte_count);
4208 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4209 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4210 if (rc) {
4211 cFYI(1, ("Send error in QFSInfo = %d", rc));
4212 } else { /* decode response */
4213 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4215 if (rc || (pSMBr->ByteCount < 24))
4216 rc = -EIO; /* bad smb */
4217 else {
4218 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4220 response_data =
4221 (FILE_SYSTEM_INFO
4222 *) (((char *) &pSMBr->hdr.Protocol) +
4223 data_offset);
4224 FSData->f_bsize =
4225 le32_to_cpu(response_data->BytesPerSector) *
4226 le32_to_cpu(response_data->
4227 SectorsPerAllocationUnit);
4228 FSData->f_blocks =
4229 le64_to_cpu(response_data->TotalAllocationUnits);
4230 FSData->f_bfree = FSData->f_bavail =
4231 le64_to_cpu(response_data->FreeAllocationUnits);
4232 cFYI(1,
4233 ("Blocks: %lld Free: %lld Block size %ld",
4234 (unsigned long long)FSData->f_blocks,
4235 (unsigned long long)FSData->f_bfree,
4236 FSData->f_bsize));
4239 cifs_buf_release(pSMB);
4241 if (rc == -EAGAIN)
4242 goto QFSInfoRetry;
4244 return rc;
4248 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4250 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4251 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4252 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4253 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4254 int rc = 0;
4255 int bytes_returned = 0;
4256 __u16 params, byte_count;
4258 cFYI(1, ("In QFSAttributeInfo"));
4259 QFSAttributeRetry:
4260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4261 (void **) &pSMBr);
4262 if (rc)
4263 return rc;
4265 params = 2; /* level */
4266 pSMB->TotalDataCount = 0;
4267 pSMB->MaxParameterCount = cpu_to_le16(2);
4268 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4269 pSMB->MaxSetupCount = 0;
4270 pSMB->Reserved = 0;
4271 pSMB->Flags = 0;
4272 pSMB->Timeout = 0;
4273 pSMB->Reserved2 = 0;
4274 byte_count = params + 1 /* pad */ ;
4275 pSMB->TotalParameterCount = cpu_to_le16(params);
4276 pSMB->ParameterCount = pSMB->TotalParameterCount;
4277 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4278 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4279 pSMB->DataCount = 0;
4280 pSMB->DataOffset = 0;
4281 pSMB->SetupCount = 1;
4282 pSMB->Reserved3 = 0;
4283 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4284 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4285 pSMB->hdr.smb_buf_length += byte_count;
4286 pSMB->ByteCount = cpu_to_le16(byte_count);
4288 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4289 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4290 if (rc) {
4291 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4292 } else { /* decode response */
4293 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4295 if (rc || (pSMBr->ByteCount < 13)) {
4296 /* BB also check if enough bytes returned */
4297 rc = -EIO; /* bad smb */
4298 } else {
4299 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4300 response_data =
4301 (FILE_SYSTEM_ATTRIBUTE_INFO
4302 *) (((char *) &pSMBr->hdr.Protocol) +
4303 data_offset);
4304 memcpy(&tcon->fsAttrInfo, response_data,
4305 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4308 cifs_buf_release(pSMB);
4310 if (rc == -EAGAIN)
4311 goto QFSAttributeRetry;
4313 return rc;
4317 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4319 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4320 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4321 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4322 FILE_SYSTEM_DEVICE_INFO *response_data;
4323 int rc = 0;
4324 int bytes_returned = 0;
4325 __u16 params, byte_count;
4327 cFYI(1, ("In QFSDeviceInfo"));
4328 QFSDeviceRetry:
4329 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4330 (void **) &pSMBr);
4331 if (rc)
4332 return rc;
4334 params = 2; /* level */
4335 pSMB->TotalDataCount = 0;
4336 pSMB->MaxParameterCount = cpu_to_le16(2);
4337 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4338 pSMB->MaxSetupCount = 0;
4339 pSMB->Reserved = 0;
4340 pSMB->Flags = 0;
4341 pSMB->Timeout = 0;
4342 pSMB->Reserved2 = 0;
4343 byte_count = params + 1 /* pad */ ;
4344 pSMB->TotalParameterCount = cpu_to_le16(params);
4345 pSMB->ParameterCount = pSMB->TotalParameterCount;
4346 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4347 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4349 pSMB->DataCount = 0;
4350 pSMB->DataOffset = 0;
4351 pSMB->SetupCount = 1;
4352 pSMB->Reserved3 = 0;
4353 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4354 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4355 pSMB->hdr.smb_buf_length += byte_count;
4356 pSMB->ByteCount = cpu_to_le16(byte_count);
4358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4360 if (rc) {
4361 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4362 } else { /* decode response */
4363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4365 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4366 rc = -EIO; /* bad smb */
4367 else {
4368 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4369 response_data =
4370 (FILE_SYSTEM_DEVICE_INFO *)
4371 (((char *) &pSMBr->hdr.Protocol) +
4372 data_offset);
4373 memcpy(&tcon->fsDevInfo, response_data,
4374 sizeof(FILE_SYSTEM_DEVICE_INFO));
4377 cifs_buf_release(pSMB);
4379 if (rc == -EAGAIN)
4380 goto QFSDeviceRetry;
4382 return rc;
4386 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4388 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4389 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4390 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4391 FILE_SYSTEM_UNIX_INFO *response_data;
4392 int rc = 0;
4393 int bytes_returned = 0;
4394 __u16 params, byte_count;
4396 cFYI(1, ("In QFSUnixInfo"));
4397 QFSUnixRetry:
4398 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4399 (void **) &pSMBr);
4400 if (rc)
4401 return rc;
4403 params = 2; /* level */
4404 pSMB->TotalDataCount = 0;
4405 pSMB->DataCount = 0;
4406 pSMB->DataOffset = 0;
4407 pSMB->MaxParameterCount = cpu_to_le16(2);
4408 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4409 pSMB->MaxSetupCount = 0;
4410 pSMB->Reserved = 0;
4411 pSMB->Flags = 0;
4412 pSMB->Timeout = 0;
4413 pSMB->Reserved2 = 0;
4414 byte_count = params + 1 /* pad */ ;
4415 pSMB->ParameterCount = cpu_to_le16(params);
4416 pSMB->TotalParameterCount = pSMB->ParameterCount;
4417 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4418 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4419 pSMB->SetupCount = 1;
4420 pSMB->Reserved3 = 0;
4421 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4422 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4423 pSMB->hdr.smb_buf_length += byte_count;
4424 pSMB->ByteCount = cpu_to_le16(byte_count);
4426 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4428 if (rc) {
4429 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4430 } else { /* decode response */
4431 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4433 if (rc || (pSMBr->ByteCount < 13)) {
4434 rc = -EIO; /* bad smb */
4435 } else {
4436 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4437 response_data =
4438 (FILE_SYSTEM_UNIX_INFO
4439 *) (((char *) &pSMBr->hdr.Protocol) +
4440 data_offset);
4441 memcpy(&tcon->fsUnixInfo, response_data,
4442 sizeof(FILE_SYSTEM_UNIX_INFO));
4445 cifs_buf_release(pSMB);
4447 if (rc == -EAGAIN)
4448 goto QFSUnixRetry;
4451 return rc;
4455 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4457 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4458 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4459 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4460 int rc = 0;
4461 int bytes_returned = 0;
4462 __u16 params, param_offset, offset, byte_count;
4464 cFYI(1, ("In SETFSUnixInfo"));
4465 SETFSUnixRetry:
4466 /* BB switch to small buf init to save memory */
4467 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4468 (void **) &pSMBr);
4469 if (rc)
4470 return rc;
4472 params = 4; /* 2 bytes zero followed by info level. */
4473 pSMB->MaxSetupCount = 0;
4474 pSMB->Reserved = 0;
4475 pSMB->Flags = 0;
4476 pSMB->Timeout = 0;
4477 pSMB->Reserved2 = 0;
4478 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4479 - 4;
4480 offset = param_offset + params;
4482 pSMB->MaxParameterCount = cpu_to_le16(4);
4483 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4484 pSMB->SetupCount = 1;
4485 pSMB->Reserved3 = 0;
4486 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4487 byte_count = 1 /* pad */ + params + 12;
4489 pSMB->DataCount = cpu_to_le16(12);
4490 pSMB->ParameterCount = cpu_to_le16(params);
4491 pSMB->TotalDataCount = pSMB->DataCount;
4492 pSMB->TotalParameterCount = pSMB->ParameterCount;
4493 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4494 pSMB->DataOffset = cpu_to_le16(offset);
4496 /* Params. */
4497 pSMB->FileNum = 0;
4498 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4500 /* Data. */
4501 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4502 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4503 pSMB->ClientUnixCap = cpu_to_le64(cap);
4505 pSMB->hdr.smb_buf_length += byte_count;
4506 pSMB->ByteCount = cpu_to_le16(byte_count);
4508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4510 if (rc) {
4511 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4512 } else { /* decode response */
4513 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4514 if (rc) {
4515 rc = -EIO; /* bad smb */
4518 cifs_buf_release(pSMB);
4520 if (rc == -EAGAIN)
4521 goto SETFSUnixRetry;
4523 return rc;
4529 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4530 struct kstatfs *FSData)
4532 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4533 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4534 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4535 FILE_SYSTEM_POSIX_INFO *response_data;
4536 int rc = 0;
4537 int bytes_returned = 0;
4538 __u16 params, byte_count;
4540 cFYI(1, ("In QFSPosixInfo"));
4541 QFSPosixRetry:
4542 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4543 (void **) &pSMBr);
4544 if (rc)
4545 return rc;
4547 params = 2; /* level */
4548 pSMB->TotalDataCount = 0;
4549 pSMB->DataCount = 0;
4550 pSMB->DataOffset = 0;
4551 pSMB->MaxParameterCount = cpu_to_le16(2);
4552 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4553 pSMB->MaxSetupCount = 0;
4554 pSMB->Reserved = 0;
4555 pSMB->Flags = 0;
4556 pSMB->Timeout = 0;
4557 pSMB->Reserved2 = 0;
4558 byte_count = params + 1 /* pad */ ;
4559 pSMB->ParameterCount = cpu_to_le16(params);
4560 pSMB->TotalParameterCount = pSMB->ParameterCount;
4561 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4562 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4563 pSMB->SetupCount = 1;
4564 pSMB->Reserved3 = 0;
4565 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4566 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4567 pSMB->hdr.smb_buf_length += byte_count;
4568 pSMB->ByteCount = cpu_to_le16(byte_count);
4570 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4571 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4572 if (rc) {
4573 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4574 } else { /* decode response */
4575 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4577 if (rc || (pSMBr->ByteCount < 13)) {
4578 rc = -EIO; /* bad smb */
4579 } else {
4580 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4581 response_data =
4582 (FILE_SYSTEM_POSIX_INFO
4583 *) (((char *) &pSMBr->hdr.Protocol) +
4584 data_offset);
4585 FSData->f_bsize =
4586 le32_to_cpu(response_data->BlockSize);
4587 FSData->f_blocks =
4588 le64_to_cpu(response_data->TotalBlocks);
4589 FSData->f_bfree =
4590 le64_to_cpu(response_data->BlocksAvail);
4591 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4592 FSData->f_bavail = FSData->f_bfree;
4593 } else {
4594 FSData->f_bavail =
4595 le64_to_cpu(response_data->UserBlocksAvail);
4597 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4598 FSData->f_files =
4599 le64_to_cpu(response_data->TotalFileNodes);
4600 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4601 FSData->f_ffree =
4602 le64_to_cpu(response_data->FreeFileNodes);
4605 cifs_buf_release(pSMB);
4607 if (rc == -EAGAIN)
4608 goto QFSPosixRetry;
4610 return rc;
4614 /* We can not use write of zero bytes trick to
4615 set file size due to need for large file support. Also note that
4616 this SetPathInfo is preferred to SetFileInfo based method in next
4617 routine which is only needed to work around a sharing violation bug
4618 in Samba which this routine can run into */
4621 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4622 __u64 size, int SetAllocation,
4623 const struct nls_table *nls_codepage, int remap)
4625 struct smb_com_transaction2_spi_req *pSMB = NULL;
4626 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4627 struct file_end_of_file_info *parm_data;
4628 int name_len;
4629 int rc = 0;
4630 int bytes_returned = 0;
4631 __u16 params, byte_count, data_count, param_offset, offset;
4633 cFYI(1, ("In SetEOF"));
4634 SetEOFRetry:
4635 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4636 (void **) &pSMBr);
4637 if (rc)
4638 return rc;
4640 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4641 name_len =
4642 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4643 PATH_MAX, nls_codepage, remap);
4644 name_len++; /* trailing null */
4645 name_len *= 2;
4646 } else { /* BB improve the check for buffer overruns BB */
4647 name_len = strnlen(fileName, PATH_MAX);
4648 name_len++; /* trailing null */
4649 strncpy(pSMB->FileName, fileName, name_len);
4651 params = 6 + name_len;
4652 data_count = sizeof(struct file_end_of_file_info);
4653 pSMB->MaxParameterCount = cpu_to_le16(2);
4654 pSMB->MaxDataCount = cpu_to_le16(4100);
4655 pSMB->MaxSetupCount = 0;
4656 pSMB->Reserved = 0;
4657 pSMB->Flags = 0;
4658 pSMB->Timeout = 0;
4659 pSMB->Reserved2 = 0;
4660 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4661 InformationLevel) - 4;
4662 offset = param_offset + params;
4663 if (SetAllocation) {
4664 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4665 pSMB->InformationLevel =
4666 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4667 else
4668 pSMB->InformationLevel =
4669 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4670 } else /* Set File Size */ {
4671 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4672 pSMB->InformationLevel =
4673 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4674 else
4675 pSMB->InformationLevel =
4676 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4679 parm_data =
4680 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4681 offset);
4682 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4683 pSMB->DataOffset = cpu_to_le16(offset);
4684 pSMB->SetupCount = 1;
4685 pSMB->Reserved3 = 0;
4686 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4687 byte_count = 3 /* pad */ + params + data_count;
4688 pSMB->DataCount = cpu_to_le16(data_count);
4689 pSMB->TotalDataCount = pSMB->DataCount;
4690 pSMB->ParameterCount = cpu_to_le16(params);
4691 pSMB->TotalParameterCount = pSMB->ParameterCount;
4692 pSMB->Reserved4 = 0;
4693 pSMB->hdr.smb_buf_length += byte_count;
4694 parm_data->FileSize = cpu_to_le64(size);
4695 pSMB->ByteCount = cpu_to_le16(byte_count);
4696 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4697 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4698 if (rc) {
4699 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4702 cifs_buf_release(pSMB);
4704 if (rc == -EAGAIN)
4705 goto SetEOFRetry;
4707 return rc;
4711 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4712 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4714 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4715 char *data_offset;
4716 struct file_end_of_file_info *parm_data;
4717 int rc = 0;
4718 __u16 params, param_offset, offset, byte_count, count;
4720 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4721 (long long)size));
4722 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4724 if (rc)
4725 return rc;
4727 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4728 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4730 params = 6;
4731 pSMB->MaxSetupCount = 0;
4732 pSMB->Reserved = 0;
4733 pSMB->Flags = 0;
4734 pSMB->Timeout = 0;
4735 pSMB->Reserved2 = 0;
4736 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4737 offset = param_offset + params;
4739 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4741 count = sizeof(struct file_end_of_file_info);
4742 pSMB->MaxParameterCount = cpu_to_le16(2);
4743 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4744 pSMB->SetupCount = 1;
4745 pSMB->Reserved3 = 0;
4746 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4747 byte_count = 3 /* pad */ + params + count;
4748 pSMB->DataCount = cpu_to_le16(count);
4749 pSMB->ParameterCount = cpu_to_le16(params);
4750 pSMB->TotalDataCount = pSMB->DataCount;
4751 pSMB->TotalParameterCount = pSMB->ParameterCount;
4752 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4753 parm_data =
4754 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4755 + offset);
4756 pSMB->DataOffset = cpu_to_le16(offset);
4757 parm_data->FileSize = cpu_to_le64(size);
4758 pSMB->Fid = fid;
4759 if (SetAllocation) {
4760 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4761 pSMB->InformationLevel =
4762 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4763 else
4764 pSMB->InformationLevel =
4765 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4766 } else /* Set File Size */ {
4767 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4768 pSMB->InformationLevel =
4769 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4770 else
4771 pSMB->InformationLevel =
4772 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4774 pSMB->Reserved4 = 0;
4775 pSMB->hdr.smb_buf_length += byte_count;
4776 pSMB->ByteCount = cpu_to_le16(byte_count);
4777 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4778 if (rc) {
4779 cFYI(1,
4780 ("Send error in SetFileInfo (SetFileSize) = %d",
4781 rc));
4784 /* Note: On -EAGAIN error only caller can retry on handle based calls
4785 since file handle passed in no longer valid */
4787 return rc;
4790 /* Some legacy servers such as NT4 require that the file times be set on
4791 an open handle, rather than by pathname - this is awkward due to
4792 potential access conflicts on the open, but it is unavoidable for these
4793 old servers since the only other choice is to go from 100 nanosecond DCE
4794 time and resort to the original setpathinfo level which takes the ancient
4795 DOS time format with 2 second granularity */
4797 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4798 const FILE_BASIC_INFO *data, __u16 fid)
4800 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4801 char *data_offset;
4802 int rc = 0;
4803 __u16 params, param_offset, offset, byte_count, count;
4805 cFYI(1, ("Set Times (via SetFileInfo)"));
4806 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4808 if (rc)
4809 return rc;
4811 /* At this point there is no need to override the current pid
4812 with the pid of the opener, but that could change if we someday
4813 use an existing handle (rather than opening one on the fly) */
4814 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4815 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4817 params = 6;
4818 pSMB->MaxSetupCount = 0;
4819 pSMB->Reserved = 0;
4820 pSMB->Flags = 0;
4821 pSMB->Timeout = 0;
4822 pSMB->Reserved2 = 0;
4823 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4824 offset = param_offset + params;
4826 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4828 count = sizeof(FILE_BASIC_INFO);
4829 pSMB->MaxParameterCount = cpu_to_le16(2);
4830 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4831 pSMB->SetupCount = 1;
4832 pSMB->Reserved3 = 0;
4833 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4834 byte_count = 3 /* pad */ + params + count;
4835 pSMB->DataCount = cpu_to_le16(count);
4836 pSMB->ParameterCount = cpu_to_le16(params);
4837 pSMB->TotalDataCount = pSMB->DataCount;
4838 pSMB->TotalParameterCount = pSMB->ParameterCount;
4839 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4840 pSMB->DataOffset = cpu_to_le16(offset);
4841 pSMB->Fid = fid;
4842 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4843 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4844 else
4845 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4846 pSMB->Reserved4 = 0;
4847 pSMB->hdr.smb_buf_length += byte_count;
4848 pSMB->ByteCount = cpu_to_le16(byte_count);
4849 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4850 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4851 if (rc) {
4852 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4855 /* Note: On -EAGAIN error only caller can retry on handle based calls
4856 since file handle passed in no longer valid */
4858 return rc;
4863 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4864 const FILE_BASIC_INFO *data,
4865 const struct nls_table *nls_codepage, int remap)
4867 TRANSACTION2_SPI_REQ *pSMB = NULL;
4868 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4869 int name_len;
4870 int rc = 0;
4871 int bytes_returned = 0;
4872 char *data_offset;
4873 __u16 params, param_offset, offset, byte_count, count;
4875 cFYI(1, ("In SetTimes"));
4877 SetTimesRetry:
4878 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4879 (void **) &pSMBr);
4880 if (rc)
4881 return rc;
4883 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4884 name_len =
4885 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4886 PATH_MAX, nls_codepage, remap);
4887 name_len++; /* trailing null */
4888 name_len *= 2;
4889 } else { /* BB improve the check for buffer overruns BB */
4890 name_len = strnlen(fileName, PATH_MAX);
4891 name_len++; /* trailing null */
4892 strncpy(pSMB->FileName, fileName, name_len);
4895 params = 6 + name_len;
4896 count = sizeof(FILE_BASIC_INFO);
4897 pSMB->MaxParameterCount = cpu_to_le16(2);
4898 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4899 pSMB->MaxSetupCount = 0;
4900 pSMB->Reserved = 0;
4901 pSMB->Flags = 0;
4902 pSMB->Timeout = 0;
4903 pSMB->Reserved2 = 0;
4904 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4905 InformationLevel) - 4;
4906 offset = param_offset + params;
4907 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4908 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4909 pSMB->DataOffset = cpu_to_le16(offset);
4910 pSMB->SetupCount = 1;
4911 pSMB->Reserved3 = 0;
4912 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4913 byte_count = 3 /* pad */ + params + count;
4915 pSMB->DataCount = cpu_to_le16(count);
4916 pSMB->ParameterCount = cpu_to_le16(params);
4917 pSMB->TotalDataCount = pSMB->DataCount;
4918 pSMB->TotalParameterCount = pSMB->ParameterCount;
4919 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4920 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4921 else
4922 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4923 pSMB->Reserved4 = 0;
4924 pSMB->hdr.smb_buf_length += byte_count;
4925 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4926 pSMB->ByteCount = cpu_to_le16(byte_count);
4927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4929 if (rc) {
4930 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4933 cifs_buf_release(pSMB);
4935 if (rc == -EAGAIN)
4936 goto SetTimesRetry;
4938 return rc;
4941 /* Can not be used to set time stamps yet (due to old DOS time format) */
4942 /* Can be used to set attributes */
4943 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4944 handling it anyway and NT4 was what we thought it would be needed for
4945 Do not delete it until we prove whether needed for Win9x though */
4947 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4948 __u16 dos_attrs, const struct nls_table *nls_codepage)
4950 SETATTR_REQ *pSMB = NULL;
4951 SETATTR_RSP *pSMBr = NULL;
4952 int rc = 0;
4953 int bytes_returned;
4954 int name_len;
4956 cFYI(1, ("In SetAttrLegacy"));
4958 SetAttrLgcyRetry:
4959 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4960 (void **) &pSMBr);
4961 if (rc)
4962 return rc;
4964 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4965 name_len =
4966 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4967 PATH_MAX, nls_codepage);
4968 name_len++; /* trailing null */
4969 name_len *= 2;
4970 } else { /* BB improve the check for buffer overruns BB */
4971 name_len = strnlen(fileName, PATH_MAX);
4972 name_len++; /* trailing null */
4973 strncpy(pSMB->fileName, fileName, name_len);
4975 pSMB->attr = cpu_to_le16(dos_attrs);
4976 pSMB->BufferFormat = 0x04;
4977 pSMB->hdr.smb_buf_length += name_len + 1;
4978 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4981 if (rc) {
4982 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4985 cifs_buf_release(pSMB);
4987 if (rc == -EAGAIN)
4988 goto SetAttrLgcyRetry;
4990 return rc;
4992 #endif /* temporarily unneeded SetAttr legacy function */
4995 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4996 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4997 dev_t device, const struct nls_table *nls_codepage,
4998 int remap)
5000 TRANSACTION2_SPI_REQ *pSMB = NULL;
5001 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5002 int name_len;
5003 int rc = 0;
5004 int bytes_returned = 0;
5005 FILE_UNIX_BASIC_INFO *data_offset;
5006 __u16 params, param_offset, offset, count, byte_count;
5008 cFYI(1, ("In SetUID/GID/Mode"));
5009 setPermsRetry:
5010 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5011 (void **) &pSMBr);
5012 if (rc)
5013 return rc;
5015 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5016 name_len =
5017 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5018 PATH_MAX, nls_codepage, remap);
5019 name_len++; /* trailing null */
5020 name_len *= 2;
5021 } else { /* BB improve the check for buffer overruns BB */
5022 name_len = strnlen(fileName, PATH_MAX);
5023 name_len++; /* trailing null */
5024 strncpy(pSMB->FileName, fileName, name_len);
5027 params = 6 + name_len;
5028 count = sizeof(FILE_UNIX_BASIC_INFO);
5029 pSMB->MaxParameterCount = cpu_to_le16(2);
5030 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5031 pSMB->MaxSetupCount = 0;
5032 pSMB->Reserved = 0;
5033 pSMB->Flags = 0;
5034 pSMB->Timeout = 0;
5035 pSMB->Reserved2 = 0;
5036 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5037 InformationLevel) - 4;
5038 offset = param_offset + params;
5039 data_offset =
5040 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5041 offset);
5042 memset(data_offset, 0, count);
5043 pSMB->DataOffset = cpu_to_le16(offset);
5044 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5045 pSMB->SetupCount = 1;
5046 pSMB->Reserved3 = 0;
5047 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5048 byte_count = 3 /* pad */ + params + count;
5049 pSMB->ParameterCount = cpu_to_le16(params);
5050 pSMB->DataCount = cpu_to_le16(count);
5051 pSMB->TotalParameterCount = pSMB->ParameterCount;
5052 pSMB->TotalDataCount = pSMB->DataCount;
5053 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5054 pSMB->Reserved4 = 0;
5055 pSMB->hdr.smb_buf_length += byte_count;
5056 /* Samba server ignores set of file size to zero due to bugs in some
5057 older clients, but we should be precise - we use SetFileSize to
5058 set file size and do not want to truncate file size to zero
5059 accidently as happened on one Samba server beta by putting
5060 zero instead of -1 here */
5061 data_offset->EndOfFile = NO_CHANGE_64;
5062 data_offset->NumOfBytes = NO_CHANGE_64;
5063 data_offset->LastStatusChange = NO_CHANGE_64;
5064 data_offset->LastAccessTime = NO_CHANGE_64;
5065 data_offset->LastModificationTime = NO_CHANGE_64;
5066 data_offset->Uid = cpu_to_le64(uid);
5067 data_offset->Gid = cpu_to_le64(gid);
5068 /* better to leave device as zero when it is */
5069 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5070 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5071 data_offset->Permissions = cpu_to_le64(mode);
5073 if (S_ISREG(mode))
5074 data_offset->Type = cpu_to_le32(UNIX_FILE);
5075 else if (S_ISDIR(mode))
5076 data_offset->Type = cpu_to_le32(UNIX_DIR);
5077 else if (S_ISLNK(mode))
5078 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5079 else if (S_ISCHR(mode))
5080 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5081 else if (S_ISBLK(mode))
5082 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5083 else if (S_ISFIFO(mode))
5084 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5085 else if (S_ISSOCK(mode))
5086 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5089 pSMB->ByteCount = cpu_to_le16(byte_count);
5090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5092 if (rc) {
5093 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5096 if (pSMB)
5097 cifs_buf_release(pSMB);
5098 if (rc == -EAGAIN)
5099 goto setPermsRetry;
5100 return rc;
5103 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5104 const int notify_subdirs, const __u16 netfid,
5105 __u32 filter, struct file *pfile, int multishot,
5106 const struct nls_table *nls_codepage)
5108 int rc = 0;
5109 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5110 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5111 struct dir_notify_req *dnotify_req;
5112 int bytes_returned;
5114 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5115 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5116 (void **) &pSMBr);
5117 if (rc)
5118 return rc;
5120 pSMB->TotalParameterCount = 0 ;
5121 pSMB->TotalDataCount = 0;
5122 pSMB->MaxParameterCount = cpu_to_le32(2);
5123 /* BB find exact data count max from sess structure BB */
5124 pSMB->MaxDataCount = 0; /* same in little endian or be */
5125 /* BB VERIFY verify which is correct for above BB */
5126 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5127 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5129 pSMB->MaxSetupCount = 4;
5130 pSMB->Reserved = 0;
5131 pSMB->ParameterOffset = 0;
5132 pSMB->DataCount = 0;
5133 pSMB->DataOffset = 0;
5134 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5135 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5136 pSMB->ParameterCount = pSMB->TotalParameterCount;
5137 if (notify_subdirs)
5138 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5139 pSMB->Reserved2 = 0;
5140 pSMB->CompletionFilter = cpu_to_le32(filter);
5141 pSMB->Fid = netfid; /* file handle always le */
5142 pSMB->ByteCount = 0;
5144 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5145 (struct smb_hdr *)pSMBr, &bytes_returned,
5146 CIFS_ASYNC_OP);
5147 if (rc) {
5148 cFYI(1, ("Error in Notify = %d", rc));
5149 } else {
5150 /* Add file to outstanding requests */
5151 /* BB change to kmem cache alloc */
5152 dnotify_req = kmalloc(
5153 sizeof(struct dir_notify_req),
5154 GFP_KERNEL);
5155 if (dnotify_req) {
5156 dnotify_req->Pid = pSMB->hdr.Pid;
5157 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5158 dnotify_req->Mid = pSMB->hdr.Mid;
5159 dnotify_req->Tid = pSMB->hdr.Tid;
5160 dnotify_req->Uid = pSMB->hdr.Uid;
5161 dnotify_req->netfid = netfid;
5162 dnotify_req->pfile = pfile;
5163 dnotify_req->filter = filter;
5164 dnotify_req->multishot = multishot;
5165 spin_lock(&GlobalMid_Lock);
5166 list_add_tail(&dnotify_req->lhead,
5167 &GlobalDnotifyReqList);
5168 spin_unlock(&GlobalMid_Lock);
5169 } else
5170 rc = -ENOMEM;
5172 cifs_buf_release(pSMB);
5173 return rc;
5175 #ifdef CONFIG_CIFS_XATTR
5176 ssize_t
5177 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5178 const unsigned char *searchName,
5179 char *EAData, size_t buf_size,
5180 const struct nls_table *nls_codepage, int remap)
5182 /* BB assumes one setup word */
5183 TRANSACTION2_QPI_REQ *pSMB = NULL;
5184 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5185 int rc = 0;
5186 int bytes_returned;
5187 int name_len;
5188 struct fea *temp_fea;
5189 char *temp_ptr;
5190 __u16 params, byte_count;
5192 cFYI(1, ("In Query All EAs path %s", searchName));
5193 QAllEAsRetry:
5194 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5195 (void **) &pSMBr);
5196 if (rc)
5197 return rc;
5199 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5200 name_len =
5201 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5202 PATH_MAX, nls_codepage, remap);
5203 name_len++; /* trailing null */
5204 name_len *= 2;
5205 } else { /* BB improve the check for buffer overruns BB */
5206 name_len = strnlen(searchName, PATH_MAX);
5207 name_len++; /* trailing null */
5208 strncpy(pSMB->FileName, searchName, name_len);
5211 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5212 pSMB->TotalDataCount = 0;
5213 pSMB->MaxParameterCount = cpu_to_le16(2);
5214 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5215 pSMB->MaxSetupCount = 0;
5216 pSMB->Reserved = 0;
5217 pSMB->Flags = 0;
5218 pSMB->Timeout = 0;
5219 pSMB->Reserved2 = 0;
5220 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5221 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5222 pSMB->DataCount = 0;
5223 pSMB->DataOffset = 0;
5224 pSMB->SetupCount = 1;
5225 pSMB->Reserved3 = 0;
5226 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5227 byte_count = params + 1 /* pad */ ;
5228 pSMB->TotalParameterCount = cpu_to_le16(params);
5229 pSMB->ParameterCount = pSMB->TotalParameterCount;
5230 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5231 pSMB->Reserved4 = 0;
5232 pSMB->hdr.smb_buf_length += byte_count;
5233 pSMB->ByteCount = cpu_to_le16(byte_count);
5235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5236 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5237 if (rc) {
5238 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5239 } else { /* decode response */
5240 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5242 /* BB also check enough total bytes returned */
5243 /* BB we need to improve the validity checking
5244 of these trans2 responses */
5245 if (rc || (pSMBr->ByteCount < 4))
5246 rc = -EIO; /* bad smb */
5247 /* else if (pFindData){
5248 memcpy((char *) pFindData,
5249 (char *) &pSMBr->hdr.Protocol +
5250 data_offset, kl);
5251 }*/ else {
5252 /* check that length of list is not more than bcc */
5253 /* check that each entry does not go beyond length
5254 of list */
5255 /* check that each element of each entry does not
5256 go beyond end of list */
5257 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5258 struct fealist *ea_response_data;
5259 rc = 0;
5260 /* validate_trans2_offsets() */
5261 /* BB check if start of smb + data_offset > &bcc+ bcc */
5262 ea_response_data = (struct fealist *)
5263 (((char *) &pSMBr->hdr.Protocol) +
5264 data_offset);
5265 name_len = le32_to_cpu(ea_response_data->list_len);
5266 cFYI(1, ("ea length %d", name_len));
5267 if (name_len <= 8) {
5268 /* returned EA size zeroed at top of function */
5269 cFYI(1, ("empty EA list returned from server"));
5270 } else {
5271 /* account for ea list len */
5272 name_len -= 4;
5273 temp_fea = ea_response_data->list;
5274 temp_ptr = (char *)temp_fea;
5275 while (name_len > 0) {
5276 __u16 value_len;
5277 name_len -= 4;
5278 temp_ptr += 4;
5279 rc += temp_fea->name_len;
5280 /* account for prefix user. and trailing null */
5281 rc = rc + 5 + 1;
5282 if (rc < (int)buf_size) {
5283 memcpy(EAData, "user.", 5);
5284 EAData += 5;
5285 memcpy(EAData, temp_ptr,
5286 temp_fea->name_len);
5287 EAData += temp_fea->name_len;
5288 /* null terminate name */
5289 *EAData = 0;
5290 EAData = EAData + 1;
5291 } else if (buf_size == 0) {
5292 /* skip copy - calc size only */
5293 } else {
5294 /* stop before overrun buffer */
5295 rc = -ERANGE;
5296 break;
5298 name_len -= temp_fea->name_len;
5299 temp_ptr += temp_fea->name_len;
5300 /* account for trailing null */
5301 name_len--;
5302 temp_ptr++;
5303 value_len =
5304 le16_to_cpu(temp_fea->value_len);
5305 name_len -= value_len;
5306 temp_ptr += value_len;
5307 /* BB check that temp_ptr is still
5308 within the SMB BB*/
5310 /* no trailing null to account for
5311 in value len */
5312 /* go on to next EA */
5313 temp_fea = (struct fea *)temp_ptr;
5318 if (pSMB)
5319 cifs_buf_release(pSMB);
5320 if (rc == -EAGAIN)
5321 goto QAllEAsRetry;
5323 return (ssize_t)rc;
5326 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5327 const unsigned char *searchName, const unsigned char *ea_name,
5328 unsigned char *ea_value, size_t buf_size,
5329 const struct nls_table *nls_codepage, int remap)
5331 TRANSACTION2_QPI_REQ *pSMB = NULL;
5332 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5333 int rc = 0;
5334 int bytes_returned;
5335 int name_len;
5336 struct fea *temp_fea;
5337 char *temp_ptr;
5338 __u16 params, byte_count;
5340 cFYI(1, ("In Query EA path %s", searchName));
5341 QEARetry:
5342 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5343 (void **) &pSMBr);
5344 if (rc)
5345 return rc;
5347 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5348 name_len =
5349 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5350 PATH_MAX, nls_codepage, remap);
5351 name_len++; /* trailing null */
5352 name_len *= 2;
5353 } else { /* BB improve the check for buffer overruns BB */
5354 name_len = strnlen(searchName, PATH_MAX);
5355 name_len++; /* trailing null */
5356 strncpy(pSMB->FileName, searchName, name_len);
5359 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5360 pSMB->TotalDataCount = 0;
5361 pSMB->MaxParameterCount = cpu_to_le16(2);
5362 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5363 pSMB->MaxSetupCount = 0;
5364 pSMB->Reserved = 0;
5365 pSMB->Flags = 0;
5366 pSMB->Timeout = 0;
5367 pSMB->Reserved2 = 0;
5368 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5369 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5370 pSMB->DataCount = 0;
5371 pSMB->DataOffset = 0;
5372 pSMB->SetupCount = 1;
5373 pSMB->Reserved3 = 0;
5374 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5375 byte_count = params + 1 /* pad */ ;
5376 pSMB->TotalParameterCount = cpu_to_le16(params);
5377 pSMB->ParameterCount = pSMB->TotalParameterCount;
5378 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5379 pSMB->Reserved4 = 0;
5380 pSMB->hdr.smb_buf_length += byte_count;
5381 pSMB->ByteCount = cpu_to_le16(byte_count);
5383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5385 if (rc) {
5386 cFYI(1, ("Send error in Query EA = %d", rc));
5387 } else { /* decode response */
5388 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5390 /* BB also check enough total bytes returned */
5391 /* BB we need to improve the validity checking
5392 of these trans2 responses */
5393 if (rc || (pSMBr->ByteCount < 4))
5394 rc = -EIO; /* bad smb */
5395 /* else if (pFindData){
5396 memcpy((char *) pFindData,
5397 (char *) &pSMBr->hdr.Protocol +
5398 data_offset, kl);
5399 }*/ else {
5400 /* check that length of list is not more than bcc */
5401 /* check that each entry does not go beyond length
5402 of list */
5403 /* check that each element of each entry does not
5404 go beyond end of list */
5405 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5406 struct fealist *ea_response_data;
5407 rc = -ENODATA;
5408 /* validate_trans2_offsets() */
5409 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5410 ea_response_data = (struct fealist *)
5411 (((char *) &pSMBr->hdr.Protocol) +
5412 data_offset);
5413 name_len = le32_to_cpu(ea_response_data->list_len);
5414 cFYI(1, ("ea length %d", name_len));
5415 if (name_len <= 8) {
5416 /* returned EA size zeroed at top of function */
5417 cFYI(1, ("empty EA list returned from server"));
5418 } else {
5419 /* account for ea list len */
5420 name_len -= 4;
5421 temp_fea = ea_response_data->list;
5422 temp_ptr = (char *)temp_fea;
5423 /* loop through checking if we have a matching
5424 name and then return the associated value */
5425 while (name_len > 0) {
5426 __u16 value_len;
5427 name_len -= 4;
5428 temp_ptr += 4;
5429 value_len =
5430 le16_to_cpu(temp_fea->value_len);
5431 /* BB validate that value_len falls within SMB,
5432 even though maximum for name_len is 255 */
5433 if (memcmp(temp_fea->name, ea_name,
5434 temp_fea->name_len) == 0) {
5435 /* found a match */
5436 rc = value_len;
5437 /* account for prefix user. and trailing null */
5438 if (rc <= (int)buf_size) {
5439 memcpy(ea_value,
5440 temp_fea->name+temp_fea->name_len+1,
5441 rc);
5442 /* ea values, unlike ea
5443 names, are not null
5444 terminated */
5445 } else if (buf_size == 0) {
5446 /* skip copy - calc size only */
5447 } else {
5448 /* stop before overrun buffer */
5449 rc = -ERANGE;
5451 break;
5453 name_len -= temp_fea->name_len;
5454 temp_ptr += temp_fea->name_len;
5455 /* account for trailing null */
5456 name_len--;
5457 temp_ptr++;
5458 name_len -= value_len;
5459 temp_ptr += value_len;
5460 /* No trailing null to account for in
5461 value_len. Go on to next EA */
5462 temp_fea = (struct fea *)temp_ptr;
5467 if (pSMB)
5468 cifs_buf_release(pSMB);
5469 if (rc == -EAGAIN)
5470 goto QEARetry;
5472 return (ssize_t)rc;
5476 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5477 const char *ea_name, const void *ea_value,
5478 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5479 int remap)
5481 struct smb_com_transaction2_spi_req *pSMB = NULL;
5482 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5483 struct fealist *parm_data;
5484 int name_len;
5485 int rc = 0;
5486 int bytes_returned = 0;
5487 __u16 params, param_offset, byte_count, offset, count;
5489 cFYI(1, ("In SetEA"));
5490 SetEARetry:
5491 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5492 (void **) &pSMBr);
5493 if (rc)
5494 return rc;
5496 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5497 name_len =
5498 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5499 PATH_MAX, nls_codepage, remap);
5500 name_len++; /* trailing null */
5501 name_len *= 2;
5502 } else { /* BB improve the check for buffer overruns BB */
5503 name_len = strnlen(fileName, PATH_MAX);
5504 name_len++; /* trailing null */
5505 strncpy(pSMB->FileName, fileName, name_len);
5508 params = 6 + name_len;
5510 /* done calculating parms using name_len of file name,
5511 now use name_len to calculate length of ea name
5512 we are going to create in the inode xattrs */
5513 if (ea_name == NULL)
5514 name_len = 0;
5515 else
5516 name_len = strnlen(ea_name, 255);
5518 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5519 pSMB->MaxParameterCount = cpu_to_le16(2);
5520 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5521 pSMB->MaxSetupCount = 0;
5522 pSMB->Reserved = 0;
5523 pSMB->Flags = 0;
5524 pSMB->Timeout = 0;
5525 pSMB->Reserved2 = 0;
5526 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5527 InformationLevel) - 4;
5528 offset = param_offset + params;
5529 pSMB->InformationLevel =
5530 cpu_to_le16(SMB_SET_FILE_EA);
5532 parm_data =
5533 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5534 offset);
5535 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5536 pSMB->DataOffset = cpu_to_le16(offset);
5537 pSMB->SetupCount = 1;
5538 pSMB->Reserved3 = 0;
5539 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5540 byte_count = 3 /* pad */ + params + count;
5541 pSMB->DataCount = cpu_to_le16(count);
5542 parm_data->list_len = cpu_to_le32(count);
5543 parm_data->list[0].EA_flags = 0;
5544 /* we checked above that name len is less than 255 */
5545 parm_data->list[0].name_len = (__u8)name_len;
5546 /* EA names are always ASCII */
5547 if (ea_name)
5548 strncpy(parm_data->list[0].name, ea_name, name_len);
5549 parm_data->list[0].name[name_len] = 0;
5550 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5551 /* caller ensures that ea_value_len is less than 64K but
5552 we need to ensure that it fits within the smb */
5554 /*BB add length check to see if it would fit in
5555 negotiated SMB buffer size BB */
5556 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5557 if (ea_value_len)
5558 memcpy(parm_data->list[0].name+name_len+1,
5559 ea_value, ea_value_len);
5561 pSMB->TotalDataCount = pSMB->DataCount;
5562 pSMB->ParameterCount = cpu_to_le16(params);
5563 pSMB->TotalParameterCount = pSMB->ParameterCount;
5564 pSMB->Reserved4 = 0;
5565 pSMB->hdr.smb_buf_length += byte_count;
5566 pSMB->ByteCount = cpu_to_le16(byte_count);
5567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5569 if (rc) {
5570 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5573 cifs_buf_release(pSMB);
5575 if (rc == -EAGAIN)
5576 goto SetEARetry;
5578 return rc;
5581 #endif