[CIFS] Finishup DFS code
[linux-2.6/libata-dev.git] / fs / cifs / cifssmb.c
blobfc297383cb0e349bb1519b59848b3135f60af270
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2008
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * Contains the routines for constructing the SMB PDUs themselves
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsacl.h"
38 #include "cifsproto.h"
39 #include "cifs_unicode.h"
40 #include "cifs_debug.h"
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44 int index;
45 char *name;
46 } protocols[] = {
47 #ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49 {LANMAN2_PROT, "\2LANMAN2.1"},
50 #endif /* weak password hashing for legacy clients */
51 {CIFS_PROT, "\2NT LM 0.12"},
52 {POSIX_PROT, "\2POSIX 2"},
53 {BAD_PROT, "\2"}
55 #else
56 static struct {
57 int index;
58 char *name;
59 } protocols[] = {
60 #ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
62 {LANMAN2_PROT, "\2LANMAN2.1"},
63 #endif /* weak password hashing for legacy clients */
64 {CIFS_PROT, "\2NT LM 0.12"},
65 {BAD_PROT, "\2"}
67 #endif
69 /* define the number of elements in the cifs dialect array */
70 #ifdef CONFIG_CIFS_POSIX
71 #ifdef CONFIG_CIFS_WEAK_PW_HASH
72 #define CIFS_NUM_PROT 4
73 #else
74 #define CIFS_NUM_PROT 2
75 #endif /* CIFS_WEAK_PW_HASH */
76 #else /* not posix */
77 #ifdef CONFIG_CIFS_WEAK_PW_HASH
78 #define CIFS_NUM_PROT 3
79 #else
80 #define CIFS_NUM_PROT 1
81 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
82 #endif /* CIFS_POSIX */
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 /* Allocate and return pointer to an SMB request buffer, and set basic
106 SMB information in the SMB header. If the return code is zero, this
107 function must have filled in request_buf pointer */
108 static int
109 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
110 void **request_buf)
112 int rc = 0;
114 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
115 check for tcp and smb session status done differently
116 for those three - in the calling routine */
117 if (tcon) {
118 if (tcon->tidStatus == CifsExiting) {
119 /* only tree disconnect, open, and write,
120 (and ulogoff which does not have tcon)
121 are allowed as we start force umount */
122 if ((smb_command != SMB_COM_WRITE_ANDX) &&
123 (smb_command != SMB_COM_OPEN_ANDX) &&
124 (smb_command != SMB_COM_TREE_DISCONNECT)) {
125 cFYI(1, ("can not send cmd %d while umounting",
126 smb_command));
127 return -ENODEV;
130 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
131 (tcon->ses->server)) {
132 struct nls_table *nls_codepage;
133 /* Give Demultiplex thread up to 10 seconds to
134 reconnect, should be greater than cifs socket
135 timeout which is 7 seconds */
136 while (tcon->ses->server->tcpStatus ==
137 CifsNeedReconnect) {
138 wait_event_interruptible_timeout(tcon->ses->server->response_q,
139 (tcon->ses->server->tcpStatus ==
140 CifsGood), 10 * HZ);
141 if (tcon->ses->server->tcpStatus ==
142 CifsNeedReconnect) {
143 /* on "soft" mounts we wait once */
144 if (!tcon->retry ||
145 (tcon->ses->status == CifsExiting)) {
146 cFYI(1, ("gave up waiting on "
147 "reconnect in smb_init"));
148 return -EHOSTDOWN;
149 } /* else "hard" mount - keep retrying
150 until process is killed or server
151 comes back on-line */
152 } else /* TCP session is reestablished now */
153 break;
156 nls_codepage = load_nls_default();
157 /* need to prevent multiple threads trying to
158 simultaneously reconnect the same SMB session */
159 down(&tcon->ses->sesSem);
160 if (tcon->ses->status == CifsNeedReconnect)
161 rc = cifs_setup_session(0, tcon->ses,
162 nls_codepage);
163 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
164 mark_open_files_invalid(tcon);
165 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
166 tcon, nls_codepage);
167 up(&tcon->ses->sesSem);
168 /* BB FIXME add code to check if wsize needs
169 update due to negotiated smb buffer size
170 shrinking */
171 if (rc == 0) {
172 atomic_inc(&tconInfoReconnectCount);
173 /* tell server Unix caps we support */
174 if (tcon->ses->capabilities & CAP_UNIX)
175 reset_cifs_unix_caps(
176 0 /* no xid */,
177 tcon,
178 NULL /* we do not know sb */,
179 NULL /* no vol info */);
182 cFYI(1, ("reconnect tcon rc = %d", rc));
183 /* Removed call to reopen open files here.
184 It is safer (and faster) to reopen files
185 one at a time as needed in read and write */
187 /* Check if handle based operation so we
188 know whether we can continue or not without
189 returning to caller to reset file handle */
190 switch (smb_command) {
191 case SMB_COM_READ_ANDX:
192 case SMB_COM_WRITE_ANDX:
193 case SMB_COM_CLOSE:
194 case SMB_COM_FIND_CLOSE2:
195 case SMB_COM_LOCKING_ANDX: {
196 unload_nls(nls_codepage);
197 return -EAGAIN;
200 } else {
201 up(&tcon->ses->sesSem);
203 unload_nls(nls_codepage);
205 } else {
206 return -EIO;
209 if (rc)
210 return rc;
212 *request_buf = cifs_small_buf_get();
213 if (*request_buf == NULL) {
214 /* BB should we add a retry in here if not a writepage? */
215 return -ENOMEM;
218 header_assemble((struct smb_hdr *) *request_buf, smb_command,
219 tcon, wct);
221 if (tcon != NULL)
222 cifs_stats_inc(&tcon->num_smbs_sent);
224 return rc;
228 small_smb_init_no_tc(const int smb_command, const int wct,
229 struct cifsSesInfo *ses, void **request_buf)
231 int rc;
232 struct smb_hdr *buffer;
234 rc = small_smb_init(smb_command, wct, NULL, request_buf);
235 if (rc)
236 return rc;
238 buffer = (struct smb_hdr *)*request_buf;
239 buffer->Mid = GetNextMid(ses->server);
240 if (ses->capabilities & CAP_UNICODE)
241 buffer->Flags2 |= SMBFLG2_UNICODE;
242 if (ses->capabilities & CAP_STATUS32)
243 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
245 /* uid, tid can stay at zero as set in header assemble */
247 /* BB add support for turning on the signing when
248 this function is used after 1st of session setup requests */
250 return rc;
253 /* If the return code is zero, this function must fill in request_buf pointer */
254 static int
255 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
256 void **request_buf /* returned */ ,
257 void **response_buf /* returned */ )
259 int rc = 0;
261 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
262 check for tcp and smb session status done differently
263 for those three - in the calling routine */
264 if (tcon) {
265 if (tcon->tidStatus == CifsExiting) {
266 /* only tree disconnect, open, and write,
267 (and ulogoff which does not have tcon)
268 are allowed as we start force umount */
269 if ((smb_command != SMB_COM_WRITE_ANDX) &&
270 (smb_command != SMB_COM_OPEN_ANDX) &&
271 (smb_command != SMB_COM_TREE_DISCONNECT)) {
272 cFYI(1, ("can not send cmd %d while umounting",
273 smb_command));
274 return -ENODEV;
278 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
279 (tcon->ses->server)) {
280 struct nls_table *nls_codepage;
281 /* Give Demultiplex thread up to 10 seconds to
282 reconnect, should be greater than cifs socket
283 timeout which is 7 seconds */
284 while (tcon->ses->server->tcpStatus ==
285 CifsNeedReconnect) {
286 wait_event_interruptible_timeout(tcon->ses->server->response_q,
287 (tcon->ses->server->tcpStatus ==
288 CifsGood), 10 * HZ);
289 if (tcon->ses->server->tcpStatus ==
290 CifsNeedReconnect) {
291 /* on "soft" mounts we wait once */
292 if (!tcon->retry ||
293 (tcon->ses->status == CifsExiting)) {
294 cFYI(1, ("gave up waiting on "
295 "reconnect in smb_init"));
296 return -EHOSTDOWN;
297 } /* else "hard" mount - keep retrying
298 until process is killed or server
299 comes on-line */
300 } else /* TCP session is reestablished now */
301 break;
303 nls_codepage = load_nls_default();
304 /* need to prevent multiple threads trying to
305 simultaneously reconnect the same SMB session */
306 down(&tcon->ses->sesSem);
307 if (tcon->ses->status == CifsNeedReconnect)
308 rc = cifs_setup_session(0, tcon->ses,
309 nls_codepage);
310 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
311 mark_open_files_invalid(tcon);
312 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
313 tcon, nls_codepage);
314 up(&tcon->ses->sesSem);
315 /* BB FIXME add code to check if wsize needs
316 update due to negotiated smb buffer size
317 shrinking */
318 if (rc == 0) {
319 atomic_inc(&tconInfoReconnectCount);
320 /* tell server Unix caps we support */
321 if (tcon->ses->capabilities & CAP_UNIX)
322 reset_cifs_unix_caps(
323 0 /* no xid */,
324 tcon,
325 NULL /* do not know sb */,
326 NULL /* no vol info */);
329 cFYI(1, ("reconnect tcon rc = %d", rc));
330 /* Removed call to reopen open files here.
331 It is safer (and faster) to reopen files
332 one at a time as needed in read and write */
334 /* Check if handle based operation so we
335 know whether we can continue or not without
336 returning to caller to reset file handle */
337 switch (smb_command) {
338 case SMB_COM_READ_ANDX:
339 case SMB_COM_WRITE_ANDX:
340 case SMB_COM_CLOSE:
341 case SMB_COM_FIND_CLOSE2:
342 case SMB_COM_LOCKING_ANDX: {
343 unload_nls(nls_codepage);
344 return -EAGAIN;
347 } else {
348 up(&tcon->ses->sesSem);
350 unload_nls(nls_codepage);
352 } else {
353 return -EIO;
356 if (rc)
357 return rc;
359 *request_buf = cifs_buf_get();
360 if (*request_buf == NULL) {
361 /* BB should we add a retry in here if not a writepage? */
362 return -ENOMEM;
364 /* Although the original thought was we needed the response buf for */
365 /* potential retries of smb operations it turns out we can determine */
366 /* from the mid flags when the request buffer can be resent without */
367 /* having to use a second distinct buffer for the response */
368 if (response_buf)
369 *response_buf = *request_buf;
371 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
372 wct);
374 if (tcon != NULL)
375 cifs_stats_inc(&tcon->num_smbs_sent);
377 return rc;
380 static int validate_t2(struct smb_t2_rsp *pSMB)
382 int rc = -EINVAL;
383 int total_size;
384 char *pBCC;
386 /* check for plausible wct, bcc and t2 data and parm sizes */
387 /* check for parm and data offset going beyond end of smb */
388 if (pSMB->hdr.WordCount >= 10) {
389 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
390 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
391 /* check that bcc is at least as big as parms + data */
392 /* check that bcc is less than negotiated smb buffer */
393 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
394 if (total_size < 512) {
395 total_size +=
396 le16_to_cpu(pSMB->t2_rsp.DataCount);
397 /* BCC le converted in SendReceive */
398 pBCC = (pSMB->hdr.WordCount * 2) +
399 sizeof(struct smb_hdr) +
400 (char *)pSMB;
401 if ((total_size <= (*(u16 *)pBCC)) &&
402 (total_size <
403 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
404 return 0;
409 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
410 sizeof(struct smb_t2_rsp) + 16);
411 return rc;
414 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
416 NEGOTIATE_REQ *pSMB;
417 NEGOTIATE_RSP *pSMBr;
418 int rc = 0;
419 int bytes_returned;
420 int i;
421 struct TCP_Server_Info *server;
422 u16 count;
423 unsigned int secFlags;
424 u16 dialect;
426 if (ses->server)
427 server = ses->server;
428 else {
429 rc = -EIO;
430 return rc;
432 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
433 (void **) &pSMB, (void **) &pSMBr);
434 if (rc)
435 return rc;
437 /* if any of auth flags (ie not sign or seal) are overriden use them */
438 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
439 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
440 else /* if override flags set only sign/seal OR them with global auth */
441 secFlags = extended_security | ses->overrideSecFlg;
443 cFYI(1, ("secFlags 0x%x", secFlags));
445 pSMB->hdr.Mid = GetNextMid(server);
446 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
448 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
449 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
450 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
451 cFYI(1, ("Kerberos only mechanism, enable extended security"));
452 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
455 count = 0;
456 for (i = 0; i < CIFS_NUM_PROT; i++) {
457 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
458 count += strlen(protocols[i].name) + 1;
459 /* null at end of source and target buffers anyway */
461 pSMB->hdr.smb_buf_length += count;
462 pSMB->ByteCount = cpu_to_le16(count);
464 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
466 if (rc != 0)
467 goto neg_err_exit;
469 dialect = le16_to_cpu(pSMBr->DialectIndex);
470 cFYI(1, ("Dialect: %d", dialect));
471 /* Check wct = 1 error case */
472 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
473 /* core returns wct = 1, but we do not ask for core - otherwise
474 small wct just comes when dialect index is -1 indicating we
475 could not negotiate a common dialect */
476 rc = -EOPNOTSUPP;
477 goto neg_err_exit;
478 #ifdef CONFIG_CIFS_WEAK_PW_HASH
479 } else if ((pSMBr->hdr.WordCount == 13)
480 && ((dialect == LANMAN_PROT)
481 || (dialect == LANMAN2_PROT))) {
482 __s16 tmp;
483 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
485 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
486 (secFlags & CIFSSEC_MAY_PLNTXT))
487 server->secType = LANMAN;
488 else {
489 cERROR(1, ("mount failed weak security disabled"
490 " in /proc/fs/cifs/SecurityFlags"));
491 rc = -EOPNOTSUPP;
492 goto neg_err_exit;
494 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
495 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
496 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
497 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
498 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
499 /* even though we do not use raw we might as well set this
500 accurately, in case we ever find a need for it */
501 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
502 server->maxRw = 0xFF00;
503 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
504 } else {
505 server->maxRw = 0;/* we do not need to use raw anyway */
506 server->capabilities = CAP_MPX_MODE;
508 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
509 if (tmp == -1) {
510 /* OS/2 often does not set timezone therefore
511 * we must use server time to calc time zone.
512 * Could deviate slightly from the right zone.
513 * Smallest defined timezone difference is 15 minutes
514 * (i.e. Nepal). Rounding up/down is done to match
515 * this requirement.
517 int val, seconds, remain, result;
518 struct timespec ts, utc;
519 utc = CURRENT_TIME;
520 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
521 le16_to_cpu(rsp->SrvTime.Time));
522 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
523 (int)ts.tv_sec, (int)utc.tv_sec,
524 (int)(utc.tv_sec - ts.tv_sec)));
525 val = (int)(utc.tv_sec - ts.tv_sec);
526 seconds = abs(val);
527 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
528 remain = seconds % MIN_TZ_ADJ;
529 if (remain >= (MIN_TZ_ADJ / 2))
530 result += MIN_TZ_ADJ;
531 if (val < 0)
532 result = -result;
533 server->timeAdj = result;
534 } else {
535 server->timeAdj = (int)tmp;
536 server->timeAdj *= 60; /* also in seconds */
538 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
541 /* BB get server time for time conversions and add
542 code to use it and timezone since this is not UTC */
544 if (rsp->EncryptionKeyLength ==
545 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
546 memcpy(server->cryptKey, rsp->EncryptionKey,
547 CIFS_CRYPTO_KEY_SIZE);
548 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
549 rc = -EIO; /* need cryptkey unless plain text */
550 goto neg_err_exit;
553 cFYI(1, ("LANMAN negotiated"));
554 /* we will not end up setting signing flags - as no signing
555 was in LANMAN and server did not return the flags on */
556 goto signing_check;
557 #else /* weak security disabled */
558 } else if (pSMBr->hdr.WordCount == 13) {
559 cERROR(1, ("mount failed, cifs module not built "
560 "with CIFS_WEAK_PW_HASH support"));
561 rc = -EOPNOTSUPP;
562 #endif /* WEAK_PW_HASH */
563 goto neg_err_exit;
564 } else if (pSMBr->hdr.WordCount != 17) {
565 /* unknown wct */
566 rc = -EOPNOTSUPP;
567 goto neg_err_exit;
569 /* else wct == 17 NTLM */
570 server->secMode = pSMBr->SecurityMode;
571 if ((server->secMode & SECMODE_USER) == 0)
572 cFYI(1, ("share mode security"));
574 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
575 #ifdef CONFIG_CIFS_WEAK_PW_HASH
576 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
577 #endif /* CIFS_WEAK_PW_HASH */
578 cERROR(1, ("Server requests plain text password"
579 " but client support disabled"));
581 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
582 server->secType = NTLMv2;
583 else if (secFlags & CIFSSEC_MAY_NTLM)
584 server->secType = NTLM;
585 else if (secFlags & CIFSSEC_MAY_NTLMV2)
586 server->secType = NTLMv2;
587 else if (secFlags & CIFSSEC_MAY_KRB5)
588 server->secType = Kerberos;
589 else if (secFlags & CIFSSEC_MAY_LANMAN)
590 server->secType = LANMAN;
591 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
592 else if (secFlags & CIFSSEC_MAY_PLNTXT)
593 server->secType = ??
594 #endif */
595 else {
596 rc = -EOPNOTSUPP;
597 cERROR(1, ("Invalid security type"));
598 goto neg_err_exit;
600 /* else ... any others ...? */
602 /* one byte, so no need to convert this or EncryptionKeyLen from
603 little endian */
604 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
605 /* probably no need to store and check maxvcs */
606 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
607 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
608 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
609 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
610 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
611 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
612 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
613 server->timeAdj *= 60;
614 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
615 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
616 CIFS_CRYPTO_KEY_SIZE);
617 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
618 && (pSMBr->EncryptionKeyLength == 0)) {
619 /* decode security blob */
620 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
621 rc = -EIO; /* no crypt key only if plain text pwd */
622 goto neg_err_exit;
625 /* BB might be helpful to save off the domain of server here */
627 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
628 (server->capabilities & CAP_EXTENDED_SECURITY)) {
629 count = pSMBr->ByteCount;
630 if (count < 16) {
631 rc = -EIO;
632 goto neg_err_exit;
635 if (server->socketUseCount.counter > 1) {
636 if (memcmp(server->server_GUID,
637 pSMBr->u.extended_response.
638 GUID, 16) != 0) {
639 cFYI(1, ("server UID changed"));
640 memcpy(server->server_GUID,
641 pSMBr->u.extended_response.GUID,
642 16);
644 } else
645 memcpy(server->server_GUID,
646 pSMBr->u.extended_response.GUID, 16);
648 if (count == 16) {
649 server->secType = RawNTLMSSP;
650 } else {
651 rc = decode_negTokenInit(pSMBr->u.extended_response.
652 SecurityBlob,
653 count - 16,
654 &server->secType);
655 if (rc == 1) {
656 rc = 0;
657 } else {
658 rc = -EINVAL;
661 } else
662 server->capabilities &= ~CAP_EXTENDED_SECURITY;
664 #ifdef CONFIG_CIFS_WEAK_PW_HASH
665 signing_check:
666 #endif
667 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
668 /* MUST_SIGN already includes the MAY_SIGN FLAG
669 so if this is zero it means that signing is disabled */
670 cFYI(1, ("Signing disabled"));
671 if (server->secMode & SECMODE_SIGN_REQUIRED) {
672 cERROR(1, ("Server requires "
673 "packet signing to be enabled in "
674 "/proc/fs/cifs/SecurityFlags."));
675 rc = -EOPNOTSUPP;
677 server->secMode &=
678 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
679 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
680 /* signing required */
681 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
682 if ((server->secMode &
683 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
684 cERROR(1,
685 ("signing required but server lacks support"));
686 rc = -EOPNOTSUPP;
687 } else
688 server->secMode |= SECMODE_SIGN_REQUIRED;
689 } else {
690 /* signing optional ie CIFSSEC_MAY_SIGN */
691 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
692 server->secMode &=
693 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
696 neg_err_exit:
697 cifs_buf_release(pSMB);
699 cFYI(1, ("negprot rc %d", rc));
700 return rc;
704 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
706 struct smb_hdr *smb_buffer;
707 int rc = 0;
709 cFYI(1, ("In tree disconnect"));
711 * If last user of the connection and
712 * connection alive - disconnect it
713 * If this is the last connection on the server session disconnect it
714 * (and inside session disconnect we should check if tcp socket needs
715 * to be freed and kernel thread woken up).
717 if (tcon)
718 down(&tcon->tconSem);
719 else
720 return -EIO;
722 atomic_dec(&tcon->useCount);
723 if (atomic_read(&tcon->useCount) > 0) {
724 up(&tcon->tconSem);
725 return -EBUSY;
728 /* No need to return error on this operation if tid invalidated and
729 closed on server already e.g. due to tcp session crashing */
730 if (tcon->tidStatus == CifsNeedReconnect) {
731 up(&tcon->tconSem);
732 return 0;
735 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
736 up(&tcon->tconSem);
737 return -EIO;
739 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
740 (void **)&smb_buffer);
741 if (rc) {
742 up(&tcon->tconSem);
743 return rc;
746 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
747 if (rc)
748 cFYI(1, ("Tree disconnect failed %d", rc));
750 up(&tcon->tconSem);
752 /* No need to return error on this operation if tid invalidated and
753 closed on server already e.g. due to tcp session crashing */
754 if (rc == -EAGAIN)
755 rc = 0;
757 return rc;
761 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
763 LOGOFF_ANDX_REQ *pSMB;
764 int rc = 0;
766 cFYI(1, ("In SMBLogoff for session disconnect"));
767 if (ses)
768 down(&ses->sesSem);
769 else
770 return -EIO;
772 atomic_dec(&ses->inUse);
773 if (atomic_read(&ses->inUse) > 0) {
774 up(&ses->sesSem);
775 return -EBUSY;
777 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
778 if (rc) {
779 up(&ses->sesSem);
780 return rc;
783 if (ses->server) {
784 pSMB->hdr.Mid = GetNextMid(ses->server);
786 if (ses->server->secMode &
787 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
788 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
791 pSMB->hdr.Uid = ses->Suid;
793 pSMB->AndXCommand = 0xFF;
794 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
795 if (ses->server) {
796 atomic_dec(&ses->server->socketUseCount);
797 if (atomic_read(&ses->server->socketUseCount) == 0) {
798 spin_lock(&GlobalMid_Lock);
799 ses->server->tcpStatus = CifsExiting;
800 spin_unlock(&GlobalMid_Lock);
801 rc = -ESHUTDOWN;
804 up(&ses->sesSem);
806 /* if session dead then we do not need to do ulogoff,
807 since server closed smb session, no sense reporting
808 error */
809 if (rc == -EAGAIN)
810 rc = 0;
811 return rc;
815 CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
816 __u16 type, const struct nls_table *nls_codepage, int remap)
818 TRANSACTION2_SPI_REQ *pSMB = NULL;
819 TRANSACTION2_SPI_RSP *pSMBr = NULL;
820 struct unlink_psx_rq *pRqD;
821 int name_len;
822 int rc = 0;
823 int bytes_returned = 0;
824 __u16 params, param_offset, offset, byte_count;
826 cFYI(1, ("In POSIX delete"));
827 PsxDelete:
828 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
829 (void **) &pSMBr);
830 if (rc)
831 return rc;
833 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
834 name_len =
835 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
836 PATH_MAX, nls_codepage, remap);
837 name_len++; /* trailing null */
838 name_len *= 2;
839 } else { /* BB add path length overrun check */
840 name_len = strnlen(fileName, PATH_MAX);
841 name_len++; /* trailing null */
842 strncpy(pSMB->FileName, fileName, name_len);
845 params = 6 + name_len;
846 pSMB->MaxParameterCount = cpu_to_le16(2);
847 pSMB->MaxDataCount = 0; /* BB double check this with jra */
848 pSMB->MaxSetupCount = 0;
849 pSMB->Reserved = 0;
850 pSMB->Flags = 0;
851 pSMB->Timeout = 0;
852 pSMB->Reserved2 = 0;
853 param_offset = offsetof(struct smb_com_transaction2_spi_req,
854 InformationLevel) - 4;
855 offset = param_offset + params;
857 /* Setup pointer to Request Data (inode type) */
858 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
859 pRqD->type = cpu_to_le16(type);
860 pSMB->ParameterOffset = cpu_to_le16(param_offset);
861 pSMB->DataOffset = cpu_to_le16(offset);
862 pSMB->SetupCount = 1;
863 pSMB->Reserved3 = 0;
864 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
865 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
867 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
868 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
869 pSMB->ParameterCount = cpu_to_le16(params);
870 pSMB->TotalParameterCount = pSMB->ParameterCount;
871 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
872 pSMB->Reserved4 = 0;
873 pSMB->hdr.smb_buf_length += byte_count;
874 pSMB->ByteCount = cpu_to_le16(byte_count);
875 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
876 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
877 if (rc)
878 cFYI(1, ("Posix delete returned %d", rc));
879 cifs_buf_release(pSMB);
881 cifs_stats_inc(&tcon->num_deletes);
883 if (rc == -EAGAIN)
884 goto PsxDelete;
886 return rc;
890 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
891 const struct nls_table *nls_codepage, int remap)
893 DELETE_FILE_REQ *pSMB = NULL;
894 DELETE_FILE_RSP *pSMBr = NULL;
895 int rc = 0;
896 int bytes_returned;
897 int name_len;
899 DelFileRetry:
900 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
901 (void **) &pSMBr);
902 if (rc)
903 return rc;
905 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
906 name_len =
907 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
908 PATH_MAX, nls_codepage, remap);
909 name_len++; /* trailing null */
910 name_len *= 2;
911 } else { /* BB improve check for buffer overruns BB */
912 name_len = strnlen(fileName, PATH_MAX);
913 name_len++; /* trailing null */
914 strncpy(pSMB->fileName, fileName, name_len);
916 pSMB->SearchAttributes =
917 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
918 pSMB->BufferFormat = 0x04;
919 pSMB->hdr.smb_buf_length += name_len + 1;
920 pSMB->ByteCount = cpu_to_le16(name_len + 1);
921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
923 cifs_stats_inc(&tcon->num_deletes);
924 if (rc)
925 cFYI(1, ("Error in RMFile = %d", rc));
927 cifs_buf_release(pSMB);
928 if (rc == -EAGAIN)
929 goto DelFileRetry;
931 return rc;
935 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
936 const struct nls_table *nls_codepage, int remap)
938 DELETE_DIRECTORY_REQ *pSMB = NULL;
939 DELETE_DIRECTORY_RSP *pSMBr = NULL;
940 int rc = 0;
941 int bytes_returned;
942 int name_len;
944 cFYI(1, ("In CIFSSMBRmDir"));
945 RmDirRetry:
946 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
947 (void **) &pSMBr);
948 if (rc)
949 return rc;
951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
952 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
953 PATH_MAX, nls_codepage, remap);
954 name_len++; /* trailing null */
955 name_len *= 2;
956 } else { /* BB improve check for buffer overruns BB */
957 name_len = strnlen(dirName, PATH_MAX);
958 name_len++; /* trailing null */
959 strncpy(pSMB->DirName, dirName, name_len);
962 pSMB->BufferFormat = 0x04;
963 pSMB->hdr.smb_buf_length += name_len + 1;
964 pSMB->ByteCount = cpu_to_le16(name_len + 1);
965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
967 cifs_stats_inc(&tcon->num_rmdirs);
968 if (rc)
969 cFYI(1, ("Error in RMDir = %d", rc));
971 cifs_buf_release(pSMB);
972 if (rc == -EAGAIN)
973 goto RmDirRetry;
974 return rc;
978 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
979 const char *name, const struct nls_table *nls_codepage, int remap)
981 int rc = 0;
982 CREATE_DIRECTORY_REQ *pSMB = NULL;
983 CREATE_DIRECTORY_RSP *pSMBr = NULL;
984 int bytes_returned;
985 int name_len;
987 cFYI(1, ("In CIFSSMBMkDir"));
988 MkDirRetry:
989 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
990 (void **) &pSMBr);
991 if (rc)
992 return rc;
994 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
995 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
996 PATH_MAX, nls_codepage, remap);
997 name_len++; /* trailing null */
998 name_len *= 2;
999 } else { /* BB improve check for buffer overruns BB */
1000 name_len = strnlen(name, PATH_MAX);
1001 name_len++; /* trailing null */
1002 strncpy(pSMB->DirName, name, name_len);
1005 pSMB->BufferFormat = 0x04;
1006 pSMB->hdr.smb_buf_length += name_len + 1;
1007 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1010 cifs_stats_inc(&tcon->num_mkdirs);
1011 if (rc)
1012 cFYI(1, ("Error in Mkdir = %d", rc));
1014 cifs_buf_release(pSMB);
1015 if (rc == -EAGAIN)
1016 goto MkDirRetry;
1017 return rc;
1021 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1022 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
1023 __u32 *pOplock, const char *name,
1024 const struct nls_table *nls_codepage, int remap)
1026 TRANSACTION2_SPI_REQ *pSMB = NULL;
1027 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1028 int name_len;
1029 int rc = 0;
1030 int bytes_returned = 0;
1031 __u16 params, param_offset, offset, byte_count, count;
1032 OPEN_PSX_REQ *pdata;
1033 OPEN_PSX_RSP *psx_rsp;
1035 cFYI(1, ("In POSIX Create"));
1036 PsxCreat:
1037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1038 (void **) &pSMBr);
1039 if (rc)
1040 return rc;
1042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1043 name_len =
1044 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1045 PATH_MAX, nls_codepage, remap);
1046 name_len++; /* trailing null */
1047 name_len *= 2;
1048 } else { /* BB improve the check for buffer overruns BB */
1049 name_len = strnlen(name, PATH_MAX);
1050 name_len++; /* trailing null */
1051 strncpy(pSMB->FileName, name, name_len);
1054 params = 6 + name_len;
1055 count = sizeof(OPEN_PSX_REQ);
1056 pSMB->MaxParameterCount = cpu_to_le16(2);
1057 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1058 pSMB->MaxSetupCount = 0;
1059 pSMB->Reserved = 0;
1060 pSMB->Flags = 0;
1061 pSMB->Timeout = 0;
1062 pSMB->Reserved2 = 0;
1063 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1064 InformationLevel) - 4;
1065 offset = param_offset + params;
1066 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1067 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1068 pdata->Permissions = cpu_to_le64(mode);
1069 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1070 pdata->OpenFlags = cpu_to_le32(*pOplock);
1071 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1072 pSMB->DataOffset = cpu_to_le16(offset);
1073 pSMB->SetupCount = 1;
1074 pSMB->Reserved3 = 0;
1075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1076 byte_count = 3 /* pad */ + params + count;
1078 pSMB->DataCount = cpu_to_le16(count);
1079 pSMB->ParameterCount = cpu_to_le16(params);
1080 pSMB->TotalDataCount = pSMB->DataCount;
1081 pSMB->TotalParameterCount = pSMB->ParameterCount;
1082 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1083 pSMB->Reserved4 = 0;
1084 pSMB->hdr.smb_buf_length += byte_count;
1085 pSMB->ByteCount = cpu_to_le16(byte_count);
1086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1088 if (rc) {
1089 cFYI(1, ("Posix create returned %d", rc));
1090 goto psx_create_err;
1093 cFYI(1, ("copying inode info"));
1094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1096 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1097 rc = -EIO; /* bad smb */
1098 goto psx_create_err;
1101 /* copy return information to pRetData */
1102 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1103 + le16_to_cpu(pSMBr->t2.DataOffset));
1105 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1106 if (netfid)
1107 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1108 /* Let caller know file was created so we can set the mode. */
1109 /* Do we care about the CreateAction in any other cases? */
1110 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1111 *pOplock |= CIFS_CREATE_ACTION;
1112 /* check to make sure response data is there */
1113 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1114 pRetData->Type = cpu_to_le32(-1); /* unknown */
1115 cFYI(DBG2, ("unknown type"));
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;
1169 static int
1170 access_flags_to_smbopen_mode(const int access_flags)
1172 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1174 if (masked_flags == GENERIC_READ)
1175 return SMBOPEN_READ;
1176 else if (masked_flags == GENERIC_WRITE)
1177 return SMBOPEN_WRITE;
1179 /* just go for read/write */
1180 return SMBOPEN_READWRITE;
1184 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1185 const char *fileName, const int openDisposition,
1186 const int access_flags, const int create_options, __u16 *netfid,
1187 int *pOplock, FILE_ALL_INFO *pfile_info,
1188 const struct nls_table *nls_codepage, int remap)
1190 int rc = -EACCES;
1191 OPENX_REQ *pSMB = NULL;
1192 OPENX_RSP *pSMBr = NULL;
1193 int bytes_returned;
1194 int name_len;
1195 __u16 count;
1197 OldOpenRetry:
1198 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1199 (void **) &pSMBr);
1200 if (rc)
1201 return rc;
1203 pSMB->AndXCommand = 0xFF; /* none */
1205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1206 count = 1; /* account for one byte pad to word boundary */
1207 name_len =
1208 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1209 fileName, PATH_MAX, nls_codepage, remap);
1210 name_len++; /* trailing null */
1211 name_len *= 2;
1212 } else { /* BB improve check for buffer overruns BB */
1213 count = 0; /* no pad */
1214 name_len = strnlen(fileName, PATH_MAX);
1215 name_len++; /* trailing null */
1216 strncpy(pSMB->fileName, fileName, name_len);
1218 if (*pOplock & REQ_OPLOCK)
1219 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1220 else if (*pOplock & REQ_BATCHOPLOCK)
1221 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1223 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1224 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1225 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1226 /* set file as system file if special file such
1227 as fifo and server expecting SFU style and
1228 no Unix extensions */
1230 if (create_options & CREATE_OPTION_SPECIAL)
1231 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1232 else /* BB FIXME BB */
1233 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1235 if (create_options & CREATE_OPTION_READONLY)
1236 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1238 /* BB FIXME BB */
1239 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1240 CREATE_OPTIONS_MASK); */
1241 /* BB FIXME END BB */
1243 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1244 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1245 count += name_len;
1246 pSMB->hdr.smb_buf_length += count;
1248 pSMB->ByteCount = cpu_to_le16(count);
1249 /* long_op set to 1 to allow for oplock break timeouts */
1250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1251 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1252 cifs_stats_inc(&tcon->num_opens);
1253 if (rc) {
1254 cFYI(1, ("Error in Open = %d", rc));
1255 } else {
1256 /* BB verify if wct == 15 */
1258 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1260 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1261 /* Let caller know file was created so we can set the mode. */
1262 /* Do we care about the CreateAction in any other cases? */
1263 /* BB FIXME BB */
1264 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1265 *pOplock |= CIFS_CREATE_ACTION; */
1266 /* BB FIXME END */
1268 if (pfile_info) {
1269 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1270 pfile_info->LastAccessTime = 0; /* BB fixme */
1271 pfile_info->LastWriteTime = 0; /* BB fixme */
1272 pfile_info->ChangeTime = 0; /* BB fixme */
1273 pfile_info->Attributes =
1274 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1275 /* the file_info buf is endian converted by caller */
1276 pfile_info->AllocationSize =
1277 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1278 pfile_info->EndOfFile = pfile_info->AllocationSize;
1279 pfile_info->NumberOfLinks = cpu_to_le32(1);
1283 cifs_buf_release(pSMB);
1284 if (rc == -EAGAIN)
1285 goto OldOpenRetry;
1286 return rc;
1290 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1291 const char *fileName, const int openDisposition,
1292 const int access_flags, const int create_options, __u16 *netfid,
1293 int *pOplock, FILE_ALL_INFO *pfile_info,
1294 const struct nls_table *nls_codepage, int remap)
1296 int rc = -EACCES;
1297 OPEN_REQ *pSMB = NULL;
1298 OPEN_RSP *pSMBr = NULL;
1299 int bytes_returned;
1300 int name_len;
1301 __u16 count;
1303 openRetry:
1304 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1305 (void **) &pSMBr);
1306 if (rc)
1307 return rc;
1309 pSMB->AndXCommand = 0xFF; /* none */
1311 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1312 count = 1; /* account for one byte pad to word boundary */
1313 name_len =
1314 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1315 fileName, PATH_MAX, nls_codepage, remap);
1316 name_len++; /* trailing null */
1317 name_len *= 2;
1318 pSMB->NameLength = cpu_to_le16(name_len);
1319 } else { /* BB improve check for buffer overruns BB */
1320 count = 0; /* no pad */
1321 name_len = strnlen(fileName, PATH_MAX);
1322 name_len++; /* trailing null */
1323 pSMB->NameLength = cpu_to_le16(name_len);
1324 strncpy(pSMB->fileName, fileName, name_len);
1326 if (*pOplock & REQ_OPLOCK)
1327 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1328 else if (*pOplock & REQ_BATCHOPLOCK)
1329 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1330 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1331 pSMB->AllocationSize = 0;
1332 /* set file as system file if special file such
1333 as fifo and server expecting SFU style and
1334 no Unix extensions */
1335 if (create_options & CREATE_OPTION_SPECIAL)
1336 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1337 else
1338 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1340 /* XP does not handle ATTR_POSIX_SEMANTICS */
1341 /* but it helps speed up case sensitive checks for other
1342 servers such as Samba */
1343 if (tcon->ses->capabilities & CAP_UNIX)
1344 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1346 if (create_options & CREATE_OPTION_READONLY)
1347 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1349 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1350 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1351 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1352 /* BB Expirement with various impersonation levels and verify */
1353 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1354 pSMB->SecurityFlags =
1355 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1357 count += name_len;
1358 pSMB->hdr.smb_buf_length += count;
1360 pSMB->ByteCount = cpu_to_le16(count);
1361 /* long_op set to 1 to allow for oplock break timeouts */
1362 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1363 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1364 cifs_stats_inc(&tcon->num_opens);
1365 if (rc) {
1366 cFYI(1, ("Error in Open = %d", rc));
1367 } else {
1368 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1369 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1370 /* Let caller know file was created so we can set the mode. */
1371 /* Do we care about the CreateAction in any other cases? */
1372 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1373 *pOplock |= CIFS_CREATE_ACTION;
1374 if (pfile_info) {
1375 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1376 36 /* CreationTime to Attributes */);
1377 /* the file_info buf is endian converted by caller */
1378 pfile_info->AllocationSize = pSMBr->AllocationSize;
1379 pfile_info->EndOfFile = pSMBr->EndOfFile;
1380 pfile_info->NumberOfLinks = cpu_to_le32(1);
1384 cifs_buf_release(pSMB);
1385 if (rc == -EAGAIN)
1386 goto openRetry;
1387 return rc;
1391 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1392 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1393 char **buf, int *pbuf_type)
1395 int rc = -EACCES;
1396 READ_REQ *pSMB = NULL;
1397 READ_RSP *pSMBr = NULL;
1398 char *pReadData = NULL;
1399 int wct;
1400 int resp_buf_type = 0;
1401 struct kvec iov[1];
1403 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1404 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1405 wct = 12;
1406 else
1407 wct = 10; /* old style read */
1409 *nbytes = 0;
1410 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1411 if (rc)
1412 return rc;
1414 /* tcon and ses pointer are checked in smb_init */
1415 if (tcon->ses->server == NULL)
1416 return -ECONNABORTED;
1418 pSMB->AndXCommand = 0xFF; /* none */
1419 pSMB->Fid = netfid;
1420 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1421 if (wct == 12)
1422 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1423 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
1424 return -EIO;
1426 pSMB->Remaining = 0;
1427 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1428 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1429 if (wct == 12)
1430 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1431 else {
1432 /* old style read */
1433 struct smb_com_readx_req *pSMBW =
1434 (struct smb_com_readx_req *)pSMB;
1435 pSMBW->ByteCount = 0;
1438 iov[0].iov_base = (char *)pSMB;
1439 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1440 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1441 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1442 cifs_stats_inc(&tcon->num_reads);
1443 pSMBr = (READ_RSP *)iov[0].iov_base;
1444 if (rc) {
1445 cERROR(1, ("Send error in read = %d", rc));
1446 } else {
1447 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1448 data_length = data_length << 16;
1449 data_length += le16_to_cpu(pSMBr->DataLength);
1450 *nbytes = data_length;
1452 /*check that DataLength would not go beyond end of SMB */
1453 if ((data_length > CIFSMaxBufSize)
1454 || (data_length > count)) {
1455 cFYI(1, ("bad length %d for count %d",
1456 data_length, count));
1457 rc = -EIO;
1458 *nbytes = 0;
1459 } else {
1460 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1461 le16_to_cpu(pSMBr->DataOffset);
1462 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1463 cERROR(1,("Faulting on read rc = %d",rc));
1464 rc = -EFAULT;
1465 }*/ /* can not use copy_to_user when using page cache*/
1466 if (*buf)
1467 memcpy(*buf, pReadData, data_length);
1471 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1472 if (*buf) {
1473 if (resp_buf_type == CIFS_SMALL_BUFFER)
1474 cifs_small_buf_release(iov[0].iov_base);
1475 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1476 cifs_buf_release(iov[0].iov_base);
1477 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1478 /* return buffer to caller to free */
1479 *buf = iov[0].iov_base;
1480 if (resp_buf_type == CIFS_SMALL_BUFFER)
1481 *pbuf_type = CIFS_SMALL_BUFFER;
1482 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1483 *pbuf_type = CIFS_LARGE_BUFFER;
1484 } /* else no valid buffer on return - leave as null */
1486 /* Note: On -EAGAIN error only caller can retry on handle based calls
1487 since file handle passed in no longer valid */
1488 return rc;
1493 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1494 const int netfid, const unsigned int count,
1495 const __u64 offset, unsigned int *nbytes, const char *buf,
1496 const char __user *ubuf, const int long_op)
1498 int rc = -EACCES;
1499 WRITE_REQ *pSMB = NULL;
1500 WRITE_RSP *pSMBr = NULL;
1501 int bytes_returned, wct;
1502 __u32 bytes_sent;
1503 __u16 byte_count;
1505 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1506 if (tcon->ses == NULL)
1507 return -ECONNABORTED;
1509 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1510 wct = 14;
1511 else
1512 wct = 12;
1514 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1515 (void **) &pSMBr);
1516 if (rc)
1517 return rc;
1518 /* tcon and ses pointer are checked in smb_init */
1519 if (tcon->ses->server == NULL)
1520 return -ECONNABORTED;
1522 pSMB->AndXCommand = 0xFF; /* none */
1523 pSMB->Fid = netfid;
1524 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1525 if (wct == 14)
1526 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1527 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1528 return -EIO;
1530 pSMB->Reserved = 0xFFFFFFFF;
1531 pSMB->WriteMode = 0;
1532 pSMB->Remaining = 0;
1534 /* Can increase buffer size if buffer is big enough in some cases ie we
1535 can send more if LARGE_WRITE_X capability returned by the server and if
1536 our buffer is big enough or if we convert to iovecs on socket writes
1537 and eliminate the copy to the CIFS buffer */
1538 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1539 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1540 } else {
1541 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1542 & ~0xFF;
1545 if (bytes_sent > count)
1546 bytes_sent = count;
1547 pSMB->DataOffset =
1548 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1549 if (buf)
1550 memcpy(pSMB->Data, buf, bytes_sent);
1551 else if (ubuf) {
1552 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1553 cifs_buf_release(pSMB);
1554 return -EFAULT;
1556 } else if (count != 0) {
1557 /* No buffer */
1558 cifs_buf_release(pSMB);
1559 return -EINVAL;
1560 } /* else setting file size with write of zero bytes */
1561 if (wct == 14)
1562 byte_count = bytes_sent + 1; /* pad */
1563 else /* wct == 12 */
1564 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1566 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1567 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1568 pSMB->hdr.smb_buf_length += byte_count;
1570 if (wct == 14)
1571 pSMB->ByteCount = cpu_to_le16(byte_count);
1572 else { /* old style write has byte count 4 bytes earlier
1573 so 4 bytes pad */
1574 struct smb_com_writex_req *pSMBW =
1575 (struct smb_com_writex_req *)pSMB;
1576 pSMBW->ByteCount = cpu_to_le16(byte_count);
1579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1580 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1581 cifs_stats_inc(&tcon->num_writes);
1582 if (rc) {
1583 cFYI(1, ("Send error in write = %d", rc));
1584 *nbytes = 0;
1585 } else {
1586 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1587 *nbytes = (*nbytes) << 16;
1588 *nbytes += le16_to_cpu(pSMBr->Count);
1591 cifs_buf_release(pSMB);
1593 /* Note: On -EAGAIN error only caller can retry on handle based calls
1594 since file handle passed in no longer valid */
1596 return rc;
1600 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1601 const int netfid, const unsigned int count,
1602 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1603 int n_vec, const int long_op)
1605 int rc = -EACCES;
1606 WRITE_REQ *pSMB = NULL;
1607 int wct;
1608 int smb_hdr_len;
1609 int resp_buf_type = 0;
1611 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1613 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1614 wct = 14;
1615 else
1616 wct = 12;
1617 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1618 if (rc)
1619 return rc;
1620 /* tcon and ses pointer are checked in smb_init */
1621 if (tcon->ses->server == NULL)
1622 return -ECONNABORTED;
1624 pSMB->AndXCommand = 0xFF; /* none */
1625 pSMB->Fid = netfid;
1626 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1627 if (wct == 14)
1628 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1629 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1630 return -EIO;
1631 pSMB->Reserved = 0xFFFFFFFF;
1632 pSMB->WriteMode = 0;
1633 pSMB->Remaining = 0;
1635 pSMB->DataOffset =
1636 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1638 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1639 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1640 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1641 if (wct == 14)
1642 pSMB->hdr.smb_buf_length += count+1;
1643 else /* wct == 12 */
1644 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1645 if (wct == 14)
1646 pSMB->ByteCount = cpu_to_le16(count + 1);
1647 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1648 struct smb_com_writex_req *pSMBW =
1649 (struct smb_com_writex_req *)pSMB;
1650 pSMBW->ByteCount = cpu_to_le16(count + 5);
1652 iov[0].iov_base = pSMB;
1653 if (wct == 14)
1654 iov[0].iov_len = smb_hdr_len + 4;
1655 else /* wct == 12 pad bigger by four bytes */
1656 iov[0].iov_len = smb_hdr_len + 8;
1659 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1660 long_op);
1661 cifs_stats_inc(&tcon->num_writes);
1662 if (rc) {
1663 cFYI(1, ("Send error Write2 = %d", rc));
1664 *nbytes = 0;
1665 } else if (resp_buf_type == 0) {
1666 /* presumably this can not happen, but best to be safe */
1667 rc = -EIO;
1668 *nbytes = 0;
1669 } else {
1670 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1671 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1672 *nbytes = (*nbytes) << 16;
1673 *nbytes += le16_to_cpu(pSMBr->Count);
1676 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1677 if (resp_buf_type == CIFS_SMALL_BUFFER)
1678 cifs_small_buf_release(iov[0].iov_base);
1679 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1680 cifs_buf_release(iov[0].iov_base);
1682 /* Note: On -EAGAIN error only caller can retry on handle based calls
1683 since file handle passed in no longer valid */
1685 return rc;
1690 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1691 const __u16 smb_file_id, const __u64 len,
1692 const __u64 offset, const __u32 numUnlock,
1693 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1695 int rc = 0;
1696 LOCK_REQ *pSMB = NULL;
1697 LOCK_RSP *pSMBr = NULL;
1698 int bytes_returned;
1699 int timeout = 0;
1700 __u16 count;
1702 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
1703 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1705 if (rc)
1706 return rc;
1708 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1710 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1711 timeout = CIFS_ASYNC_OP; /* no response expected */
1712 pSMB->Timeout = 0;
1713 } else if (waitFlag) {
1714 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1715 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1716 } else {
1717 pSMB->Timeout = 0;
1720 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1721 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1722 pSMB->LockType = lockType;
1723 pSMB->AndXCommand = 0xFF; /* none */
1724 pSMB->Fid = smb_file_id; /* netfid stays le */
1726 if ((numLock != 0) || (numUnlock != 0)) {
1727 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1728 /* BB where to store pid high? */
1729 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1730 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1731 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1732 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1733 count = sizeof(LOCKING_ANDX_RANGE);
1734 } else {
1735 /* oplock break */
1736 count = 0;
1738 pSMB->hdr.smb_buf_length += count;
1739 pSMB->ByteCount = cpu_to_le16(count);
1741 if (waitFlag) {
1742 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1743 (struct smb_hdr *) pSMBr, &bytes_returned);
1744 cifs_small_buf_release(pSMB);
1745 } else {
1746 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1747 timeout);
1748 /* SMB buffer freed by function above */
1750 cifs_stats_inc(&tcon->num_locks);
1751 if (rc)
1752 cFYI(1, ("Send error in Lock = %d", rc));
1754 /* Note: On -EAGAIN error only caller can retry on handle based calls
1755 since file handle passed in no longer valid */
1756 return rc;
1760 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1761 const __u16 smb_file_id, const int get_flag, const __u64 len,
1762 struct file_lock *pLockData, const __u16 lock_type,
1763 const bool waitFlag)
1765 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1766 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1767 struct cifs_posix_lock *parm_data;
1768 int rc = 0;
1769 int timeout = 0;
1770 int bytes_returned = 0;
1771 int resp_buf_type = 0;
1772 __u16 params, param_offset, offset, byte_count, count;
1773 struct kvec iov[1];
1775 cFYI(1, ("Posix Lock"));
1777 if (pLockData == NULL)
1778 return -EINVAL;
1780 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1782 if (rc)
1783 return rc;
1785 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1787 params = 6;
1788 pSMB->MaxSetupCount = 0;
1789 pSMB->Reserved = 0;
1790 pSMB->Flags = 0;
1791 pSMB->Reserved2 = 0;
1792 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1793 offset = param_offset + params;
1795 count = sizeof(struct cifs_posix_lock);
1796 pSMB->MaxParameterCount = cpu_to_le16(2);
1797 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1798 pSMB->SetupCount = 1;
1799 pSMB->Reserved3 = 0;
1800 if (get_flag)
1801 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1802 else
1803 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1804 byte_count = 3 /* pad */ + params + count;
1805 pSMB->DataCount = cpu_to_le16(count);
1806 pSMB->ParameterCount = cpu_to_le16(params);
1807 pSMB->TotalDataCount = pSMB->DataCount;
1808 pSMB->TotalParameterCount = pSMB->ParameterCount;
1809 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1810 parm_data = (struct cifs_posix_lock *)
1811 (((char *) &pSMB->hdr.Protocol) + offset);
1813 parm_data->lock_type = cpu_to_le16(lock_type);
1814 if (waitFlag) {
1815 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1816 parm_data->lock_flags = cpu_to_le16(1);
1817 pSMB->Timeout = cpu_to_le32(-1);
1818 } else
1819 pSMB->Timeout = 0;
1821 parm_data->pid = cpu_to_le32(current->tgid);
1822 parm_data->start = cpu_to_le64(pLockData->fl_start);
1823 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1825 pSMB->DataOffset = cpu_to_le16(offset);
1826 pSMB->Fid = smb_file_id;
1827 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1828 pSMB->Reserved4 = 0;
1829 pSMB->hdr.smb_buf_length += byte_count;
1830 pSMB->ByteCount = cpu_to_le16(byte_count);
1831 if (waitFlag) {
1832 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1833 (struct smb_hdr *) pSMBr, &bytes_returned);
1834 } else {
1835 iov[0].iov_base = (char *)pSMB;
1836 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1837 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1838 &resp_buf_type, timeout);
1839 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1840 not try to free it twice below on exit */
1841 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1844 if (rc) {
1845 cFYI(1, ("Send error in Posix Lock = %d", rc));
1846 } else if (get_flag) {
1847 /* lock structure can be returned on get */
1848 __u16 data_offset;
1849 __u16 data_count;
1850 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1852 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1853 rc = -EIO; /* bad smb */
1854 goto plk_err_exit;
1856 if (pLockData == NULL) {
1857 rc = -EINVAL;
1858 goto plk_err_exit;
1860 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1861 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1862 if (data_count < sizeof(struct cifs_posix_lock)) {
1863 rc = -EIO;
1864 goto plk_err_exit;
1866 parm_data = (struct cifs_posix_lock *)
1867 ((char *)&pSMBr->hdr.Protocol + data_offset);
1868 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1869 pLockData->fl_type = F_UNLCK;
1872 plk_err_exit:
1873 if (pSMB)
1874 cifs_small_buf_release(pSMB);
1876 if (resp_buf_type == CIFS_SMALL_BUFFER)
1877 cifs_small_buf_release(iov[0].iov_base);
1878 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1879 cifs_buf_release(iov[0].iov_base);
1881 /* Note: On -EAGAIN error only caller can retry on handle based calls
1882 since file handle passed in no longer valid */
1884 return rc;
1889 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1891 int rc = 0;
1892 CLOSE_REQ *pSMB = NULL;
1893 cFYI(1, ("In CIFSSMBClose"));
1895 /* do not retry on dead session on close */
1896 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1897 if (rc == -EAGAIN)
1898 return 0;
1899 if (rc)
1900 return rc;
1902 pSMB->FileID = (__u16) smb_file_id;
1903 pSMB->LastWriteTime = 0xFFFFFFFF;
1904 pSMB->ByteCount = 0;
1905 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1906 cifs_stats_inc(&tcon->num_closes);
1907 if (rc) {
1908 if (rc != -EINTR) {
1909 /* EINTR is expected when user ctl-c to kill app */
1910 cERROR(1, ("Send error in Close = %d", rc));
1914 /* Since session is dead, file will be closed on server already */
1915 if (rc == -EAGAIN)
1916 rc = 0;
1918 return rc;
1922 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1923 const char *fromName, const char *toName,
1924 const struct nls_table *nls_codepage, int remap)
1926 int rc = 0;
1927 RENAME_REQ *pSMB = NULL;
1928 RENAME_RSP *pSMBr = NULL;
1929 int bytes_returned;
1930 int name_len, name_len2;
1931 __u16 count;
1933 cFYI(1, ("In CIFSSMBRename"));
1934 renameRetry:
1935 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1936 (void **) &pSMBr);
1937 if (rc)
1938 return rc;
1940 pSMB->BufferFormat = 0x04;
1941 pSMB->SearchAttributes =
1942 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1943 ATTR_DIRECTORY);
1945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1946 name_len =
1947 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1948 PATH_MAX, nls_codepage, remap);
1949 name_len++; /* trailing null */
1950 name_len *= 2;
1951 pSMB->OldFileName[name_len] = 0x04; /* pad */
1952 /* protocol requires ASCII signature byte on Unicode string */
1953 pSMB->OldFileName[name_len + 1] = 0x00;
1954 name_len2 =
1955 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1956 toName, PATH_MAX, nls_codepage, remap);
1957 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1958 name_len2 *= 2; /* convert to bytes */
1959 } else { /* BB improve the check for buffer overruns BB */
1960 name_len = strnlen(fromName, PATH_MAX);
1961 name_len++; /* trailing null */
1962 strncpy(pSMB->OldFileName, fromName, name_len);
1963 name_len2 = strnlen(toName, PATH_MAX);
1964 name_len2++; /* trailing null */
1965 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1966 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1967 name_len2++; /* trailing null */
1968 name_len2++; /* signature byte */
1971 count = 1 /* 1st signature byte */ + name_len + name_len2;
1972 pSMB->hdr.smb_buf_length += count;
1973 pSMB->ByteCount = cpu_to_le16(count);
1975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1977 cifs_stats_inc(&tcon->num_renames);
1978 if (rc)
1979 cFYI(1, ("Send error in rename = %d", rc));
1981 cifs_buf_release(pSMB);
1983 if (rc == -EAGAIN)
1984 goto renameRetry;
1986 return rc;
1989 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1990 int netfid, char *target_name,
1991 const struct nls_table *nls_codepage, int remap)
1993 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1994 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1995 struct set_file_rename *rename_info;
1996 char *data_offset;
1997 char dummy_string[30];
1998 int rc = 0;
1999 int bytes_returned = 0;
2000 int len_of_str;
2001 __u16 params, param_offset, offset, count, byte_count;
2003 cFYI(1, ("Rename to File by handle"));
2004 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2005 (void **) &pSMBr);
2006 if (rc)
2007 return rc;
2009 params = 6;
2010 pSMB->MaxSetupCount = 0;
2011 pSMB->Reserved = 0;
2012 pSMB->Flags = 0;
2013 pSMB->Timeout = 0;
2014 pSMB->Reserved2 = 0;
2015 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2016 offset = param_offset + params;
2018 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2019 rename_info = (struct set_file_rename *) data_offset;
2020 pSMB->MaxParameterCount = cpu_to_le16(2);
2021 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2022 pSMB->SetupCount = 1;
2023 pSMB->Reserved3 = 0;
2024 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2025 byte_count = 3 /* pad */ + params;
2026 pSMB->ParameterCount = cpu_to_le16(params);
2027 pSMB->TotalParameterCount = pSMB->ParameterCount;
2028 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2029 pSMB->DataOffset = cpu_to_le16(offset);
2030 /* construct random name ".cifs_tmp<inodenum><mid>" */
2031 rename_info->overwrite = cpu_to_le32(1);
2032 rename_info->root_fid = 0;
2033 /* unicode only call */
2034 if (target_name == NULL) {
2035 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2036 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2037 dummy_string, 24, nls_codepage, remap);
2038 } else {
2039 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2040 target_name, PATH_MAX, nls_codepage,
2041 remap);
2043 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2044 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2045 byte_count += count;
2046 pSMB->DataCount = cpu_to_le16(count);
2047 pSMB->TotalDataCount = pSMB->DataCount;
2048 pSMB->Fid = netfid;
2049 pSMB->InformationLevel =
2050 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2051 pSMB->Reserved4 = 0;
2052 pSMB->hdr.smb_buf_length += byte_count;
2053 pSMB->ByteCount = cpu_to_le16(byte_count);
2054 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2056 cifs_stats_inc(&pTcon->num_t2renames);
2057 if (rc)
2058 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2060 cifs_buf_release(pSMB);
2062 /* Note: On -EAGAIN error only caller can retry on handle based calls
2063 since file handle passed in no longer valid */
2065 return rc;
2069 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2070 const __u16 target_tid, const char *toName, const int flags,
2071 const struct nls_table *nls_codepage, int remap)
2073 int rc = 0;
2074 COPY_REQ *pSMB = NULL;
2075 COPY_RSP *pSMBr = NULL;
2076 int bytes_returned;
2077 int name_len, name_len2;
2078 __u16 count;
2080 cFYI(1, ("In CIFSSMBCopy"));
2081 copyRetry:
2082 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2083 (void **) &pSMBr);
2084 if (rc)
2085 return rc;
2087 pSMB->BufferFormat = 0x04;
2088 pSMB->Tid2 = target_tid;
2090 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2092 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2093 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2094 fromName, PATH_MAX, nls_codepage,
2095 remap);
2096 name_len++; /* trailing null */
2097 name_len *= 2;
2098 pSMB->OldFileName[name_len] = 0x04; /* pad */
2099 /* protocol requires ASCII signature byte on Unicode string */
2100 pSMB->OldFileName[name_len + 1] = 0x00;
2101 name_len2 =
2102 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2103 toName, PATH_MAX, nls_codepage, remap);
2104 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2105 name_len2 *= 2; /* convert to bytes */
2106 } else { /* BB improve the check for buffer overruns BB */
2107 name_len = strnlen(fromName, PATH_MAX);
2108 name_len++; /* trailing null */
2109 strncpy(pSMB->OldFileName, fromName, name_len);
2110 name_len2 = strnlen(toName, PATH_MAX);
2111 name_len2++; /* trailing null */
2112 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2113 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2114 name_len2++; /* trailing null */
2115 name_len2++; /* signature byte */
2118 count = 1 /* 1st signature byte */ + name_len + name_len2;
2119 pSMB->hdr.smb_buf_length += count;
2120 pSMB->ByteCount = cpu_to_le16(count);
2122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2124 if (rc) {
2125 cFYI(1, ("Send error in copy = %d with %d files copied",
2126 rc, le16_to_cpu(pSMBr->CopyCount)));
2128 if (pSMB)
2129 cifs_buf_release(pSMB);
2131 if (rc == -EAGAIN)
2132 goto copyRetry;
2134 return rc;
2138 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2139 const char *fromName, const char *toName,
2140 const struct nls_table *nls_codepage)
2142 TRANSACTION2_SPI_REQ *pSMB = NULL;
2143 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2144 char *data_offset;
2145 int name_len;
2146 int name_len_target;
2147 int rc = 0;
2148 int bytes_returned = 0;
2149 __u16 params, param_offset, offset, byte_count;
2151 cFYI(1, ("In Symlink Unix style"));
2152 createSymLinkRetry:
2153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154 (void **) &pSMBr);
2155 if (rc)
2156 return rc;
2158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2159 name_len =
2160 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2161 /* find define for this maxpathcomponent */
2162 , nls_codepage);
2163 name_len++; /* trailing null */
2164 name_len *= 2;
2166 } else { /* BB improve the check for buffer overruns BB */
2167 name_len = strnlen(fromName, PATH_MAX);
2168 name_len++; /* trailing null */
2169 strncpy(pSMB->FileName, fromName, name_len);
2171 params = 6 + name_len;
2172 pSMB->MaxSetupCount = 0;
2173 pSMB->Reserved = 0;
2174 pSMB->Flags = 0;
2175 pSMB->Timeout = 0;
2176 pSMB->Reserved2 = 0;
2177 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2178 InformationLevel) - 4;
2179 offset = param_offset + params;
2181 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2183 name_len_target =
2184 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2185 /* find define for this maxpathcomponent */
2186 , nls_codepage);
2187 name_len_target++; /* trailing null */
2188 name_len_target *= 2;
2189 } else { /* BB improve the check for buffer overruns BB */
2190 name_len_target = strnlen(toName, PATH_MAX);
2191 name_len_target++; /* trailing null */
2192 strncpy(data_offset, toName, name_len_target);
2195 pSMB->MaxParameterCount = cpu_to_le16(2);
2196 /* BB find exact max on data count below from sess */
2197 pSMB->MaxDataCount = cpu_to_le16(1000);
2198 pSMB->SetupCount = 1;
2199 pSMB->Reserved3 = 0;
2200 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2201 byte_count = 3 /* pad */ + params + name_len_target;
2202 pSMB->DataCount = cpu_to_le16(name_len_target);
2203 pSMB->ParameterCount = cpu_to_le16(params);
2204 pSMB->TotalDataCount = pSMB->DataCount;
2205 pSMB->TotalParameterCount = pSMB->ParameterCount;
2206 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2207 pSMB->DataOffset = cpu_to_le16(offset);
2208 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2209 pSMB->Reserved4 = 0;
2210 pSMB->hdr.smb_buf_length += byte_count;
2211 pSMB->ByteCount = cpu_to_le16(byte_count);
2212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2214 cifs_stats_inc(&tcon->num_symlinks);
2215 if (rc)
2216 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2218 if (pSMB)
2219 cifs_buf_release(pSMB);
2221 if (rc == -EAGAIN)
2222 goto createSymLinkRetry;
2224 return rc;
2228 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2229 const char *fromName, const char *toName,
2230 const struct nls_table *nls_codepage, int remap)
2232 TRANSACTION2_SPI_REQ *pSMB = NULL;
2233 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2234 char *data_offset;
2235 int name_len;
2236 int name_len_target;
2237 int rc = 0;
2238 int bytes_returned = 0;
2239 __u16 params, param_offset, offset, byte_count;
2241 cFYI(1, ("In Create Hard link Unix style"));
2242 createHardLinkRetry:
2243 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2244 (void **) &pSMBr);
2245 if (rc)
2246 return rc;
2248 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2249 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2250 PATH_MAX, nls_codepage, remap);
2251 name_len++; /* trailing null */
2252 name_len *= 2;
2254 } else { /* BB improve the check for buffer overruns BB */
2255 name_len = strnlen(toName, PATH_MAX);
2256 name_len++; /* trailing null */
2257 strncpy(pSMB->FileName, toName, name_len);
2259 params = 6 + name_len;
2260 pSMB->MaxSetupCount = 0;
2261 pSMB->Reserved = 0;
2262 pSMB->Flags = 0;
2263 pSMB->Timeout = 0;
2264 pSMB->Reserved2 = 0;
2265 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2266 InformationLevel) - 4;
2267 offset = param_offset + params;
2269 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271 name_len_target =
2272 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2273 nls_codepage, remap);
2274 name_len_target++; /* trailing null */
2275 name_len_target *= 2;
2276 } else { /* BB improve the check for buffer overruns BB */
2277 name_len_target = strnlen(fromName, PATH_MAX);
2278 name_len_target++; /* trailing null */
2279 strncpy(data_offset, fromName, name_len_target);
2282 pSMB->MaxParameterCount = cpu_to_le16(2);
2283 /* BB find exact max on data count below from sess*/
2284 pSMB->MaxDataCount = cpu_to_le16(1000);
2285 pSMB->SetupCount = 1;
2286 pSMB->Reserved3 = 0;
2287 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2288 byte_count = 3 /* pad */ + params + name_len_target;
2289 pSMB->ParameterCount = cpu_to_le16(params);
2290 pSMB->TotalParameterCount = pSMB->ParameterCount;
2291 pSMB->DataCount = cpu_to_le16(name_len_target);
2292 pSMB->TotalDataCount = pSMB->DataCount;
2293 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2294 pSMB->DataOffset = cpu_to_le16(offset);
2295 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2296 pSMB->Reserved4 = 0;
2297 pSMB->hdr.smb_buf_length += byte_count;
2298 pSMB->ByteCount = cpu_to_le16(byte_count);
2299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2301 cifs_stats_inc(&tcon->num_hardlinks);
2302 if (rc)
2303 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2305 cifs_buf_release(pSMB);
2306 if (rc == -EAGAIN)
2307 goto createHardLinkRetry;
2309 return rc;
2313 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2314 const char *fromName, const char *toName,
2315 const struct nls_table *nls_codepage, int remap)
2317 int rc = 0;
2318 NT_RENAME_REQ *pSMB = NULL;
2319 RENAME_RSP *pSMBr = NULL;
2320 int bytes_returned;
2321 int name_len, name_len2;
2322 __u16 count;
2324 cFYI(1, ("In CIFSCreateHardLink"));
2325 winCreateHardLinkRetry:
2327 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2328 (void **) &pSMBr);
2329 if (rc)
2330 return rc;
2332 pSMB->SearchAttributes =
2333 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2334 ATTR_DIRECTORY);
2335 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2336 pSMB->ClusterCount = 0;
2338 pSMB->BufferFormat = 0x04;
2340 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2341 name_len =
2342 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2343 PATH_MAX, nls_codepage, remap);
2344 name_len++; /* trailing null */
2345 name_len *= 2;
2346 pSMB->OldFileName[name_len] = 0; /* pad */
2347 pSMB->OldFileName[name_len + 1] = 0x04;
2348 name_len2 =
2349 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2350 toName, PATH_MAX, nls_codepage, remap);
2351 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2352 name_len2 *= 2; /* convert to bytes */
2353 } else { /* BB improve the check for buffer overruns BB */
2354 name_len = strnlen(fromName, PATH_MAX);
2355 name_len++; /* trailing null */
2356 strncpy(pSMB->OldFileName, fromName, name_len);
2357 name_len2 = strnlen(toName, PATH_MAX);
2358 name_len2++; /* trailing null */
2359 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2360 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2361 name_len2++; /* trailing null */
2362 name_len2++; /* signature byte */
2365 count = 1 /* string type byte */ + name_len + name_len2;
2366 pSMB->hdr.smb_buf_length += count;
2367 pSMB->ByteCount = cpu_to_le16(count);
2369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2371 cifs_stats_inc(&tcon->num_hardlinks);
2372 if (rc)
2373 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2375 cifs_buf_release(pSMB);
2376 if (rc == -EAGAIN)
2377 goto winCreateHardLinkRetry;
2379 return rc;
2383 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2384 const unsigned char *searchName,
2385 char *symlinkinfo, const int buflen,
2386 const struct nls_table *nls_codepage)
2388 /* SMB_QUERY_FILE_UNIX_LINK */
2389 TRANSACTION2_QPI_REQ *pSMB = NULL;
2390 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2391 int rc = 0;
2392 int bytes_returned;
2393 int name_len;
2394 __u16 params, byte_count;
2396 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2398 querySymLinkRetry:
2399 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2400 (void **) &pSMBr);
2401 if (rc)
2402 return rc;
2404 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2405 name_len =
2406 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2407 PATH_MAX, nls_codepage);
2408 name_len++; /* trailing null */
2409 name_len *= 2;
2410 } else { /* BB improve the check for buffer overruns BB */
2411 name_len = strnlen(searchName, PATH_MAX);
2412 name_len++; /* trailing null */
2413 strncpy(pSMB->FileName, searchName, name_len);
2416 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2417 pSMB->TotalDataCount = 0;
2418 pSMB->MaxParameterCount = cpu_to_le16(2);
2419 /* BB find exact max data count below from sess structure BB */
2420 pSMB->MaxDataCount = cpu_to_le16(4000);
2421 pSMB->MaxSetupCount = 0;
2422 pSMB->Reserved = 0;
2423 pSMB->Flags = 0;
2424 pSMB->Timeout = 0;
2425 pSMB->Reserved2 = 0;
2426 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2427 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2428 pSMB->DataCount = 0;
2429 pSMB->DataOffset = 0;
2430 pSMB->SetupCount = 1;
2431 pSMB->Reserved3 = 0;
2432 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2433 byte_count = params + 1 /* pad */ ;
2434 pSMB->TotalParameterCount = cpu_to_le16(params);
2435 pSMB->ParameterCount = pSMB->TotalParameterCount;
2436 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2437 pSMB->Reserved4 = 0;
2438 pSMB->hdr.smb_buf_length += byte_count;
2439 pSMB->ByteCount = cpu_to_le16(byte_count);
2441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2443 if (rc) {
2444 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2445 } else {
2446 /* decode response */
2448 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2449 if (rc || (pSMBr->ByteCount < 2))
2450 /* BB also check enough total bytes returned */
2451 rc = -EIO; /* bad smb */
2452 else {
2453 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2454 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2456 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2457 name_len = UniStrnlen((wchar_t *) ((char *)
2458 &pSMBr->hdr.Protocol + data_offset),
2459 min_t(const int, buflen, count) / 2);
2460 /* BB FIXME investigate remapping reserved chars here */
2461 cifs_strfromUCS_le(symlinkinfo,
2462 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2463 + data_offset),
2464 name_len, nls_codepage);
2465 } else {
2466 strncpy(symlinkinfo,
2467 (char *) &pSMBr->hdr.Protocol +
2468 data_offset,
2469 min_t(const int, buflen, count));
2471 symlinkinfo[buflen] = 0;
2472 /* just in case so calling code does not go off the end of buffer */
2475 cifs_buf_release(pSMB);
2476 if (rc == -EAGAIN)
2477 goto querySymLinkRetry;
2478 return rc;
2481 #ifdef CONFIG_CIFS_EXPERIMENTAL
2482 /* Initialize NT TRANSACT SMB into small smb request buffer.
2483 This assumes that all NT TRANSACTS that we init here have
2484 total parm and data under about 400 bytes (to fit in small cifs
2485 buffer size), which is the case so far, it easily fits. NB:
2486 Setup words themselves and ByteCount
2487 MaxSetupCount (size of returned setup area) and
2488 MaxParameterCount (returned parms size) must be set by caller */
2489 static int
2490 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2491 const int parm_len, struct cifsTconInfo *tcon,
2492 void **ret_buf)
2494 int rc;
2495 __u32 temp_offset;
2496 struct smb_com_ntransact_req *pSMB;
2498 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2499 (void **)&pSMB);
2500 if (rc)
2501 return rc;
2502 *ret_buf = (void *)pSMB;
2503 pSMB->Reserved = 0;
2504 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2505 pSMB->TotalDataCount = 0;
2506 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2507 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2508 pSMB->ParameterCount = pSMB->TotalParameterCount;
2509 pSMB->DataCount = pSMB->TotalDataCount;
2510 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2511 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2512 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2513 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2514 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2515 pSMB->SubCommand = cpu_to_le16(sub_command);
2516 return 0;
2519 static int
2520 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2521 __u32 *pparmlen, __u32 *pdatalen)
2523 char *end_of_smb;
2524 __u32 data_count, data_offset, parm_count, parm_offset;
2525 struct smb_com_ntransact_rsp *pSMBr;
2527 *pdatalen = 0;
2528 *pparmlen = 0;
2530 if (buf == NULL)
2531 return -EINVAL;
2533 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2535 /* ByteCount was converted from little endian in SendReceive */
2536 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2537 (char *)&pSMBr->ByteCount;
2539 data_offset = le32_to_cpu(pSMBr->DataOffset);
2540 data_count = le32_to_cpu(pSMBr->DataCount);
2541 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2542 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2544 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2545 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2547 /* should we also check that parm and data areas do not overlap? */
2548 if (*ppparm > end_of_smb) {
2549 cFYI(1, ("parms start after end of smb"));
2550 return -EINVAL;
2551 } else if (parm_count + *ppparm > end_of_smb) {
2552 cFYI(1, ("parm end after end of smb"));
2553 return -EINVAL;
2554 } else if (*ppdata > end_of_smb) {
2555 cFYI(1, ("data starts after end of smb"));
2556 return -EINVAL;
2557 } else if (data_count + *ppdata > end_of_smb) {
2558 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2559 *ppdata, data_count, (data_count + *ppdata),
2560 end_of_smb, pSMBr));
2561 return -EINVAL;
2562 } else if (parm_count + data_count > pSMBr->ByteCount) {
2563 cFYI(1, ("parm count and data count larger than SMB"));
2564 return -EINVAL;
2566 *pdatalen = data_count;
2567 *pparmlen = parm_count;
2568 return 0;
2570 #endif /* CIFS_EXPERIMENTAL */
2573 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2574 const unsigned char *searchName,
2575 char *symlinkinfo, const int buflen, __u16 fid,
2576 const struct nls_table *nls_codepage)
2578 int rc = 0;
2579 int bytes_returned;
2580 int name_len;
2581 struct smb_com_transaction_ioctl_req *pSMB;
2582 struct smb_com_transaction_ioctl_rsp *pSMBr;
2584 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2585 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2586 (void **) &pSMBr);
2587 if (rc)
2588 return rc;
2590 pSMB->TotalParameterCount = 0 ;
2591 pSMB->TotalDataCount = 0;
2592 pSMB->MaxParameterCount = cpu_to_le32(2);
2593 /* BB find exact data count max from sess structure BB */
2594 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2595 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2596 pSMB->MaxSetupCount = 4;
2597 pSMB->Reserved = 0;
2598 pSMB->ParameterOffset = 0;
2599 pSMB->DataCount = 0;
2600 pSMB->DataOffset = 0;
2601 pSMB->SetupCount = 4;
2602 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2603 pSMB->ParameterCount = pSMB->TotalParameterCount;
2604 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2605 pSMB->IsFsctl = 1; /* FSCTL */
2606 pSMB->IsRootFlag = 0;
2607 pSMB->Fid = fid; /* file handle always le */
2608 pSMB->ByteCount = 0;
2610 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2611 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2612 if (rc) {
2613 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2614 } else { /* decode response */
2615 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2616 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2617 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2618 /* BB also check enough total bytes returned */
2619 rc = -EIO; /* bad smb */
2620 else {
2621 if (data_count && (data_count < 2048)) {
2622 char *end_of_smb = 2 /* sizeof byte count */ +
2623 pSMBr->ByteCount +
2624 (char *)&pSMBr->ByteCount;
2626 struct reparse_data *reparse_buf =
2627 (struct reparse_data *)
2628 ((char *)&pSMBr->hdr.Protocol
2629 + data_offset);
2630 if ((char *)reparse_buf >= end_of_smb) {
2631 rc = -EIO;
2632 goto qreparse_out;
2634 if ((reparse_buf->LinkNamesBuf +
2635 reparse_buf->TargetNameOffset +
2636 reparse_buf->TargetNameLen) >
2637 end_of_smb) {
2638 cFYI(1, ("reparse buf beyond SMB"));
2639 rc = -EIO;
2640 goto qreparse_out;
2643 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2644 name_len = UniStrnlen((wchar_t *)
2645 (reparse_buf->LinkNamesBuf +
2646 reparse_buf->TargetNameOffset),
2647 min(buflen/2,
2648 reparse_buf->TargetNameLen / 2));
2649 cifs_strfromUCS_le(symlinkinfo,
2650 (__le16 *) (reparse_buf->LinkNamesBuf +
2651 reparse_buf->TargetNameOffset),
2652 name_len, nls_codepage);
2653 } else { /* ASCII names */
2654 strncpy(symlinkinfo,
2655 reparse_buf->LinkNamesBuf +
2656 reparse_buf->TargetNameOffset,
2657 min_t(const int, buflen,
2658 reparse_buf->TargetNameLen));
2660 } else {
2661 rc = -EIO;
2662 cFYI(1, ("Invalid return data count on "
2663 "get reparse info ioctl"));
2665 symlinkinfo[buflen] = 0; /* just in case so the caller
2666 does not go off the end of the buffer */
2667 cFYI(1, ("readlink result - %s", symlinkinfo));
2670 qreparse_out:
2671 cifs_buf_release(pSMB);
2673 /* Note: On -EAGAIN error only caller can retry on handle based calls
2674 since file handle passed in no longer valid */
2676 return rc;
2679 #ifdef CONFIG_CIFS_POSIX
2681 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2682 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2683 struct cifs_posix_ace *cifs_ace)
2685 /* u8 cifs fields do not need le conversion */
2686 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2687 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2688 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2689 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2691 return;
2694 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2695 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2696 const int acl_type, const int size_of_data_area)
2698 int size = 0;
2699 int i;
2700 __u16 count;
2701 struct cifs_posix_ace *pACE;
2702 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2703 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2705 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2706 return -EOPNOTSUPP;
2708 if (acl_type & ACL_TYPE_ACCESS) {
2709 count = le16_to_cpu(cifs_acl->access_entry_count);
2710 pACE = &cifs_acl->ace_array[0];
2711 size = sizeof(struct cifs_posix_acl);
2712 size += sizeof(struct cifs_posix_ace) * count;
2713 /* check if we would go beyond end of SMB */
2714 if (size_of_data_area < size) {
2715 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2716 size_of_data_area, size));
2717 return -EINVAL;
2719 } else if (acl_type & ACL_TYPE_DEFAULT) {
2720 count = le16_to_cpu(cifs_acl->access_entry_count);
2721 size = sizeof(struct cifs_posix_acl);
2722 size += sizeof(struct cifs_posix_ace) * count;
2723 /* skip past access ACEs to get to default ACEs */
2724 pACE = &cifs_acl->ace_array[count];
2725 count = le16_to_cpu(cifs_acl->default_entry_count);
2726 size += sizeof(struct cifs_posix_ace) * count;
2727 /* check if we would go beyond end of SMB */
2728 if (size_of_data_area < size)
2729 return -EINVAL;
2730 } else {
2731 /* illegal type */
2732 return -EINVAL;
2735 size = posix_acl_xattr_size(count);
2736 if ((buflen == 0) || (local_acl == NULL)) {
2737 /* used to query ACL EA size */
2738 } else if (size > buflen) {
2739 return -ERANGE;
2740 } else /* buffer big enough */ {
2741 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2742 for (i = 0; i < count ; i++) {
2743 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2744 pACE++;
2747 return size;
2750 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2751 const posix_acl_xattr_entry *local_ace)
2753 __u16 rc = 0; /* 0 = ACL converted ok */
2755 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2756 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2757 /* BB is there a better way to handle the large uid? */
2758 if (local_ace->e_id == cpu_to_le32(-1)) {
2759 /* Probably no need to le convert -1 on any arch but can not hurt */
2760 cifs_ace->cifs_uid = cpu_to_le64(-1);
2761 } else
2762 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2763 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2764 return rc;
2767 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2768 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2769 const int buflen, const int acl_type)
2771 __u16 rc = 0;
2772 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2773 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2774 int count;
2775 int i;
2777 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2778 return 0;
2780 count = posix_acl_xattr_count((size_t)buflen);
2781 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2782 "version of %d",
2783 count, buflen, le32_to_cpu(local_acl->a_version)));
2784 if (le32_to_cpu(local_acl->a_version) != 2) {
2785 cFYI(1, ("unknown POSIX ACL version %d",
2786 le32_to_cpu(local_acl->a_version)));
2787 return 0;
2789 cifs_acl->version = cpu_to_le16(1);
2790 if (acl_type == ACL_TYPE_ACCESS)
2791 cifs_acl->access_entry_count = cpu_to_le16(count);
2792 else if (acl_type == ACL_TYPE_DEFAULT)
2793 cifs_acl->default_entry_count = cpu_to_le16(count);
2794 else {
2795 cFYI(1, ("unknown ACL type %d", acl_type));
2796 return 0;
2798 for (i = 0; i < count; i++) {
2799 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2800 &local_acl->a_entries[i]);
2801 if (rc != 0) {
2802 /* ACE not converted */
2803 break;
2806 if (rc == 0) {
2807 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2808 rc += sizeof(struct cifs_posix_acl);
2809 /* BB add check to make sure ACL does not overflow SMB */
2811 return rc;
2815 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2816 const unsigned char *searchName,
2817 char *acl_inf, const int buflen, const int acl_type,
2818 const struct nls_table *nls_codepage, int remap)
2820 /* SMB_QUERY_POSIX_ACL */
2821 TRANSACTION2_QPI_REQ *pSMB = NULL;
2822 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2823 int rc = 0;
2824 int bytes_returned;
2825 int name_len;
2826 __u16 params, byte_count;
2828 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2830 queryAclRetry:
2831 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2832 (void **) &pSMBr);
2833 if (rc)
2834 return rc;
2836 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2837 name_len =
2838 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2839 PATH_MAX, nls_codepage, remap);
2840 name_len++; /* trailing null */
2841 name_len *= 2;
2842 pSMB->FileName[name_len] = 0;
2843 pSMB->FileName[name_len+1] = 0;
2844 } else { /* BB improve the check for buffer overruns BB */
2845 name_len = strnlen(searchName, PATH_MAX);
2846 name_len++; /* trailing null */
2847 strncpy(pSMB->FileName, searchName, name_len);
2850 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2851 pSMB->TotalDataCount = 0;
2852 pSMB->MaxParameterCount = cpu_to_le16(2);
2853 /* BB find exact max data count below from sess structure BB */
2854 pSMB->MaxDataCount = cpu_to_le16(4000);
2855 pSMB->MaxSetupCount = 0;
2856 pSMB->Reserved = 0;
2857 pSMB->Flags = 0;
2858 pSMB->Timeout = 0;
2859 pSMB->Reserved2 = 0;
2860 pSMB->ParameterOffset = cpu_to_le16(
2861 offsetof(struct smb_com_transaction2_qpi_req,
2862 InformationLevel) - 4);
2863 pSMB->DataCount = 0;
2864 pSMB->DataOffset = 0;
2865 pSMB->SetupCount = 1;
2866 pSMB->Reserved3 = 0;
2867 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2868 byte_count = params + 1 /* pad */ ;
2869 pSMB->TotalParameterCount = cpu_to_le16(params);
2870 pSMB->ParameterCount = pSMB->TotalParameterCount;
2871 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2872 pSMB->Reserved4 = 0;
2873 pSMB->hdr.smb_buf_length += byte_count;
2874 pSMB->ByteCount = cpu_to_le16(byte_count);
2876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2878 cifs_stats_inc(&tcon->num_acl_get);
2879 if (rc) {
2880 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2881 } else {
2882 /* decode response */
2884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2885 if (rc || (pSMBr->ByteCount < 2))
2886 /* BB also check enough total bytes returned */
2887 rc = -EIO; /* bad smb */
2888 else {
2889 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2890 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2891 rc = cifs_copy_posix_acl(acl_inf,
2892 (char *)&pSMBr->hdr.Protocol+data_offset,
2893 buflen, acl_type, count);
2896 cifs_buf_release(pSMB);
2897 if (rc == -EAGAIN)
2898 goto queryAclRetry;
2899 return rc;
2903 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2904 const unsigned char *fileName,
2905 const char *local_acl, const int buflen,
2906 const int acl_type,
2907 const struct nls_table *nls_codepage, int remap)
2909 struct smb_com_transaction2_spi_req *pSMB = NULL;
2910 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2911 char *parm_data;
2912 int name_len;
2913 int rc = 0;
2914 int bytes_returned = 0;
2915 __u16 params, byte_count, data_count, param_offset, offset;
2917 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2918 setAclRetry:
2919 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2920 (void **) &pSMBr);
2921 if (rc)
2922 return rc;
2923 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2924 name_len =
2925 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2926 PATH_MAX, nls_codepage, remap);
2927 name_len++; /* trailing null */
2928 name_len *= 2;
2929 } else { /* BB improve the check for buffer overruns BB */
2930 name_len = strnlen(fileName, PATH_MAX);
2931 name_len++; /* trailing null */
2932 strncpy(pSMB->FileName, fileName, name_len);
2934 params = 6 + name_len;
2935 pSMB->MaxParameterCount = cpu_to_le16(2);
2936 /* BB find max SMB size from sess */
2937 pSMB->MaxDataCount = cpu_to_le16(1000);
2938 pSMB->MaxSetupCount = 0;
2939 pSMB->Reserved = 0;
2940 pSMB->Flags = 0;
2941 pSMB->Timeout = 0;
2942 pSMB->Reserved2 = 0;
2943 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2944 InformationLevel) - 4;
2945 offset = param_offset + params;
2946 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2947 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2949 /* convert to on the wire format for POSIX ACL */
2950 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2952 if (data_count == 0) {
2953 rc = -EOPNOTSUPP;
2954 goto setACLerrorExit;
2956 pSMB->DataOffset = cpu_to_le16(offset);
2957 pSMB->SetupCount = 1;
2958 pSMB->Reserved3 = 0;
2959 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2960 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2961 byte_count = 3 /* pad */ + params + data_count;
2962 pSMB->DataCount = cpu_to_le16(data_count);
2963 pSMB->TotalDataCount = pSMB->DataCount;
2964 pSMB->ParameterCount = cpu_to_le16(params);
2965 pSMB->TotalParameterCount = pSMB->ParameterCount;
2966 pSMB->Reserved4 = 0;
2967 pSMB->hdr.smb_buf_length += byte_count;
2968 pSMB->ByteCount = cpu_to_le16(byte_count);
2969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2971 if (rc)
2972 cFYI(1, ("Set POSIX ACL returned %d", rc));
2974 setACLerrorExit:
2975 cifs_buf_release(pSMB);
2976 if (rc == -EAGAIN)
2977 goto setAclRetry;
2978 return rc;
2981 /* BB fix tabs in this function FIXME BB */
2983 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2984 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2986 int rc = 0;
2987 struct smb_t2_qfi_req *pSMB = NULL;
2988 struct smb_t2_qfi_rsp *pSMBr = NULL;
2989 int bytes_returned;
2990 __u16 params, byte_count;
2992 cFYI(1, ("In GetExtAttr"));
2993 if (tcon == NULL)
2994 return -ENODEV;
2996 GetExtAttrRetry:
2997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2998 (void **) &pSMBr);
2999 if (rc)
3000 return rc;
3002 params = 2 /* level */ + 2 /* fid */;
3003 pSMB->t2.TotalDataCount = 0;
3004 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3005 /* BB find exact max data count below from sess structure BB */
3006 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3007 pSMB->t2.MaxSetupCount = 0;
3008 pSMB->t2.Reserved = 0;
3009 pSMB->t2.Flags = 0;
3010 pSMB->t2.Timeout = 0;
3011 pSMB->t2.Reserved2 = 0;
3012 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3013 Fid) - 4);
3014 pSMB->t2.DataCount = 0;
3015 pSMB->t2.DataOffset = 0;
3016 pSMB->t2.SetupCount = 1;
3017 pSMB->t2.Reserved3 = 0;
3018 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3019 byte_count = params + 1 /* pad */ ;
3020 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3021 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3022 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3023 pSMB->Pad = 0;
3024 pSMB->Fid = netfid;
3025 pSMB->hdr.smb_buf_length += byte_count;
3026 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3030 if (rc) {
3031 cFYI(1, ("error %d in GetExtAttr", rc));
3032 } else {
3033 /* decode response */
3034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3035 if (rc || (pSMBr->ByteCount < 2))
3036 /* BB also check enough total bytes returned */
3037 /* If rc should we check for EOPNOSUPP and
3038 disable the srvino flag? or in caller? */
3039 rc = -EIO; /* bad smb */
3040 else {
3041 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3042 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3043 struct file_chattr_info *pfinfo;
3044 /* BB Do we need a cast or hash here ? */
3045 if (count != 16) {
3046 cFYI(1, ("Illegal size ret in GetExtAttr"));
3047 rc = -EIO;
3048 goto GetExtAttrOut;
3050 pfinfo = (struct file_chattr_info *)
3051 (data_offset + (char *) &pSMBr->hdr.Protocol);
3052 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3053 *pMask = le64_to_cpu(pfinfo->mask);
3056 GetExtAttrOut:
3057 cifs_buf_release(pSMB);
3058 if (rc == -EAGAIN)
3059 goto GetExtAttrRetry;
3060 return rc;
3063 #endif /* CONFIG_POSIX */
3065 #ifdef CONFIG_CIFS_EXPERIMENTAL
3066 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3068 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3069 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3071 int rc = 0;
3072 int buf_type = 0;
3073 QUERY_SEC_DESC_REQ *pSMB;
3074 struct kvec iov[1];
3076 cFYI(1, ("GetCifsACL"));
3078 *pbuflen = 0;
3079 *acl_inf = NULL;
3081 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3082 8 /* parm len */, tcon, (void **) &pSMB);
3083 if (rc)
3084 return rc;
3086 pSMB->MaxParameterCount = cpu_to_le32(4);
3087 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3088 pSMB->MaxSetupCount = 0;
3089 pSMB->Fid = fid; /* file handle always le */
3090 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3091 CIFS_ACL_DACL);
3092 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3093 pSMB->hdr.smb_buf_length += 11;
3094 iov[0].iov_base = (char *)pSMB;
3095 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3097 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3098 CIFS_STD_OP);
3099 cifs_stats_inc(&tcon->num_acl_get);
3100 if (rc) {
3101 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3102 } else { /* decode response */
3103 __le32 *parm;
3104 __u32 parm_len;
3105 __u32 acl_len;
3106 struct smb_com_ntransact_rsp *pSMBr;
3107 char *pdata;
3109 /* validate_nttransact */
3110 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3111 &pdata, &parm_len, pbuflen);
3112 if (rc)
3113 goto qsec_out;
3114 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3116 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3118 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3119 rc = -EIO; /* bad smb */
3120 *pbuflen = 0;
3121 goto qsec_out;
3124 /* BB check that data area is minimum length and as big as acl_len */
3126 acl_len = le32_to_cpu(*parm);
3127 if (acl_len != *pbuflen) {
3128 cERROR(1, ("acl length %d does not match %d",
3129 acl_len, *pbuflen));
3130 if (*pbuflen > acl_len)
3131 *pbuflen = acl_len;
3134 /* check if buffer is big enough for the acl
3135 header followed by the smallest SID */
3136 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3137 (*pbuflen >= 64 * 1024)) {
3138 cERROR(1, ("bad acl length %d", *pbuflen));
3139 rc = -EINVAL;
3140 *pbuflen = 0;
3141 } else {
3142 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3143 if (*acl_inf == NULL) {
3144 *pbuflen = 0;
3145 rc = -ENOMEM;
3147 memcpy(*acl_inf, pdata, *pbuflen);
3150 qsec_out:
3151 if (buf_type == CIFS_SMALL_BUFFER)
3152 cifs_small_buf_release(iov[0].iov_base);
3153 else if (buf_type == CIFS_LARGE_BUFFER)
3154 cifs_buf_release(iov[0].iov_base);
3155 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3156 return rc;
3160 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3161 struct cifs_ntsd *pntsd, __u32 acllen)
3163 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3164 int rc = 0;
3165 int bytes_returned = 0;
3166 SET_SEC_DESC_REQ *pSMB = NULL;
3167 NTRANSACT_RSP *pSMBr = NULL;
3169 setCifsAclRetry:
3170 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3171 (void **) &pSMBr);
3172 if (rc)
3173 return (rc);
3175 pSMB->MaxSetupCount = 0;
3176 pSMB->Reserved = 0;
3178 param_count = 8;
3179 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3180 data_count = acllen;
3181 data_offset = param_offset + param_count;
3182 byte_count = 3 /* pad */ + param_count;
3184 pSMB->DataCount = cpu_to_le32(data_count);
3185 pSMB->TotalDataCount = pSMB->DataCount;
3186 pSMB->MaxParameterCount = cpu_to_le32(4);
3187 pSMB->MaxDataCount = cpu_to_le32(16384);
3188 pSMB->ParameterCount = cpu_to_le32(param_count);
3189 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3190 pSMB->TotalParameterCount = pSMB->ParameterCount;
3191 pSMB->DataOffset = cpu_to_le32(data_offset);
3192 pSMB->SetupCount = 0;
3193 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3194 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3196 pSMB->Fid = fid; /* file handle always le */
3197 pSMB->Reserved2 = 0;
3198 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3200 if (pntsd && acllen) {
3201 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3202 (char *) pntsd,
3203 acllen);
3204 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3206 } else
3207 pSMB->hdr.smb_buf_length += byte_count;
3209 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3210 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3212 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3213 if (rc)
3214 cFYI(1, ("Set CIFS ACL returned %d", rc));
3215 cifs_buf_release(pSMB);
3217 if (rc == -EAGAIN)
3218 goto setCifsAclRetry;
3220 return (rc);
3223 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3225 /* Legacy Query Path Information call for lookup to old servers such
3226 as Win9x/WinME */
3227 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3228 const unsigned char *searchName,
3229 FILE_ALL_INFO *pFinfo,
3230 const struct nls_table *nls_codepage, int remap)
3232 QUERY_INFORMATION_REQ *pSMB;
3233 QUERY_INFORMATION_RSP *pSMBr;
3234 int rc = 0;
3235 int bytes_returned;
3236 int name_len;
3238 cFYI(1, ("In SMBQPath path %s", searchName));
3239 QInfRetry:
3240 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3241 (void **) &pSMBr);
3242 if (rc)
3243 return rc;
3245 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3246 name_len =
3247 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3248 PATH_MAX, nls_codepage, remap);
3249 name_len++; /* trailing null */
3250 name_len *= 2;
3251 } else {
3252 name_len = strnlen(searchName, PATH_MAX);
3253 name_len++; /* trailing null */
3254 strncpy(pSMB->FileName, searchName, name_len);
3256 pSMB->BufferFormat = 0x04;
3257 name_len++; /* account for buffer type byte */
3258 pSMB->hdr.smb_buf_length += (__u16) name_len;
3259 pSMB->ByteCount = cpu_to_le16(name_len);
3261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3263 if (rc) {
3264 cFYI(1, ("Send error in QueryInfo = %d", rc));
3265 } else if (pFinfo) {
3266 struct timespec ts;
3267 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3269 /* decode response */
3270 /* BB FIXME - add time zone adjustment BB */
3271 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3272 ts.tv_nsec = 0;
3273 ts.tv_sec = time;
3274 /* decode time fields */
3275 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3276 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3277 pFinfo->LastAccessTime = 0;
3278 pFinfo->AllocationSize =
3279 cpu_to_le64(le32_to_cpu(pSMBr->size));
3280 pFinfo->EndOfFile = pFinfo->AllocationSize;
3281 pFinfo->Attributes =
3282 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3283 } else
3284 rc = -EIO; /* bad buffer passed in */
3286 cifs_buf_release(pSMB);
3288 if (rc == -EAGAIN)
3289 goto QInfRetry;
3291 return rc;
3298 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3299 const unsigned char *searchName,
3300 FILE_ALL_INFO *pFindData,
3301 int legacy /* old style infolevel */,
3302 const struct nls_table *nls_codepage, int remap)
3304 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3305 TRANSACTION2_QPI_REQ *pSMB = NULL;
3306 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3307 int rc = 0;
3308 int bytes_returned;
3309 int name_len;
3310 __u16 params, byte_count;
3312 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3313 QPathInfoRetry:
3314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3315 (void **) &pSMBr);
3316 if (rc)
3317 return rc;
3319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3320 name_len =
3321 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3322 PATH_MAX, nls_codepage, remap);
3323 name_len++; /* trailing null */
3324 name_len *= 2;
3325 } else { /* BB improve the check for buffer overruns BB */
3326 name_len = strnlen(searchName, PATH_MAX);
3327 name_len++; /* trailing null */
3328 strncpy(pSMB->FileName, searchName, name_len);
3331 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3332 pSMB->TotalDataCount = 0;
3333 pSMB->MaxParameterCount = cpu_to_le16(2);
3334 /* BB find exact max SMB PDU from sess structure BB */
3335 pSMB->MaxDataCount = cpu_to_le16(4000);
3336 pSMB->MaxSetupCount = 0;
3337 pSMB->Reserved = 0;
3338 pSMB->Flags = 0;
3339 pSMB->Timeout = 0;
3340 pSMB->Reserved2 = 0;
3341 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3342 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3343 pSMB->DataCount = 0;
3344 pSMB->DataOffset = 0;
3345 pSMB->SetupCount = 1;
3346 pSMB->Reserved3 = 0;
3347 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3348 byte_count = params + 1 /* pad */ ;
3349 pSMB->TotalParameterCount = cpu_to_le16(params);
3350 pSMB->ParameterCount = pSMB->TotalParameterCount;
3351 if (legacy)
3352 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3353 else
3354 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3355 pSMB->Reserved4 = 0;
3356 pSMB->hdr.smb_buf_length += byte_count;
3357 pSMB->ByteCount = cpu_to_le16(byte_count);
3359 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3360 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3361 if (rc) {
3362 cFYI(1, ("Send error in QPathInfo = %d", rc));
3363 } else { /* decode response */
3364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3366 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3367 rc = -EIO;
3368 else if (!legacy && (pSMBr->ByteCount < 40))
3369 rc = -EIO; /* bad smb */
3370 else if (legacy && (pSMBr->ByteCount < 24))
3371 rc = -EIO; /* 24 or 26 expected but we do not read
3372 last field */
3373 else if (pFindData) {
3374 int size;
3375 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3377 /* On legacy responses we do not read the last field,
3378 EAsize, fortunately since it varies by subdialect and
3379 also note it differs on Set vs. Get, ie two bytes or 4
3380 bytes depending but we don't care here */
3381 if (legacy)
3382 size = sizeof(FILE_INFO_STANDARD);
3383 else
3384 size = sizeof(FILE_ALL_INFO);
3385 memcpy((char *) pFindData,
3386 (char *) &pSMBr->hdr.Protocol +
3387 data_offset, size);
3388 } else
3389 rc = -ENOMEM;
3391 cifs_buf_release(pSMB);
3392 if (rc == -EAGAIN)
3393 goto QPathInfoRetry;
3395 return rc;
3399 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3400 const unsigned char *searchName,
3401 FILE_UNIX_BASIC_INFO *pFindData,
3402 const struct nls_table *nls_codepage, int remap)
3404 /* SMB_QUERY_FILE_UNIX_BASIC */
3405 TRANSACTION2_QPI_REQ *pSMB = NULL;
3406 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3407 int rc = 0;
3408 int bytes_returned = 0;
3409 int name_len;
3410 __u16 params, byte_count;
3412 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3413 UnixQPathInfoRetry:
3414 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3415 (void **) &pSMBr);
3416 if (rc)
3417 return rc;
3419 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3420 name_len =
3421 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3422 PATH_MAX, nls_codepage, remap);
3423 name_len++; /* trailing null */
3424 name_len *= 2;
3425 } else { /* BB improve the check for buffer overruns BB */
3426 name_len = strnlen(searchName, PATH_MAX);
3427 name_len++; /* trailing null */
3428 strncpy(pSMB->FileName, searchName, name_len);
3431 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3432 pSMB->TotalDataCount = 0;
3433 pSMB->MaxParameterCount = cpu_to_le16(2);
3434 /* BB find exact max SMB PDU from sess structure BB */
3435 pSMB->MaxDataCount = cpu_to_le16(4000);
3436 pSMB->MaxSetupCount = 0;
3437 pSMB->Reserved = 0;
3438 pSMB->Flags = 0;
3439 pSMB->Timeout = 0;
3440 pSMB->Reserved2 = 0;
3441 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3442 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3443 pSMB->DataCount = 0;
3444 pSMB->DataOffset = 0;
3445 pSMB->SetupCount = 1;
3446 pSMB->Reserved3 = 0;
3447 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3448 byte_count = params + 1 /* pad */ ;
3449 pSMB->TotalParameterCount = cpu_to_le16(params);
3450 pSMB->ParameterCount = pSMB->TotalParameterCount;
3451 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3452 pSMB->Reserved4 = 0;
3453 pSMB->hdr.smb_buf_length += byte_count;
3454 pSMB->ByteCount = cpu_to_le16(byte_count);
3456 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3457 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3458 if (rc) {
3459 cFYI(1, ("Send error in QPathInfo = %d", rc));
3460 } else { /* decode response */
3461 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3463 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3464 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3465 "Unix Extensions can be disabled on mount "
3466 "by specifying the nosfu mount option."));
3467 rc = -EIO; /* bad smb */
3468 } else {
3469 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3470 memcpy((char *) pFindData,
3471 (char *) &pSMBr->hdr.Protocol +
3472 data_offset,
3473 sizeof(FILE_UNIX_BASIC_INFO));
3476 cifs_buf_release(pSMB);
3477 if (rc == -EAGAIN)
3478 goto UnixQPathInfoRetry;
3480 return rc;
3483 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3485 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3486 const char *searchName,
3487 const struct nls_table *nls_codepage,
3488 __u16 *pnetfid,
3489 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3491 /* level 257 SMB_ */
3492 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3493 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3494 T2_FFIRST_RSP_PARMS *parms;
3495 int rc = 0;
3496 int bytes_returned = 0;
3497 int name_len;
3498 __u16 params, byte_count;
3500 cFYI(1, ("In FindFirst for %s", searchName));
3502 findFirstRetry:
3503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3504 (void **) &pSMBr);
3505 if (rc)
3506 return rc;
3508 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3509 name_len =
3510 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3511 PATH_MAX, nls_codepage, remap);
3512 /* We can not add the asterik earlier in case
3513 it got remapped to 0xF03A as if it were part of the
3514 directory name instead of a wildcard */
3515 name_len *= 2;
3516 pSMB->FileName[name_len] = dirsep;
3517 pSMB->FileName[name_len+1] = 0;
3518 pSMB->FileName[name_len+2] = '*';
3519 pSMB->FileName[name_len+3] = 0;
3520 name_len += 4; /* now the trailing null */
3521 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3522 pSMB->FileName[name_len+1] = 0;
3523 name_len += 2;
3524 } else { /* BB add check for overrun of SMB buf BB */
3525 name_len = strnlen(searchName, PATH_MAX);
3526 /* BB fix here and in unicode clause above ie
3527 if (name_len > buffersize-header)
3528 free buffer exit; BB */
3529 strncpy(pSMB->FileName, searchName, name_len);
3530 pSMB->FileName[name_len] = dirsep;
3531 pSMB->FileName[name_len+1] = '*';
3532 pSMB->FileName[name_len+2] = 0;
3533 name_len += 3;
3536 params = 12 + name_len /* includes null */ ;
3537 pSMB->TotalDataCount = 0; /* no EAs */
3538 pSMB->MaxParameterCount = cpu_to_le16(10);
3539 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3540 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3541 pSMB->MaxSetupCount = 0;
3542 pSMB->Reserved = 0;
3543 pSMB->Flags = 0;
3544 pSMB->Timeout = 0;
3545 pSMB->Reserved2 = 0;
3546 byte_count = params + 1 /* pad */ ;
3547 pSMB->TotalParameterCount = cpu_to_le16(params);
3548 pSMB->ParameterCount = pSMB->TotalParameterCount;
3549 pSMB->ParameterOffset = cpu_to_le16(
3550 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3551 - 4);
3552 pSMB->DataCount = 0;
3553 pSMB->DataOffset = 0;
3554 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3555 pSMB->Reserved3 = 0;
3556 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3557 pSMB->SearchAttributes =
3558 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3559 ATTR_DIRECTORY);
3560 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3561 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3562 CIFS_SEARCH_RETURN_RESUME);
3563 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3565 /* BB what should we set StorageType to? Does it matter? BB */
3566 pSMB->SearchStorageType = 0;
3567 pSMB->hdr.smb_buf_length += byte_count;
3568 pSMB->ByteCount = cpu_to_le16(byte_count);
3570 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3571 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3572 cifs_stats_inc(&tcon->num_ffirst);
3574 if (rc) {/* BB add logic to retry regular search if Unix search
3575 rejected unexpectedly by server */
3576 /* BB Add code to handle unsupported level rc */
3577 cFYI(1, ("Error in FindFirst = %d", rc));
3579 cifs_buf_release(pSMB);
3581 /* BB eventually could optimize out free and realloc of buf */
3582 /* for this case */
3583 if (rc == -EAGAIN)
3584 goto findFirstRetry;
3585 } else { /* decode response */
3586 /* BB remember to free buffer if error BB */
3587 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3588 if (rc == 0) {
3589 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3590 psrch_inf->unicode = true;
3591 else
3592 psrch_inf->unicode = false;
3594 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3595 psrch_inf->smallBuf = 0;
3596 psrch_inf->srch_entries_start =
3597 (char *) &pSMBr->hdr.Protocol +
3598 le16_to_cpu(pSMBr->t2.DataOffset);
3599 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3600 le16_to_cpu(pSMBr->t2.ParameterOffset));
3602 if (parms->EndofSearch)
3603 psrch_inf->endOfSearch = true;
3604 else
3605 psrch_inf->endOfSearch = false;
3607 psrch_inf->entries_in_buffer =
3608 le16_to_cpu(parms->SearchCount);
3609 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3610 psrch_inf->entries_in_buffer;
3611 *pnetfid = parms->SearchHandle;
3612 } else {
3613 cifs_buf_release(pSMB);
3617 return rc;
3620 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3621 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3623 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3624 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3625 T2_FNEXT_RSP_PARMS *parms;
3626 char *response_data;
3627 int rc = 0;
3628 int bytes_returned, name_len;
3629 __u16 params, byte_count;
3631 cFYI(1, ("In FindNext"));
3633 if (psrch_inf->endOfSearch)
3634 return -ENOENT;
3636 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3637 (void **) &pSMBr);
3638 if (rc)
3639 return rc;
3641 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3642 byte_count = 0;
3643 pSMB->TotalDataCount = 0; /* no EAs */
3644 pSMB->MaxParameterCount = cpu_to_le16(8);
3645 pSMB->MaxDataCount =
3646 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3647 0xFFFFFF00);
3648 pSMB->MaxSetupCount = 0;
3649 pSMB->Reserved = 0;
3650 pSMB->Flags = 0;
3651 pSMB->Timeout = 0;
3652 pSMB->Reserved2 = 0;
3653 pSMB->ParameterOffset = cpu_to_le16(
3654 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3655 pSMB->DataCount = 0;
3656 pSMB->DataOffset = 0;
3657 pSMB->SetupCount = 1;
3658 pSMB->Reserved3 = 0;
3659 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3660 pSMB->SearchHandle = searchHandle; /* always kept as le */
3661 pSMB->SearchCount =
3662 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3663 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3664 pSMB->ResumeKey = psrch_inf->resume_key;
3665 pSMB->SearchFlags =
3666 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3668 name_len = psrch_inf->resume_name_len;
3669 params += name_len;
3670 if (name_len < PATH_MAX) {
3671 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3672 byte_count += name_len;
3673 /* 14 byte parm len above enough for 2 byte null terminator */
3674 pSMB->ResumeFileName[name_len] = 0;
3675 pSMB->ResumeFileName[name_len+1] = 0;
3676 } else {
3677 rc = -EINVAL;
3678 goto FNext2_err_exit;
3680 byte_count = params + 1 /* pad */ ;
3681 pSMB->TotalParameterCount = cpu_to_le16(params);
3682 pSMB->ParameterCount = pSMB->TotalParameterCount;
3683 pSMB->hdr.smb_buf_length += byte_count;
3684 pSMB->ByteCount = cpu_to_le16(byte_count);
3686 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3687 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3688 cifs_stats_inc(&tcon->num_fnext);
3689 if (rc) {
3690 if (rc == -EBADF) {
3691 psrch_inf->endOfSearch = true;
3692 cifs_buf_release(pSMB);
3693 rc = 0; /* search probably was closed at end of search*/
3694 } else
3695 cFYI(1, ("FindNext returned = %d", rc));
3696 } else { /* decode response */
3697 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3699 if (rc == 0) {
3700 /* BB fixme add lock for file (srch_info) struct here */
3701 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3702 psrch_inf->unicode = true;
3703 else
3704 psrch_inf->unicode = false;
3705 response_data = (char *) &pSMBr->hdr.Protocol +
3706 le16_to_cpu(pSMBr->t2.ParameterOffset);
3707 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3708 response_data = (char *)&pSMBr->hdr.Protocol +
3709 le16_to_cpu(pSMBr->t2.DataOffset);
3710 if (psrch_inf->smallBuf)
3711 cifs_small_buf_release(
3712 psrch_inf->ntwrk_buf_start);
3713 else
3714 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3715 psrch_inf->srch_entries_start = response_data;
3716 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3717 psrch_inf->smallBuf = 0;
3718 if (parms->EndofSearch)
3719 psrch_inf->endOfSearch = true;
3720 else
3721 psrch_inf->endOfSearch = false;
3722 psrch_inf->entries_in_buffer =
3723 le16_to_cpu(parms->SearchCount);
3724 psrch_inf->index_of_last_entry +=
3725 psrch_inf->entries_in_buffer;
3726 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3727 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3729 /* BB fixme add unlock here */
3734 /* BB On error, should we leave previous search buf (and count and
3735 last entry fields) intact or free the previous one? */
3737 /* Note: On -EAGAIN error only caller can retry on handle based calls
3738 since file handle passed in no longer valid */
3739 FNext2_err_exit:
3740 if (rc != 0)
3741 cifs_buf_release(pSMB);
3742 return rc;
3746 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3747 const __u16 searchHandle)
3749 int rc = 0;
3750 FINDCLOSE_REQ *pSMB = NULL;
3752 cFYI(1, ("In CIFSSMBFindClose"));
3753 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3755 /* no sense returning error if session restarted
3756 as file handle has been closed */
3757 if (rc == -EAGAIN)
3758 return 0;
3759 if (rc)
3760 return rc;
3762 pSMB->FileID = searchHandle;
3763 pSMB->ByteCount = 0;
3764 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3765 if (rc)
3766 cERROR(1, ("Send error in FindClose = %d", rc));
3768 cifs_stats_inc(&tcon->num_fclose);
3770 /* Since session is dead, search handle closed on server already */
3771 if (rc == -EAGAIN)
3772 rc = 0;
3774 return rc;
3778 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3779 const unsigned char *searchName,
3780 __u64 *inode_number,
3781 const struct nls_table *nls_codepage, int remap)
3783 int rc = 0;
3784 TRANSACTION2_QPI_REQ *pSMB = NULL;
3785 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3786 int name_len, bytes_returned;
3787 __u16 params, byte_count;
3789 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3790 if (tcon == NULL)
3791 return -ENODEV;
3793 GetInodeNumberRetry:
3794 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3795 (void **) &pSMBr);
3796 if (rc)
3797 return rc;
3799 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3800 name_len =
3801 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3802 PATH_MAX, nls_codepage, remap);
3803 name_len++; /* trailing null */
3804 name_len *= 2;
3805 } else { /* BB improve the check for buffer overruns BB */
3806 name_len = strnlen(searchName, PATH_MAX);
3807 name_len++; /* trailing null */
3808 strncpy(pSMB->FileName, searchName, name_len);
3811 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3812 pSMB->TotalDataCount = 0;
3813 pSMB->MaxParameterCount = cpu_to_le16(2);
3814 /* BB find exact max data count below from sess structure BB */
3815 pSMB->MaxDataCount = cpu_to_le16(4000);
3816 pSMB->MaxSetupCount = 0;
3817 pSMB->Reserved = 0;
3818 pSMB->Flags = 0;
3819 pSMB->Timeout = 0;
3820 pSMB->Reserved2 = 0;
3821 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3822 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3823 pSMB->DataCount = 0;
3824 pSMB->DataOffset = 0;
3825 pSMB->SetupCount = 1;
3826 pSMB->Reserved3 = 0;
3827 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3828 byte_count = params + 1 /* pad */ ;
3829 pSMB->TotalParameterCount = cpu_to_le16(params);
3830 pSMB->ParameterCount = pSMB->TotalParameterCount;
3831 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3832 pSMB->Reserved4 = 0;
3833 pSMB->hdr.smb_buf_length += byte_count;
3834 pSMB->ByteCount = cpu_to_le16(byte_count);
3836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3837 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3838 if (rc) {
3839 cFYI(1, ("error %d in QueryInternalInfo", rc));
3840 } else {
3841 /* decode response */
3842 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3843 if (rc || (pSMBr->ByteCount < 2))
3844 /* BB also check enough total bytes returned */
3845 /* If rc should we check for EOPNOSUPP and
3846 disable the srvino flag? or in caller? */
3847 rc = -EIO; /* bad smb */
3848 else {
3849 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3850 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3851 struct file_internal_info *pfinfo;
3852 /* BB Do we need a cast or hash here ? */
3853 if (count < 8) {
3854 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3855 rc = -EIO;
3856 goto GetInodeNumOut;
3858 pfinfo = (struct file_internal_info *)
3859 (data_offset + (char *) &pSMBr->hdr.Protocol);
3860 *inode_number = pfinfo->UniqueId;
3863 GetInodeNumOut:
3864 cifs_buf_release(pSMB);
3865 if (rc == -EAGAIN)
3866 goto GetInodeNumberRetry;
3867 return rc;
3871 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3872 const unsigned char *searchName,
3873 struct dfs_info3_param **target_nodes,
3874 unsigned int *num_of_nodes,
3875 const struct nls_table *nls_codepage, int remap)
3877 /* TRANS2_GET_DFS_REFERRAL */
3878 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3879 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3880 struct dfs_referral_level_3 *referrals = NULL;
3881 int rc = 0;
3882 int bytes_returned;
3883 int name_len;
3884 unsigned int i;
3885 char *temp;
3886 __u16 params, byte_count;
3887 *num_of_nodes = 0;
3888 *target_nodes = NULL;
3890 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3891 if (ses == NULL)
3892 return -ENODEV;
3893 getDFSRetry:
3894 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3895 (void **) &pSMBr);
3896 if (rc)
3897 return rc;
3899 /* server pointer checked in called function,
3900 but should never be null here anyway */
3901 pSMB->hdr.Mid = GetNextMid(ses->server);
3902 pSMB->hdr.Tid = ses->ipc_tid;
3903 pSMB->hdr.Uid = ses->Suid;
3904 if (ses->capabilities & CAP_STATUS32)
3905 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3906 if (ses->capabilities & CAP_DFS)
3907 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3909 if (ses->capabilities & CAP_UNICODE) {
3910 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3911 name_len =
3912 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3913 searchName, PATH_MAX, nls_codepage, remap);
3914 name_len++; /* trailing null */
3915 name_len *= 2;
3916 } else { /* BB improve the check for buffer overruns BB */
3917 name_len = strnlen(searchName, PATH_MAX);
3918 name_len++; /* trailing null */
3919 strncpy(pSMB->RequestFileName, searchName, name_len);
3922 if (ses->server) {
3923 if (ses->server->secMode &
3924 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3925 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3928 pSMB->hdr.Uid = ses->Suid;
3930 params = 2 /* level */ + name_len /*includes null */ ;
3931 pSMB->TotalDataCount = 0;
3932 pSMB->DataCount = 0;
3933 pSMB->DataOffset = 0;
3934 pSMB->MaxParameterCount = 0;
3935 /* BB find exact max SMB PDU from sess structure BB */
3936 pSMB->MaxDataCount = cpu_to_le16(4000);
3937 pSMB->MaxSetupCount = 0;
3938 pSMB->Reserved = 0;
3939 pSMB->Flags = 0;
3940 pSMB->Timeout = 0;
3941 pSMB->Reserved2 = 0;
3942 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3943 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3944 pSMB->SetupCount = 1;
3945 pSMB->Reserved3 = 0;
3946 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3947 byte_count = params + 3 /* pad */ ;
3948 pSMB->ParameterCount = cpu_to_le16(params);
3949 pSMB->TotalParameterCount = pSMB->ParameterCount;
3950 pSMB->MaxReferralLevel = cpu_to_le16(3);
3951 pSMB->hdr.smb_buf_length += byte_count;
3952 pSMB->ByteCount = cpu_to_le16(byte_count);
3954 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3956 if (rc) {
3957 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3958 goto GetDFSRefExit;
3960 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3962 /* BB Also check if enough total bytes returned? */
3963 if (rc || (pSMBr->ByteCount < 17))
3964 rc = -EIO; /* bad smb */
3965 else {
3966 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3967 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3969 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
3970 pSMBr->ByteCount, data_offset));
3971 referrals =
3972 (struct dfs_referral_level_3 *)
3973 (8 /* sizeof start of data block */ +
3974 data_offset +
3975 (char *) &pSMBr->hdr.Protocol);
3976 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
3977 "for referral one refer size: 0x%x srv "
3978 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3979 le16_to_cpu(pSMBr->NumberOfReferrals),
3980 le16_to_cpu(pSMBr->DFSFlags),
3981 le16_to_cpu(referrals->ReferralSize),
3982 le16_to_cpu(referrals->ServerType),
3983 le16_to_cpu(referrals->ReferralFlags),
3984 le16_to_cpu(referrals->TimeToLive)));
3985 /* BB This field is actually two bytes in from start of
3986 data block so we could do safety check that DataBlock
3987 begins at address of pSMBr->NumberOfReferrals */
3988 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3990 /* BB Fix below so can return more than one referral */
3991 if (*num_of_nodes > 1)
3992 *num_of_nodes = 1;
3994 /* get the length of the strings describing refs */
3995 name_len = 0;
3996 for (i = 0; i < *num_of_nodes; i++) {
3997 /* make sure that DfsPathOffset not past end */
3998 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3999 if (offset > data_count) {
4000 /* if invalid referral, stop here and do
4001 not try to copy any more */
4002 *num_of_nodes = i;
4003 break;
4005 temp = ((char *)referrals) + offset;
4007 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4008 name_len += UniStrnlen((wchar_t *)temp,
4009 data_count);
4010 } else {
4011 name_len += strnlen(temp, data_count);
4013 referrals++;
4014 /* BB add check that referral pointer does
4015 not fall off end PDU */
4017 /* BB add check for name_len bigger than bcc */
4018 *target_nodes =
4019 kmalloc(name_len+1+(*num_of_nodes),
4020 GFP_KERNEL);
4021 if (*target_nodes == NULL) {
4022 rc = -ENOMEM;
4023 goto GetDFSRefExit;
4026 referrals = (struct dfs_referral_level_3 *)
4027 (8 /* sizeof data hdr */ + data_offset +
4028 (char *) &pSMBr->hdr.Protocol);
4030 for (i = 0; i < *num_of_nodes; i++) {
4031 temp = ((char *)referrals) +
4032 le16_to_cpu(referrals->DfsPathOffset);
4033 /* BB update target_uncs pointers */
4034 referrals++;
4037 GetDFSRefExit:
4038 if (pSMB)
4039 cifs_buf_release(pSMB);
4041 if (rc == -EAGAIN)
4042 goto getDFSRetry;
4044 return rc;
4047 /* Query File System Info such as free space to old servers such as Win 9x */
4049 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4051 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4052 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4053 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4054 FILE_SYSTEM_ALLOC_INFO *response_data;
4055 int rc = 0;
4056 int bytes_returned = 0;
4057 __u16 params, byte_count;
4059 cFYI(1, ("OldQFSInfo"));
4060 oldQFSInfoRetry:
4061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4062 (void **) &pSMBr);
4063 if (rc)
4064 return rc;
4066 params = 2; /* level */
4067 pSMB->TotalDataCount = 0;
4068 pSMB->MaxParameterCount = cpu_to_le16(2);
4069 pSMB->MaxDataCount = cpu_to_le16(1000);
4070 pSMB->MaxSetupCount = 0;
4071 pSMB->Reserved = 0;
4072 pSMB->Flags = 0;
4073 pSMB->Timeout = 0;
4074 pSMB->Reserved2 = 0;
4075 byte_count = params + 1 /* pad */ ;
4076 pSMB->TotalParameterCount = cpu_to_le16(params);
4077 pSMB->ParameterCount = pSMB->TotalParameterCount;
4078 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4079 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4080 pSMB->DataCount = 0;
4081 pSMB->DataOffset = 0;
4082 pSMB->SetupCount = 1;
4083 pSMB->Reserved3 = 0;
4084 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4085 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4086 pSMB->hdr.smb_buf_length += byte_count;
4087 pSMB->ByteCount = cpu_to_le16(byte_count);
4089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091 if (rc) {
4092 cFYI(1, ("Send error in QFSInfo = %d", rc));
4093 } else { /* decode response */
4094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4096 if (rc || (pSMBr->ByteCount < 18))
4097 rc = -EIO; /* bad smb */
4098 else {
4099 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4100 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4101 pSMBr->ByteCount, data_offset));
4103 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4104 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4105 FSData->f_bsize =
4106 le16_to_cpu(response_data->BytesPerSector) *
4107 le32_to_cpu(response_data->
4108 SectorsPerAllocationUnit);
4109 FSData->f_blocks =
4110 le32_to_cpu(response_data->TotalAllocationUnits);
4111 FSData->f_bfree = FSData->f_bavail =
4112 le32_to_cpu(response_data->FreeAllocationUnits);
4113 cFYI(1,
4114 ("Blocks: %lld Free: %lld Block size %ld",
4115 (unsigned long long)FSData->f_blocks,
4116 (unsigned long long)FSData->f_bfree,
4117 FSData->f_bsize));
4120 cifs_buf_release(pSMB);
4122 if (rc == -EAGAIN)
4123 goto oldQFSInfoRetry;
4125 return rc;
4129 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4131 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4132 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4133 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4134 FILE_SYSTEM_INFO *response_data;
4135 int rc = 0;
4136 int bytes_returned = 0;
4137 __u16 params, byte_count;
4139 cFYI(1, ("In QFSInfo"));
4140 QFSInfoRetry:
4141 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4142 (void **) &pSMBr);
4143 if (rc)
4144 return rc;
4146 params = 2; /* level */
4147 pSMB->TotalDataCount = 0;
4148 pSMB->MaxParameterCount = cpu_to_le16(2);
4149 pSMB->MaxDataCount = cpu_to_le16(1000);
4150 pSMB->MaxSetupCount = 0;
4151 pSMB->Reserved = 0;
4152 pSMB->Flags = 0;
4153 pSMB->Timeout = 0;
4154 pSMB->Reserved2 = 0;
4155 byte_count = params + 1 /* pad */ ;
4156 pSMB->TotalParameterCount = cpu_to_le16(params);
4157 pSMB->ParameterCount = pSMB->TotalParameterCount;
4158 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4159 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4160 pSMB->DataCount = 0;
4161 pSMB->DataOffset = 0;
4162 pSMB->SetupCount = 1;
4163 pSMB->Reserved3 = 0;
4164 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4165 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4166 pSMB->hdr.smb_buf_length += byte_count;
4167 pSMB->ByteCount = cpu_to_le16(byte_count);
4169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171 if (rc) {
4172 cFYI(1, ("Send error in QFSInfo = %d", rc));
4173 } else { /* decode response */
4174 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4176 if (rc || (pSMBr->ByteCount < 24))
4177 rc = -EIO; /* bad smb */
4178 else {
4179 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4181 response_data =
4182 (FILE_SYSTEM_INFO
4183 *) (((char *) &pSMBr->hdr.Protocol) +
4184 data_offset);
4185 FSData->f_bsize =
4186 le32_to_cpu(response_data->BytesPerSector) *
4187 le32_to_cpu(response_data->
4188 SectorsPerAllocationUnit);
4189 FSData->f_blocks =
4190 le64_to_cpu(response_data->TotalAllocationUnits);
4191 FSData->f_bfree = FSData->f_bavail =
4192 le64_to_cpu(response_data->FreeAllocationUnits);
4193 cFYI(1,
4194 ("Blocks: %lld Free: %lld Block size %ld",
4195 (unsigned long long)FSData->f_blocks,
4196 (unsigned long long)FSData->f_bfree,
4197 FSData->f_bsize));
4200 cifs_buf_release(pSMB);
4202 if (rc == -EAGAIN)
4203 goto QFSInfoRetry;
4205 return rc;
4209 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4211 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4212 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4213 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4214 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4215 int rc = 0;
4216 int bytes_returned = 0;
4217 __u16 params, byte_count;
4219 cFYI(1, ("In QFSAttributeInfo"));
4220 QFSAttributeRetry:
4221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4222 (void **) &pSMBr);
4223 if (rc)
4224 return rc;
4226 params = 2; /* level */
4227 pSMB->TotalDataCount = 0;
4228 pSMB->MaxParameterCount = cpu_to_le16(2);
4229 /* BB find exact max SMB PDU from sess structure BB */
4230 pSMB->MaxDataCount = cpu_to_le16(1000);
4231 pSMB->MaxSetupCount = 0;
4232 pSMB->Reserved = 0;
4233 pSMB->Flags = 0;
4234 pSMB->Timeout = 0;
4235 pSMB->Reserved2 = 0;
4236 byte_count = params + 1 /* pad */ ;
4237 pSMB->TotalParameterCount = cpu_to_le16(params);
4238 pSMB->ParameterCount = pSMB->TotalParameterCount;
4239 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4240 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4241 pSMB->DataCount = 0;
4242 pSMB->DataOffset = 0;
4243 pSMB->SetupCount = 1;
4244 pSMB->Reserved3 = 0;
4245 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4246 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4247 pSMB->hdr.smb_buf_length += byte_count;
4248 pSMB->ByteCount = cpu_to_le16(byte_count);
4250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4251 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4252 if (rc) {
4253 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4254 } else { /* decode response */
4255 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4257 if (rc || (pSMBr->ByteCount < 13)) {
4258 /* BB also check if enough bytes returned */
4259 rc = -EIO; /* bad smb */
4260 } else {
4261 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4262 response_data =
4263 (FILE_SYSTEM_ATTRIBUTE_INFO
4264 *) (((char *) &pSMBr->hdr.Protocol) +
4265 data_offset);
4266 memcpy(&tcon->fsAttrInfo, response_data,
4267 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4270 cifs_buf_release(pSMB);
4272 if (rc == -EAGAIN)
4273 goto QFSAttributeRetry;
4275 return rc;
4279 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4281 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4282 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4283 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4284 FILE_SYSTEM_DEVICE_INFO *response_data;
4285 int rc = 0;
4286 int bytes_returned = 0;
4287 __u16 params, byte_count;
4289 cFYI(1, ("In QFSDeviceInfo"));
4290 QFSDeviceRetry:
4291 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4292 (void **) &pSMBr);
4293 if (rc)
4294 return rc;
4296 params = 2; /* level */
4297 pSMB->TotalDataCount = 0;
4298 pSMB->MaxParameterCount = cpu_to_le16(2);
4299 /* BB find exact max SMB PDU from sess structure BB */
4300 pSMB->MaxDataCount = cpu_to_le16(1000);
4301 pSMB->MaxSetupCount = 0;
4302 pSMB->Reserved = 0;
4303 pSMB->Flags = 0;
4304 pSMB->Timeout = 0;
4305 pSMB->Reserved2 = 0;
4306 byte_count = params + 1 /* pad */ ;
4307 pSMB->TotalParameterCount = cpu_to_le16(params);
4308 pSMB->ParameterCount = pSMB->TotalParameterCount;
4309 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4310 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4312 pSMB->DataCount = 0;
4313 pSMB->DataOffset = 0;
4314 pSMB->SetupCount = 1;
4315 pSMB->Reserved3 = 0;
4316 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4317 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4318 pSMB->hdr.smb_buf_length += byte_count;
4319 pSMB->ByteCount = cpu_to_le16(byte_count);
4321 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4322 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4323 if (rc) {
4324 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4325 } else { /* decode response */
4326 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4328 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4329 rc = -EIO; /* bad smb */
4330 else {
4331 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4332 response_data =
4333 (FILE_SYSTEM_DEVICE_INFO *)
4334 (((char *) &pSMBr->hdr.Protocol) +
4335 data_offset);
4336 memcpy(&tcon->fsDevInfo, response_data,
4337 sizeof(FILE_SYSTEM_DEVICE_INFO));
4340 cifs_buf_release(pSMB);
4342 if (rc == -EAGAIN)
4343 goto QFSDeviceRetry;
4345 return rc;
4349 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4351 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4352 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4353 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4354 FILE_SYSTEM_UNIX_INFO *response_data;
4355 int rc = 0;
4356 int bytes_returned = 0;
4357 __u16 params, byte_count;
4359 cFYI(1, ("In QFSUnixInfo"));
4360 QFSUnixRetry:
4361 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4362 (void **) &pSMBr);
4363 if (rc)
4364 return rc;
4366 params = 2; /* level */
4367 pSMB->TotalDataCount = 0;
4368 pSMB->DataCount = 0;
4369 pSMB->DataOffset = 0;
4370 pSMB->MaxParameterCount = cpu_to_le16(2);
4371 /* BB find exact max SMB PDU from sess structure BB */
4372 pSMB->MaxDataCount = cpu_to_le16(100);
4373 pSMB->MaxSetupCount = 0;
4374 pSMB->Reserved = 0;
4375 pSMB->Flags = 0;
4376 pSMB->Timeout = 0;
4377 pSMB->Reserved2 = 0;
4378 byte_count = params + 1 /* pad */ ;
4379 pSMB->ParameterCount = cpu_to_le16(params);
4380 pSMB->TotalParameterCount = pSMB->ParameterCount;
4381 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4382 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4383 pSMB->SetupCount = 1;
4384 pSMB->Reserved3 = 0;
4385 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4386 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4387 pSMB->hdr.smb_buf_length += byte_count;
4388 pSMB->ByteCount = cpu_to_le16(byte_count);
4390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4391 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4392 if (rc) {
4393 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4394 } else { /* decode response */
4395 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4397 if (rc || (pSMBr->ByteCount < 13)) {
4398 rc = -EIO; /* bad smb */
4399 } else {
4400 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4401 response_data =
4402 (FILE_SYSTEM_UNIX_INFO
4403 *) (((char *) &pSMBr->hdr.Protocol) +
4404 data_offset);
4405 memcpy(&tcon->fsUnixInfo, response_data,
4406 sizeof(FILE_SYSTEM_UNIX_INFO));
4409 cifs_buf_release(pSMB);
4411 if (rc == -EAGAIN)
4412 goto QFSUnixRetry;
4415 return rc;
4419 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4421 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4422 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4423 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4424 int rc = 0;
4425 int bytes_returned = 0;
4426 __u16 params, param_offset, offset, byte_count;
4428 cFYI(1, ("In SETFSUnixInfo"));
4429 SETFSUnixRetry:
4430 /* BB switch to small buf init to save memory */
4431 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4432 (void **) &pSMBr);
4433 if (rc)
4434 return rc;
4436 params = 4; /* 2 bytes zero followed by info level. */
4437 pSMB->MaxSetupCount = 0;
4438 pSMB->Reserved = 0;
4439 pSMB->Flags = 0;
4440 pSMB->Timeout = 0;
4441 pSMB->Reserved2 = 0;
4442 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4443 - 4;
4444 offset = param_offset + params;
4446 pSMB->MaxParameterCount = cpu_to_le16(4);
4447 /* BB find exact max SMB PDU from sess structure BB */
4448 pSMB->MaxDataCount = cpu_to_le16(100);
4449 pSMB->SetupCount = 1;
4450 pSMB->Reserved3 = 0;
4451 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4452 byte_count = 1 /* pad */ + params + 12;
4454 pSMB->DataCount = cpu_to_le16(12);
4455 pSMB->ParameterCount = cpu_to_le16(params);
4456 pSMB->TotalDataCount = pSMB->DataCount;
4457 pSMB->TotalParameterCount = pSMB->ParameterCount;
4458 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4459 pSMB->DataOffset = cpu_to_le16(offset);
4461 /* Params. */
4462 pSMB->FileNum = 0;
4463 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4465 /* Data. */
4466 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4467 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4468 pSMB->ClientUnixCap = cpu_to_le64(cap);
4470 pSMB->hdr.smb_buf_length += byte_count;
4471 pSMB->ByteCount = cpu_to_le16(byte_count);
4473 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4474 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4475 if (rc) {
4476 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4477 } else { /* decode response */
4478 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4479 if (rc)
4480 rc = -EIO; /* bad smb */
4482 cifs_buf_release(pSMB);
4484 if (rc == -EAGAIN)
4485 goto SETFSUnixRetry;
4487 return rc;
4493 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4494 struct kstatfs *FSData)
4496 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4497 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4498 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4499 FILE_SYSTEM_POSIX_INFO *response_data;
4500 int rc = 0;
4501 int bytes_returned = 0;
4502 __u16 params, byte_count;
4504 cFYI(1, ("In QFSPosixInfo"));
4505 QFSPosixRetry:
4506 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4507 (void **) &pSMBr);
4508 if (rc)
4509 return rc;
4511 params = 2; /* level */
4512 pSMB->TotalDataCount = 0;
4513 pSMB->DataCount = 0;
4514 pSMB->DataOffset = 0;
4515 pSMB->MaxParameterCount = cpu_to_le16(2);
4516 /* BB find exact max SMB PDU from sess structure BB */
4517 pSMB->MaxDataCount = cpu_to_le16(100);
4518 pSMB->MaxSetupCount = 0;
4519 pSMB->Reserved = 0;
4520 pSMB->Flags = 0;
4521 pSMB->Timeout = 0;
4522 pSMB->Reserved2 = 0;
4523 byte_count = params + 1 /* pad */ ;
4524 pSMB->ParameterCount = cpu_to_le16(params);
4525 pSMB->TotalParameterCount = pSMB->ParameterCount;
4526 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4527 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4528 pSMB->SetupCount = 1;
4529 pSMB->Reserved3 = 0;
4530 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4531 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4532 pSMB->hdr.smb_buf_length += byte_count;
4533 pSMB->ByteCount = cpu_to_le16(byte_count);
4535 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4536 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4537 if (rc) {
4538 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4539 } else { /* decode response */
4540 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4542 if (rc || (pSMBr->ByteCount < 13)) {
4543 rc = -EIO; /* bad smb */
4544 } else {
4545 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4546 response_data =
4547 (FILE_SYSTEM_POSIX_INFO
4548 *) (((char *) &pSMBr->hdr.Protocol) +
4549 data_offset);
4550 FSData->f_bsize =
4551 le32_to_cpu(response_data->BlockSize);
4552 FSData->f_blocks =
4553 le64_to_cpu(response_data->TotalBlocks);
4554 FSData->f_bfree =
4555 le64_to_cpu(response_data->BlocksAvail);
4556 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4557 FSData->f_bavail = FSData->f_bfree;
4558 } else {
4559 FSData->f_bavail =
4560 le64_to_cpu(response_data->UserBlocksAvail);
4562 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4563 FSData->f_files =
4564 le64_to_cpu(response_data->TotalFileNodes);
4565 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4566 FSData->f_ffree =
4567 le64_to_cpu(response_data->FreeFileNodes);
4570 cifs_buf_release(pSMB);
4572 if (rc == -EAGAIN)
4573 goto QFSPosixRetry;
4575 return rc;
4579 /* We can not use write of zero bytes trick to
4580 set file size due to need for large file support. Also note that
4581 this SetPathInfo is preferred to SetFileInfo based method in next
4582 routine which is only needed to work around a sharing violation bug
4583 in Samba which this routine can run into */
4586 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4587 __u64 size, bool SetAllocation,
4588 const struct nls_table *nls_codepage, int remap)
4590 struct smb_com_transaction2_spi_req *pSMB = NULL;
4591 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4592 struct file_end_of_file_info *parm_data;
4593 int name_len;
4594 int rc = 0;
4595 int bytes_returned = 0;
4596 __u16 params, byte_count, data_count, param_offset, offset;
4598 cFYI(1, ("In SetEOF"));
4599 SetEOFRetry:
4600 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4601 (void **) &pSMBr);
4602 if (rc)
4603 return rc;
4605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4606 name_len =
4607 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4608 PATH_MAX, nls_codepage, remap);
4609 name_len++; /* trailing null */
4610 name_len *= 2;
4611 } else { /* BB improve the check for buffer overruns BB */
4612 name_len = strnlen(fileName, PATH_MAX);
4613 name_len++; /* trailing null */
4614 strncpy(pSMB->FileName, fileName, name_len);
4616 params = 6 + name_len;
4617 data_count = sizeof(struct file_end_of_file_info);
4618 pSMB->MaxParameterCount = cpu_to_le16(2);
4619 pSMB->MaxDataCount = cpu_to_le16(4100);
4620 pSMB->MaxSetupCount = 0;
4621 pSMB->Reserved = 0;
4622 pSMB->Flags = 0;
4623 pSMB->Timeout = 0;
4624 pSMB->Reserved2 = 0;
4625 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4626 InformationLevel) - 4;
4627 offset = param_offset + params;
4628 if (SetAllocation) {
4629 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4630 pSMB->InformationLevel =
4631 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4632 else
4633 pSMB->InformationLevel =
4634 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4635 } else /* Set File Size */ {
4636 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4637 pSMB->InformationLevel =
4638 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4639 else
4640 pSMB->InformationLevel =
4641 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4644 parm_data =
4645 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4646 offset);
4647 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4648 pSMB->DataOffset = cpu_to_le16(offset);
4649 pSMB->SetupCount = 1;
4650 pSMB->Reserved3 = 0;
4651 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4652 byte_count = 3 /* pad */ + params + data_count;
4653 pSMB->DataCount = cpu_to_le16(data_count);
4654 pSMB->TotalDataCount = pSMB->DataCount;
4655 pSMB->ParameterCount = cpu_to_le16(params);
4656 pSMB->TotalParameterCount = pSMB->ParameterCount;
4657 pSMB->Reserved4 = 0;
4658 pSMB->hdr.smb_buf_length += byte_count;
4659 parm_data->FileSize = cpu_to_le64(size);
4660 pSMB->ByteCount = cpu_to_le16(byte_count);
4661 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4662 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4663 if (rc)
4664 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4666 cifs_buf_release(pSMB);
4668 if (rc == -EAGAIN)
4669 goto SetEOFRetry;
4671 return rc;
4675 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4676 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
4678 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4679 char *data_offset;
4680 struct file_end_of_file_info *parm_data;
4681 int rc = 0;
4682 __u16 params, param_offset, offset, byte_count, count;
4684 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4685 (long long)size));
4686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4688 if (rc)
4689 return rc;
4691 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4692 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4694 params = 6;
4695 pSMB->MaxSetupCount = 0;
4696 pSMB->Reserved = 0;
4697 pSMB->Flags = 0;
4698 pSMB->Timeout = 0;
4699 pSMB->Reserved2 = 0;
4700 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4701 offset = param_offset + params;
4703 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4705 count = sizeof(struct file_end_of_file_info);
4706 pSMB->MaxParameterCount = cpu_to_le16(2);
4707 /* BB find exact max SMB PDU from sess structure BB */
4708 pSMB->MaxDataCount = cpu_to_le16(1000);
4709 pSMB->SetupCount = 1;
4710 pSMB->Reserved3 = 0;
4711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4712 byte_count = 3 /* pad */ + params + count;
4713 pSMB->DataCount = cpu_to_le16(count);
4714 pSMB->ParameterCount = cpu_to_le16(params);
4715 pSMB->TotalDataCount = pSMB->DataCount;
4716 pSMB->TotalParameterCount = pSMB->ParameterCount;
4717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4718 parm_data =
4719 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4720 + offset);
4721 pSMB->DataOffset = cpu_to_le16(offset);
4722 parm_data->FileSize = cpu_to_le64(size);
4723 pSMB->Fid = fid;
4724 if (SetAllocation) {
4725 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4726 pSMB->InformationLevel =
4727 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4728 else
4729 pSMB->InformationLevel =
4730 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4731 } else /* Set File Size */ {
4732 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733 pSMB->InformationLevel =
4734 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4735 else
4736 pSMB->InformationLevel =
4737 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4739 pSMB->Reserved4 = 0;
4740 pSMB->hdr.smb_buf_length += byte_count;
4741 pSMB->ByteCount = cpu_to_le16(byte_count);
4742 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4743 if (rc) {
4744 cFYI(1,
4745 ("Send error in SetFileInfo (SetFileSize) = %d",
4746 rc));
4749 /* Note: On -EAGAIN error only caller can retry on handle based calls
4750 since file handle passed in no longer valid */
4752 return rc;
4755 /* Some legacy servers such as NT4 require that the file times be set on
4756 an open handle, rather than by pathname - this is awkward due to
4757 potential access conflicts on the open, but it is unavoidable for these
4758 old servers since the only other choice is to go from 100 nanosecond DCE
4759 time and resort to the original setpathinfo level which takes the ancient
4760 DOS time format with 2 second granularity */
4762 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4763 const FILE_BASIC_INFO *data, __u16 fid)
4765 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4766 char *data_offset;
4767 int rc = 0;
4768 __u16 params, param_offset, offset, byte_count, count;
4770 cFYI(1, ("Set Times (via SetFileInfo)"));
4771 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4773 if (rc)
4774 return rc;
4776 /* At this point there is no need to override the current pid
4777 with the pid of the opener, but that could change if we someday
4778 use an existing handle (rather than opening one on the fly) */
4779 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4780 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4782 params = 6;
4783 pSMB->MaxSetupCount = 0;
4784 pSMB->Reserved = 0;
4785 pSMB->Flags = 0;
4786 pSMB->Timeout = 0;
4787 pSMB->Reserved2 = 0;
4788 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4789 offset = param_offset + params;
4791 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4793 count = sizeof(FILE_BASIC_INFO);
4794 pSMB->MaxParameterCount = cpu_to_le16(2);
4795 /* BB find max SMB PDU from sess */
4796 pSMB->MaxDataCount = cpu_to_le16(1000);
4797 pSMB->SetupCount = 1;
4798 pSMB->Reserved3 = 0;
4799 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4800 byte_count = 3 /* pad */ + params + count;
4801 pSMB->DataCount = cpu_to_le16(count);
4802 pSMB->ParameterCount = cpu_to_le16(params);
4803 pSMB->TotalDataCount = pSMB->DataCount;
4804 pSMB->TotalParameterCount = pSMB->ParameterCount;
4805 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4806 pSMB->DataOffset = cpu_to_le16(offset);
4807 pSMB->Fid = fid;
4808 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4809 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4810 else
4811 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4812 pSMB->Reserved4 = 0;
4813 pSMB->hdr.smb_buf_length += byte_count;
4814 pSMB->ByteCount = cpu_to_le16(byte_count);
4815 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4816 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4817 if (rc)
4818 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4820 /* Note: On -EAGAIN error only caller can retry on handle based calls
4821 since file handle passed in no longer valid */
4823 return rc;
4828 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4829 const FILE_BASIC_INFO *data,
4830 const struct nls_table *nls_codepage, int remap)
4832 TRANSACTION2_SPI_REQ *pSMB = NULL;
4833 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4834 int name_len;
4835 int rc = 0;
4836 int bytes_returned = 0;
4837 char *data_offset;
4838 __u16 params, param_offset, offset, byte_count, count;
4840 cFYI(1, ("In SetTimes"));
4842 SetTimesRetry:
4843 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4844 (void **) &pSMBr);
4845 if (rc)
4846 return rc;
4848 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4849 name_len =
4850 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4851 PATH_MAX, nls_codepage, remap);
4852 name_len++; /* trailing null */
4853 name_len *= 2;
4854 } else { /* BB improve the check for buffer overruns BB */
4855 name_len = strnlen(fileName, PATH_MAX);
4856 name_len++; /* trailing null */
4857 strncpy(pSMB->FileName, fileName, name_len);
4860 params = 6 + name_len;
4861 count = sizeof(FILE_BASIC_INFO);
4862 pSMB->MaxParameterCount = cpu_to_le16(2);
4863 /* BB find max SMB PDU from sess structure BB */
4864 pSMB->MaxDataCount = cpu_to_le16(1000);
4865 pSMB->MaxSetupCount = 0;
4866 pSMB->Reserved = 0;
4867 pSMB->Flags = 0;
4868 pSMB->Timeout = 0;
4869 pSMB->Reserved2 = 0;
4870 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4871 InformationLevel) - 4;
4872 offset = param_offset + params;
4873 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4874 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4875 pSMB->DataOffset = cpu_to_le16(offset);
4876 pSMB->SetupCount = 1;
4877 pSMB->Reserved3 = 0;
4878 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4879 byte_count = 3 /* pad */ + params + count;
4881 pSMB->DataCount = cpu_to_le16(count);
4882 pSMB->ParameterCount = cpu_to_le16(params);
4883 pSMB->TotalDataCount = pSMB->DataCount;
4884 pSMB->TotalParameterCount = pSMB->ParameterCount;
4885 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4886 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4887 else
4888 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4889 pSMB->Reserved4 = 0;
4890 pSMB->hdr.smb_buf_length += byte_count;
4891 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4892 pSMB->ByteCount = cpu_to_le16(byte_count);
4893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4895 if (rc)
4896 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4898 cifs_buf_release(pSMB);
4900 if (rc == -EAGAIN)
4901 goto SetTimesRetry;
4903 return rc;
4906 /* Can not be used to set time stamps yet (due to old DOS time format) */
4907 /* Can be used to set attributes */
4908 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4909 handling it anyway and NT4 was what we thought it would be needed for
4910 Do not delete it until we prove whether needed for Win9x though */
4912 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4913 __u16 dos_attrs, const struct nls_table *nls_codepage)
4915 SETATTR_REQ *pSMB = NULL;
4916 SETATTR_RSP *pSMBr = NULL;
4917 int rc = 0;
4918 int bytes_returned;
4919 int name_len;
4921 cFYI(1, ("In SetAttrLegacy"));
4923 SetAttrLgcyRetry:
4924 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4925 (void **) &pSMBr);
4926 if (rc)
4927 return rc;
4929 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4930 name_len =
4931 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4932 PATH_MAX, nls_codepage);
4933 name_len++; /* trailing null */
4934 name_len *= 2;
4935 } else { /* BB improve the check for buffer overruns BB */
4936 name_len = strnlen(fileName, PATH_MAX);
4937 name_len++; /* trailing null */
4938 strncpy(pSMB->fileName, fileName, name_len);
4940 pSMB->attr = cpu_to_le16(dos_attrs);
4941 pSMB->BufferFormat = 0x04;
4942 pSMB->hdr.smb_buf_length += name_len + 1;
4943 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4946 if (rc)
4947 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4949 cifs_buf_release(pSMB);
4951 if (rc == -EAGAIN)
4952 goto SetAttrLgcyRetry;
4954 return rc;
4956 #endif /* temporarily unneeded SetAttr legacy function */
4959 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4960 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4961 dev_t device, const struct nls_table *nls_codepage,
4962 int remap)
4964 TRANSACTION2_SPI_REQ *pSMB = NULL;
4965 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4966 int name_len;
4967 int rc = 0;
4968 int bytes_returned = 0;
4969 FILE_UNIX_BASIC_INFO *data_offset;
4970 __u16 params, param_offset, offset, count, byte_count;
4972 cFYI(1, ("In SetUID/GID/Mode"));
4973 setPermsRetry:
4974 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4975 (void **) &pSMBr);
4976 if (rc)
4977 return rc;
4979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4980 name_len =
4981 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4982 PATH_MAX, nls_codepage, remap);
4983 name_len++; /* trailing null */
4984 name_len *= 2;
4985 } else { /* BB improve the check for buffer overruns BB */
4986 name_len = strnlen(fileName, PATH_MAX);
4987 name_len++; /* trailing null */
4988 strncpy(pSMB->FileName, fileName, name_len);
4991 params = 6 + name_len;
4992 count = sizeof(FILE_UNIX_BASIC_INFO);
4993 pSMB->MaxParameterCount = cpu_to_le16(2);
4994 /* BB find max SMB PDU from sess structure BB */
4995 pSMB->MaxDataCount = cpu_to_le16(1000);
4996 pSMB->MaxSetupCount = 0;
4997 pSMB->Reserved = 0;
4998 pSMB->Flags = 0;
4999 pSMB->Timeout = 0;
5000 pSMB->Reserved2 = 0;
5001 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5002 InformationLevel) - 4;
5003 offset = param_offset + params;
5004 data_offset =
5005 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5006 offset);
5007 memset(data_offset, 0, count);
5008 pSMB->DataOffset = cpu_to_le16(offset);
5009 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5010 pSMB->SetupCount = 1;
5011 pSMB->Reserved3 = 0;
5012 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5013 byte_count = 3 /* pad */ + params + count;
5014 pSMB->ParameterCount = cpu_to_le16(params);
5015 pSMB->DataCount = cpu_to_le16(count);
5016 pSMB->TotalParameterCount = pSMB->ParameterCount;
5017 pSMB->TotalDataCount = pSMB->DataCount;
5018 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5019 pSMB->Reserved4 = 0;
5020 pSMB->hdr.smb_buf_length += byte_count;
5021 /* Samba server ignores set of file size to zero due to bugs in some
5022 older clients, but we should be precise - we use SetFileSize to
5023 set file size and do not want to truncate file size to zero
5024 accidently as happened on one Samba server beta by putting
5025 zero instead of -1 here */
5026 data_offset->EndOfFile = NO_CHANGE_64;
5027 data_offset->NumOfBytes = NO_CHANGE_64;
5028 data_offset->LastStatusChange = NO_CHANGE_64;
5029 data_offset->LastAccessTime = NO_CHANGE_64;
5030 data_offset->LastModificationTime = NO_CHANGE_64;
5031 data_offset->Uid = cpu_to_le64(uid);
5032 data_offset->Gid = cpu_to_le64(gid);
5033 /* better to leave device as zero when it is */
5034 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5035 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5036 data_offset->Permissions = cpu_to_le64(mode);
5038 if (S_ISREG(mode))
5039 data_offset->Type = cpu_to_le32(UNIX_FILE);
5040 else if (S_ISDIR(mode))
5041 data_offset->Type = cpu_to_le32(UNIX_DIR);
5042 else if (S_ISLNK(mode))
5043 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5044 else if (S_ISCHR(mode))
5045 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5046 else if (S_ISBLK(mode))
5047 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5048 else if (S_ISFIFO(mode))
5049 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5050 else if (S_ISSOCK(mode))
5051 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5054 pSMB->ByteCount = cpu_to_le16(byte_count);
5055 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5056 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5057 if (rc)
5058 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5060 if (pSMB)
5061 cifs_buf_release(pSMB);
5062 if (rc == -EAGAIN)
5063 goto setPermsRetry;
5064 return rc;
5067 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5068 const int notify_subdirs, const __u16 netfid,
5069 __u32 filter, struct file *pfile, int multishot,
5070 const struct nls_table *nls_codepage)
5072 int rc = 0;
5073 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5074 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5075 struct dir_notify_req *dnotify_req;
5076 int bytes_returned;
5078 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5079 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5080 (void **) &pSMBr);
5081 if (rc)
5082 return rc;
5084 pSMB->TotalParameterCount = 0 ;
5085 pSMB->TotalDataCount = 0;
5086 pSMB->MaxParameterCount = cpu_to_le32(2);
5087 /* BB find exact data count max from sess structure BB */
5088 pSMB->MaxDataCount = 0; /* same in little endian or be */
5089 /* BB VERIFY verify which is correct for above BB */
5090 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5091 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5093 pSMB->MaxSetupCount = 4;
5094 pSMB->Reserved = 0;
5095 pSMB->ParameterOffset = 0;
5096 pSMB->DataCount = 0;
5097 pSMB->DataOffset = 0;
5098 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5099 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5100 pSMB->ParameterCount = pSMB->TotalParameterCount;
5101 if (notify_subdirs)
5102 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5103 pSMB->Reserved2 = 0;
5104 pSMB->CompletionFilter = cpu_to_le32(filter);
5105 pSMB->Fid = netfid; /* file handle always le */
5106 pSMB->ByteCount = 0;
5108 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5109 (struct smb_hdr *)pSMBr, &bytes_returned,
5110 CIFS_ASYNC_OP);
5111 if (rc) {
5112 cFYI(1, ("Error in Notify = %d", rc));
5113 } else {
5114 /* Add file to outstanding requests */
5115 /* BB change to kmem cache alloc */
5116 dnotify_req = kmalloc(
5117 sizeof(struct dir_notify_req),
5118 GFP_KERNEL);
5119 if (dnotify_req) {
5120 dnotify_req->Pid = pSMB->hdr.Pid;
5121 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5122 dnotify_req->Mid = pSMB->hdr.Mid;
5123 dnotify_req->Tid = pSMB->hdr.Tid;
5124 dnotify_req->Uid = pSMB->hdr.Uid;
5125 dnotify_req->netfid = netfid;
5126 dnotify_req->pfile = pfile;
5127 dnotify_req->filter = filter;
5128 dnotify_req->multishot = multishot;
5129 spin_lock(&GlobalMid_Lock);
5130 list_add_tail(&dnotify_req->lhead,
5131 &GlobalDnotifyReqList);
5132 spin_unlock(&GlobalMid_Lock);
5133 } else
5134 rc = -ENOMEM;
5136 cifs_buf_release(pSMB);
5137 return rc;
5139 #ifdef CONFIG_CIFS_XATTR
5140 ssize_t
5141 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5142 const unsigned char *searchName,
5143 char *EAData, size_t buf_size,
5144 const struct nls_table *nls_codepage, int remap)
5146 /* BB assumes one setup word */
5147 TRANSACTION2_QPI_REQ *pSMB = NULL;
5148 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5149 int rc = 0;
5150 int bytes_returned;
5151 int name_len;
5152 struct fea *temp_fea;
5153 char *temp_ptr;
5154 __u16 params, byte_count;
5156 cFYI(1, ("In Query All EAs path %s", searchName));
5157 QAllEAsRetry:
5158 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5159 (void **) &pSMBr);
5160 if (rc)
5161 return rc;
5163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5164 name_len =
5165 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5166 PATH_MAX, nls_codepage, remap);
5167 name_len++; /* trailing null */
5168 name_len *= 2;
5169 } else { /* BB improve the check for buffer overruns BB */
5170 name_len = strnlen(searchName, PATH_MAX);
5171 name_len++; /* trailing null */
5172 strncpy(pSMB->FileName, searchName, name_len);
5175 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5176 pSMB->TotalDataCount = 0;
5177 pSMB->MaxParameterCount = cpu_to_le16(2);
5178 /* BB find exact max SMB PDU from sess structure BB */
5179 pSMB->MaxDataCount = cpu_to_le16(4000);
5180 pSMB->MaxSetupCount = 0;
5181 pSMB->Reserved = 0;
5182 pSMB->Flags = 0;
5183 pSMB->Timeout = 0;
5184 pSMB->Reserved2 = 0;
5185 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5186 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5187 pSMB->DataCount = 0;
5188 pSMB->DataOffset = 0;
5189 pSMB->SetupCount = 1;
5190 pSMB->Reserved3 = 0;
5191 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5192 byte_count = params + 1 /* pad */ ;
5193 pSMB->TotalParameterCount = cpu_to_le16(params);
5194 pSMB->ParameterCount = pSMB->TotalParameterCount;
5195 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5196 pSMB->Reserved4 = 0;
5197 pSMB->hdr.smb_buf_length += byte_count;
5198 pSMB->ByteCount = cpu_to_le16(byte_count);
5200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5202 if (rc) {
5203 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5204 } else { /* decode response */
5205 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5207 /* BB also check enough total bytes returned */
5208 /* BB we need to improve the validity checking
5209 of these trans2 responses */
5210 if (rc || (pSMBr->ByteCount < 4))
5211 rc = -EIO; /* bad smb */
5212 /* else if (pFindData){
5213 memcpy((char *) pFindData,
5214 (char *) &pSMBr->hdr.Protocol +
5215 data_offset, kl);
5216 }*/ else {
5217 /* check that length of list is not more than bcc */
5218 /* check that each entry does not go beyond length
5219 of list */
5220 /* check that each element of each entry does not
5221 go beyond end of list */
5222 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5223 struct fealist *ea_response_data;
5224 rc = 0;
5225 /* validate_trans2_offsets() */
5226 /* BB check if start of smb + data_offset > &bcc+ bcc */
5227 ea_response_data = (struct fealist *)
5228 (((char *) &pSMBr->hdr.Protocol) +
5229 data_offset);
5230 name_len = le32_to_cpu(ea_response_data->list_len);
5231 cFYI(1, ("ea length %d", name_len));
5232 if (name_len <= 8) {
5233 /* returned EA size zeroed at top of function */
5234 cFYI(1, ("empty EA list returned from server"));
5235 } else {
5236 /* account for ea list len */
5237 name_len -= 4;
5238 temp_fea = ea_response_data->list;
5239 temp_ptr = (char *)temp_fea;
5240 while (name_len > 0) {
5241 __u16 value_len;
5242 name_len -= 4;
5243 temp_ptr += 4;
5244 rc += temp_fea->name_len;
5245 /* account for prefix user. and trailing null */
5246 rc = rc + 5 + 1;
5247 if (rc < (int)buf_size) {
5248 memcpy(EAData, "user.", 5);
5249 EAData += 5;
5250 memcpy(EAData, temp_ptr,
5251 temp_fea->name_len);
5252 EAData += temp_fea->name_len;
5253 /* null terminate name */
5254 *EAData = 0;
5255 EAData = EAData + 1;
5256 } else if (buf_size == 0) {
5257 /* skip copy - calc size only */
5258 } else {
5259 /* stop before overrun buffer */
5260 rc = -ERANGE;
5261 break;
5263 name_len -= temp_fea->name_len;
5264 temp_ptr += temp_fea->name_len;
5265 /* account for trailing null */
5266 name_len--;
5267 temp_ptr++;
5268 value_len =
5269 le16_to_cpu(temp_fea->value_len);
5270 name_len -= value_len;
5271 temp_ptr += value_len;
5272 /* BB check that temp_ptr is still
5273 within the SMB BB*/
5275 /* no trailing null to account for
5276 in value len */
5277 /* go on to next EA */
5278 temp_fea = (struct fea *)temp_ptr;
5283 if (pSMB)
5284 cifs_buf_release(pSMB);
5285 if (rc == -EAGAIN)
5286 goto QAllEAsRetry;
5288 return (ssize_t)rc;
5291 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5292 const unsigned char *searchName, const unsigned char *ea_name,
5293 unsigned char *ea_value, size_t buf_size,
5294 const struct nls_table *nls_codepage, int remap)
5296 TRANSACTION2_QPI_REQ *pSMB = NULL;
5297 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5298 int rc = 0;
5299 int bytes_returned;
5300 int name_len;
5301 struct fea *temp_fea;
5302 char *temp_ptr;
5303 __u16 params, byte_count;
5305 cFYI(1, ("In Query EA path %s", searchName));
5306 QEARetry:
5307 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5308 (void **) &pSMBr);
5309 if (rc)
5310 return rc;
5312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5313 name_len =
5314 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5315 PATH_MAX, nls_codepage, remap);
5316 name_len++; /* trailing null */
5317 name_len *= 2;
5318 } else { /* BB improve the check for buffer overruns BB */
5319 name_len = strnlen(searchName, PATH_MAX);
5320 name_len++; /* trailing null */
5321 strncpy(pSMB->FileName, searchName, name_len);
5324 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5325 pSMB->TotalDataCount = 0;
5326 pSMB->MaxParameterCount = cpu_to_le16(2);
5327 /* BB find exact max SMB PDU from sess structure BB */
5328 pSMB->MaxDataCount = cpu_to_le16(4000);
5329 pSMB->MaxSetupCount = 0;
5330 pSMB->Reserved = 0;
5331 pSMB->Flags = 0;
5332 pSMB->Timeout = 0;
5333 pSMB->Reserved2 = 0;
5334 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5335 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5336 pSMB->DataCount = 0;
5337 pSMB->DataOffset = 0;
5338 pSMB->SetupCount = 1;
5339 pSMB->Reserved3 = 0;
5340 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5341 byte_count = params + 1 /* pad */ ;
5342 pSMB->TotalParameterCount = cpu_to_le16(params);
5343 pSMB->ParameterCount = pSMB->TotalParameterCount;
5344 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5345 pSMB->Reserved4 = 0;
5346 pSMB->hdr.smb_buf_length += byte_count;
5347 pSMB->ByteCount = cpu_to_le16(byte_count);
5349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5351 if (rc) {
5352 cFYI(1, ("Send error in Query EA = %d", rc));
5353 } else { /* decode response */
5354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5356 /* BB also check enough total bytes returned */
5357 /* BB we need to improve the validity checking
5358 of these trans2 responses */
5359 if (rc || (pSMBr->ByteCount < 4))
5360 rc = -EIO; /* bad smb */
5361 /* else if (pFindData){
5362 memcpy((char *) pFindData,
5363 (char *) &pSMBr->hdr.Protocol +
5364 data_offset, kl);
5365 }*/ else {
5366 /* check that length of list is not more than bcc */
5367 /* check that each entry does not go beyond length
5368 of list */
5369 /* check that each element of each entry does not
5370 go beyond end of list */
5371 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5372 struct fealist *ea_response_data;
5373 rc = -ENODATA;
5374 /* validate_trans2_offsets() */
5375 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5376 ea_response_data = (struct fealist *)
5377 (((char *) &pSMBr->hdr.Protocol) +
5378 data_offset);
5379 name_len = le32_to_cpu(ea_response_data->list_len);
5380 cFYI(1, ("ea length %d", name_len));
5381 if (name_len <= 8) {
5382 /* returned EA size zeroed at top of function */
5383 cFYI(1, ("empty EA list returned from server"));
5384 } else {
5385 /* account for ea list len */
5386 name_len -= 4;
5387 temp_fea = ea_response_data->list;
5388 temp_ptr = (char *)temp_fea;
5389 /* loop through checking if we have a matching
5390 name and then return the associated value */
5391 while (name_len > 0) {
5392 __u16 value_len;
5393 name_len -= 4;
5394 temp_ptr += 4;
5395 value_len =
5396 le16_to_cpu(temp_fea->value_len);
5397 /* BB validate that value_len falls within SMB,
5398 even though maximum for name_len is 255 */
5399 if (memcmp(temp_fea->name, ea_name,
5400 temp_fea->name_len) == 0) {
5401 /* found a match */
5402 rc = value_len;
5403 /* account for prefix user. and trailing null */
5404 if (rc <= (int)buf_size) {
5405 memcpy(ea_value,
5406 temp_fea->name+temp_fea->name_len+1,
5407 rc);
5408 /* ea values, unlike ea
5409 names, are not null
5410 terminated */
5411 } else if (buf_size == 0) {
5412 /* skip copy - calc size only */
5413 } else {
5414 /* stop before overrun buffer */
5415 rc = -ERANGE;
5417 break;
5419 name_len -= temp_fea->name_len;
5420 temp_ptr += temp_fea->name_len;
5421 /* account for trailing null */
5422 name_len--;
5423 temp_ptr++;
5424 name_len -= value_len;
5425 temp_ptr += value_len;
5426 /* No trailing null to account for in
5427 value_len. Go on to next EA */
5428 temp_fea = (struct fea *)temp_ptr;
5433 if (pSMB)
5434 cifs_buf_release(pSMB);
5435 if (rc == -EAGAIN)
5436 goto QEARetry;
5438 return (ssize_t)rc;
5442 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5443 const char *ea_name, const void *ea_value,
5444 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5445 int remap)
5447 struct smb_com_transaction2_spi_req *pSMB = NULL;
5448 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5449 struct fealist *parm_data;
5450 int name_len;
5451 int rc = 0;
5452 int bytes_returned = 0;
5453 __u16 params, param_offset, byte_count, offset, count;
5455 cFYI(1, ("In SetEA"));
5456 SetEARetry:
5457 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5458 (void **) &pSMBr);
5459 if (rc)
5460 return rc;
5462 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5463 name_len =
5464 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5465 PATH_MAX, nls_codepage, remap);
5466 name_len++; /* trailing null */
5467 name_len *= 2;
5468 } else { /* BB improve the check for buffer overruns BB */
5469 name_len = strnlen(fileName, PATH_MAX);
5470 name_len++; /* trailing null */
5471 strncpy(pSMB->FileName, fileName, name_len);
5474 params = 6 + name_len;
5476 /* done calculating parms using name_len of file name,
5477 now use name_len to calculate length of ea name
5478 we are going to create in the inode xattrs */
5479 if (ea_name == NULL)
5480 name_len = 0;
5481 else
5482 name_len = strnlen(ea_name, 255);
5484 count = sizeof(*parm_data) + ea_value_len + name_len;
5485 pSMB->MaxParameterCount = cpu_to_le16(2);
5486 /* BB find max SMB PDU from sess */
5487 pSMB->MaxDataCount = cpu_to_le16(1000);
5488 pSMB->MaxSetupCount = 0;
5489 pSMB->Reserved = 0;
5490 pSMB->Flags = 0;
5491 pSMB->Timeout = 0;
5492 pSMB->Reserved2 = 0;
5493 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5494 InformationLevel) - 4;
5495 offset = param_offset + params;
5496 pSMB->InformationLevel =
5497 cpu_to_le16(SMB_SET_FILE_EA);
5499 parm_data =
5500 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5501 offset);
5502 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5503 pSMB->DataOffset = cpu_to_le16(offset);
5504 pSMB->SetupCount = 1;
5505 pSMB->Reserved3 = 0;
5506 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5507 byte_count = 3 /* pad */ + params + count;
5508 pSMB->DataCount = cpu_to_le16(count);
5509 parm_data->list_len = cpu_to_le32(count);
5510 parm_data->list[0].EA_flags = 0;
5511 /* we checked above that name len is less than 255 */
5512 parm_data->list[0].name_len = (__u8)name_len;
5513 /* EA names are always ASCII */
5514 if (ea_name)
5515 strncpy(parm_data->list[0].name, ea_name, name_len);
5516 parm_data->list[0].name[name_len] = 0;
5517 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5518 /* caller ensures that ea_value_len is less than 64K but
5519 we need to ensure that it fits within the smb */
5521 /*BB add length check to see if it would fit in
5522 negotiated SMB buffer size BB */
5523 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5524 if (ea_value_len)
5525 memcpy(parm_data->list[0].name+name_len+1,
5526 ea_value, ea_value_len);
5528 pSMB->TotalDataCount = pSMB->DataCount;
5529 pSMB->ParameterCount = cpu_to_le16(params);
5530 pSMB->TotalParameterCount = pSMB->ParameterCount;
5531 pSMB->Reserved4 = 0;
5532 pSMB->hdr.smb_buf_length += byte_count;
5533 pSMB->ByteCount = cpu_to_le16(byte_count);
5534 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5535 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5536 if (rc)
5537 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5539 cifs_buf_release(pSMB);
5541 if (rc == -EAGAIN)
5542 goto SetEARetry;
5544 return rc;
5547 #endif