edac: new support for Intel 3100 chipset
[linux-2.6/x86.git] / fs / cifs / cifssmb.c
blob4728fa982a4ed965237427b7386b838266ec497b
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 == FALSE) ||
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 == FALSE) ||
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;
1170 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1171 const char *fileName, const int openDisposition,
1172 const int access_flags, const int create_options, __u16 *netfid,
1173 int *pOplock, FILE_ALL_INFO *pfile_info,
1174 const struct nls_table *nls_codepage, int remap)
1176 int rc = -EACCES;
1177 OPENX_REQ *pSMB = NULL;
1178 OPENX_RSP *pSMBr = NULL;
1179 int bytes_returned;
1180 int name_len;
1181 __u16 count;
1183 OldOpenRetry:
1184 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1185 (void **) &pSMBr);
1186 if (rc)
1187 return rc;
1189 pSMB->AndXCommand = 0xFF; /* none */
1191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1192 count = 1; /* account for one byte pad to word boundary */
1193 name_len =
1194 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1195 fileName, PATH_MAX, nls_codepage, remap);
1196 name_len++; /* trailing null */
1197 name_len *= 2;
1198 } else { /* BB improve check for buffer overruns BB */
1199 count = 0; /* no pad */
1200 name_len = strnlen(fileName, PATH_MAX);
1201 name_len++; /* trailing null */
1202 strncpy(pSMB->fileName, fileName, name_len);
1204 if (*pOplock & REQ_OPLOCK)
1205 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1206 else if (*pOplock & REQ_BATCHOPLOCK)
1207 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1209 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1210 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1211 /* 0 = read
1212 1 = write
1213 2 = rw
1214 3 = execute
1216 pSMB->Mode = cpu_to_le16(2);
1217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1224 else /* BB FIXME BB */
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1227 /* if ((omode & S_IWUGO) == 0)
1228 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1229 /* Above line causes problems due to vfs splitting create into two
1230 pieces - need to set mode after file created not while it is
1231 being created */
1233 /* BB FIXME BB */
1234 /* pSMB->CreateOptions = cpu_to_le32(create_options &
1235 CREATE_OPTIONS_MASK); */
1236 /* BB FIXME END BB */
1238 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1239 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1240 count += name_len;
1241 pSMB->hdr.smb_buf_length += count;
1243 pSMB->ByteCount = cpu_to_le16(count);
1244 /* long_op set to 1 to allow for oplock break timeouts */
1245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1246 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1247 cifs_stats_inc(&tcon->num_opens);
1248 if (rc) {
1249 cFYI(1, ("Error in Open = %d", rc));
1250 } else {
1251 /* BB verify if wct == 15 */
1253 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1255 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1256 /* Let caller know file was created so we can set the mode. */
1257 /* Do we care about the CreateAction in any other cases? */
1258 /* BB FIXME BB */
1259 /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1260 *pOplock |= CIFS_CREATE_ACTION; */
1261 /* BB FIXME END */
1263 if (pfile_info) {
1264 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1265 pfile_info->LastAccessTime = 0; /* BB fixme */
1266 pfile_info->LastWriteTime = 0; /* BB fixme */
1267 pfile_info->ChangeTime = 0; /* BB fixme */
1268 pfile_info->Attributes =
1269 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1270 /* the file_info buf is endian converted by caller */
1271 pfile_info->AllocationSize =
1272 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1273 pfile_info->EndOfFile = pfile_info->AllocationSize;
1274 pfile_info->NumberOfLinks = cpu_to_le32(1);
1278 cifs_buf_release(pSMB);
1279 if (rc == -EAGAIN)
1280 goto OldOpenRetry;
1281 return rc;
1285 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1286 const char *fileName, const int openDisposition,
1287 const int access_flags, const int create_options, __u16 *netfid,
1288 int *pOplock, FILE_ALL_INFO *pfile_info,
1289 const struct nls_table *nls_codepage, int remap)
1291 int rc = -EACCES;
1292 OPEN_REQ *pSMB = NULL;
1293 OPEN_RSP *pSMBr = NULL;
1294 int bytes_returned;
1295 int name_len;
1296 __u16 count;
1298 openRetry:
1299 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1300 (void **) &pSMBr);
1301 if (rc)
1302 return rc;
1304 pSMB->AndXCommand = 0xFF; /* none */
1306 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1307 count = 1; /* account for one byte pad to word boundary */
1308 name_len =
1309 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1310 fileName, PATH_MAX, nls_codepage, remap);
1311 name_len++; /* trailing null */
1312 name_len *= 2;
1313 pSMB->NameLength = cpu_to_le16(name_len);
1314 } else { /* BB improve check for buffer overruns BB */
1315 count = 0; /* no pad */
1316 name_len = strnlen(fileName, PATH_MAX);
1317 name_len++; /* trailing null */
1318 pSMB->NameLength = cpu_to_le16(name_len);
1319 strncpy(pSMB->fileName, fileName, name_len);
1321 if (*pOplock & REQ_OPLOCK)
1322 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1323 else if (*pOplock & REQ_BATCHOPLOCK)
1324 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1325 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1326 pSMB->AllocationSize = 0;
1327 /* set file as system file if special file such
1328 as fifo and server expecting SFU style and
1329 no Unix extensions */
1330 if (create_options & CREATE_OPTION_SPECIAL)
1331 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1332 else
1333 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1334 /* XP does not handle ATTR_POSIX_SEMANTICS */
1335 /* but it helps speed up case sensitive checks for other
1336 servers such as Samba */
1337 if (tcon->ses->capabilities & CAP_UNIX)
1338 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1340 /* if ((omode & S_IWUGO) == 0)
1341 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1342 /* Above line causes problems due to vfs splitting create into two
1343 pieces - need to set mode after file created not while it is
1344 being created */
1345 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1346 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1347 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1348 /* BB Expirement with various impersonation levels and verify */
1349 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1350 pSMB->SecurityFlags =
1351 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1353 count += name_len;
1354 pSMB->hdr.smb_buf_length += count;
1356 pSMB->ByteCount = cpu_to_le16(count);
1357 /* long_op set to 1 to allow for oplock break timeouts */
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1359 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
1360 cifs_stats_inc(&tcon->num_opens);
1361 if (rc) {
1362 cFYI(1, ("Error in Open = %d", rc));
1363 } else {
1364 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1365 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1366 /* Let caller know file was created so we can set the mode. */
1367 /* Do we care about the CreateAction in any other cases? */
1368 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1369 *pOplock |= CIFS_CREATE_ACTION;
1370 if (pfile_info) {
1371 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1372 36 /* CreationTime to Attributes */);
1373 /* the file_info buf is endian converted by caller */
1374 pfile_info->AllocationSize = pSMBr->AllocationSize;
1375 pfile_info->EndOfFile = pSMBr->EndOfFile;
1376 pfile_info->NumberOfLinks = cpu_to_le32(1);
1380 cifs_buf_release(pSMB);
1381 if (rc == -EAGAIN)
1382 goto openRetry;
1383 return rc;
1387 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1388 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1389 char **buf, int *pbuf_type)
1391 int rc = -EACCES;
1392 READ_REQ *pSMB = NULL;
1393 READ_RSP *pSMBr = NULL;
1394 char *pReadData = NULL;
1395 int wct;
1396 int resp_buf_type = 0;
1397 struct kvec iov[1];
1399 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1400 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1401 wct = 12;
1402 else
1403 wct = 10; /* old style read */
1405 *nbytes = 0;
1406 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1407 if (rc)
1408 return rc;
1410 /* tcon and ses pointer are checked in smb_init */
1411 if (tcon->ses->server == NULL)
1412 return -ECONNABORTED;
1414 pSMB->AndXCommand = 0xFF; /* none */
1415 pSMB->Fid = netfid;
1416 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1417 if (wct == 12)
1418 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1419 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
1420 return -EIO;
1422 pSMB->Remaining = 0;
1423 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1424 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1425 if (wct == 12)
1426 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1427 else {
1428 /* old style read */
1429 struct smb_com_readx_req *pSMBW =
1430 (struct smb_com_readx_req *)pSMB;
1431 pSMBW->ByteCount = 0;
1434 iov[0].iov_base = (char *)pSMB;
1435 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1436 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1437 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
1438 cifs_stats_inc(&tcon->num_reads);
1439 pSMBr = (READ_RSP *)iov[0].iov_base;
1440 if (rc) {
1441 cERROR(1, ("Send error in read = %d", rc));
1442 } else {
1443 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1444 data_length = data_length << 16;
1445 data_length += le16_to_cpu(pSMBr->DataLength);
1446 *nbytes = data_length;
1448 /*check that DataLength would not go beyond end of SMB */
1449 if ((data_length > CIFSMaxBufSize)
1450 || (data_length > count)) {
1451 cFYI(1, ("bad length %d for count %d",
1452 data_length, count));
1453 rc = -EIO;
1454 *nbytes = 0;
1455 } else {
1456 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1457 le16_to_cpu(pSMBr->DataOffset);
1458 /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1459 cERROR(1,("Faulting on read rc = %d",rc));
1460 rc = -EFAULT;
1461 }*/ /* can not use copy_to_user when using page cache*/
1462 if (*buf)
1463 memcpy(*buf, pReadData, data_length);
1467 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1468 if (*buf) {
1469 if (resp_buf_type == CIFS_SMALL_BUFFER)
1470 cifs_small_buf_release(iov[0].iov_base);
1471 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1472 cifs_buf_release(iov[0].iov_base);
1473 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1474 /* return buffer to caller to free */
1475 *buf = iov[0].iov_base;
1476 if (resp_buf_type == CIFS_SMALL_BUFFER)
1477 *pbuf_type = CIFS_SMALL_BUFFER;
1478 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1479 *pbuf_type = CIFS_LARGE_BUFFER;
1480 } /* else no valid buffer on return - leave as null */
1482 /* Note: On -EAGAIN error only caller can retry on handle based calls
1483 since file handle passed in no longer valid */
1484 return rc;
1489 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1490 const int netfid, const unsigned int count,
1491 const __u64 offset, unsigned int *nbytes, const char *buf,
1492 const char __user *ubuf, const int long_op)
1494 int rc = -EACCES;
1495 WRITE_REQ *pSMB = NULL;
1496 WRITE_RSP *pSMBr = NULL;
1497 int bytes_returned, wct;
1498 __u32 bytes_sent;
1499 __u16 byte_count;
1501 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1502 if (tcon->ses == NULL)
1503 return -ECONNABORTED;
1505 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1506 wct = 14;
1507 else
1508 wct = 12;
1510 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1511 (void **) &pSMBr);
1512 if (rc)
1513 return rc;
1514 /* tcon and ses pointer are checked in smb_init */
1515 if (tcon->ses->server == NULL)
1516 return -ECONNABORTED;
1518 pSMB->AndXCommand = 0xFF; /* none */
1519 pSMB->Fid = netfid;
1520 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1521 if (wct == 14)
1522 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1523 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1524 return -EIO;
1526 pSMB->Reserved = 0xFFFFFFFF;
1527 pSMB->WriteMode = 0;
1528 pSMB->Remaining = 0;
1530 /* Can increase buffer size if buffer is big enough in some cases ie we
1531 can send more if LARGE_WRITE_X capability returned by the server and if
1532 our buffer is big enough or if we convert to iovecs on socket writes
1533 and eliminate the copy to the CIFS buffer */
1534 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1535 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1536 } else {
1537 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1538 & ~0xFF;
1541 if (bytes_sent > count)
1542 bytes_sent = count;
1543 pSMB->DataOffset =
1544 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1545 if (buf)
1546 memcpy(pSMB->Data, buf, bytes_sent);
1547 else if (ubuf) {
1548 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1549 cifs_buf_release(pSMB);
1550 return -EFAULT;
1552 } else if (count != 0) {
1553 /* No buffer */
1554 cifs_buf_release(pSMB);
1555 return -EINVAL;
1556 } /* else setting file size with write of zero bytes */
1557 if (wct == 14)
1558 byte_count = bytes_sent + 1; /* pad */
1559 else /* wct == 12 */
1560 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1562 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1563 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1564 pSMB->hdr.smb_buf_length += byte_count;
1566 if (wct == 14)
1567 pSMB->ByteCount = cpu_to_le16(byte_count);
1568 else { /* old style write has byte count 4 bytes earlier
1569 so 4 bytes pad */
1570 struct smb_com_writex_req *pSMBW =
1571 (struct smb_com_writex_req *)pSMB;
1572 pSMBW->ByteCount = cpu_to_le16(byte_count);
1575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1576 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1577 cifs_stats_inc(&tcon->num_writes);
1578 if (rc) {
1579 cFYI(1, ("Send error in write = %d", rc));
1580 *nbytes = 0;
1581 } else {
1582 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1583 *nbytes = (*nbytes) << 16;
1584 *nbytes += le16_to_cpu(pSMBr->Count);
1587 cifs_buf_release(pSMB);
1589 /* Note: On -EAGAIN error only caller can retry on handle based calls
1590 since file handle passed in no longer valid */
1592 return rc;
1596 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1597 const int netfid, const unsigned int count,
1598 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1599 int n_vec, const int long_op)
1601 int rc = -EACCES;
1602 WRITE_REQ *pSMB = NULL;
1603 int wct;
1604 int smb_hdr_len;
1605 int resp_buf_type = 0;
1607 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1609 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1610 wct = 14;
1611 else
1612 wct = 12;
1613 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1614 if (rc)
1615 return rc;
1616 /* tcon and ses pointer are checked in smb_init */
1617 if (tcon->ses->server == NULL)
1618 return -ECONNABORTED;
1620 pSMB->AndXCommand = 0xFF; /* none */
1621 pSMB->Fid = netfid;
1622 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1623 if (wct == 14)
1624 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1625 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1626 return -EIO;
1627 pSMB->Reserved = 0xFFFFFFFF;
1628 pSMB->WriteMode = 0;
1629 pSMB->Remaining = 0;
1631 pSMB->DataOffset =
1632 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1634 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1635 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1636 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1637 if (wct == 14)
1638 pSMB->hdr.smb_buf_length += count+1;
1639 else /* wct == 12 */
1640 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1641 if (wct == 14)
1642 pSMB->ByteCount = cpu_to_le16(count + 1);
1643 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1644 struct smb_com_writex_req *pSMBW =
1645 (struct smb_com_writex_req *)pSMB;
1646 pSMBW->ByteCount = cpu_to_le16(count + 5);
1648 iov[0].iov_base = pSMB;
1649 if (wct == 14)
1650 iov[0].iov_len = smb_hdr_len + 4;
1651 else /* wct == 12 pad bigger by four bytes */
1652 iov[0].iov_len = smb_hdr_len + 8;
1655 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1656 long_op);
1657 cifs_stats_inc(&tcon->num_writes);
1658 if (rc) {
1659 cFYI(1, ("Send error Write2 = %d", rc));
1660 *nbytes = 0;
1661 } else if (resp_buf_type == 0) {
1662 /* presumably this can not happen, but best to be safe */
1663 rc = -EIO;
1664 *nbytes = 0;
1665 } else {
1666 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
1667 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1668 *nbytes = (*nbytes) << 16;
1669 *nbytes += le16_to_cpu(pSMBr->Count);
1672 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1673 if (resp_buf_type == CIFS_SMALL_BUFFER)
1674 cifs_small_buf_release(iov[0].iov_base);
1675 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1676 cifs_buf_release(iov[0].iov_base);
1678 /* Note: On -EAGAIN error only caller can retry on handle based calls
1679 since file handle passed in no longer valid */
1681 return rc;
1686 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1687 const __u16 smb_file_id, const __u64 len,
1688 const __u64 offset, const __u32 numUnlock,
1689 const __u32 numLock, const __u8 lockType, const int waitFlag)
1691 int rc = 0;
1692 LOCK_REQ *pSMB = NULL;
1693 LOCK_RSP *pSMBr = NULL;
1694 int bytes_returned;
1695 int timeout = 0;
1696 __u16 count;
1698 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock));
1699 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1701 if (rc)
1702 return rc;
1704 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1706 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1707 timeout = CIFS_ASYNC_OP; /* no response expected */
1708 pSMB->Timeout = 0;
1709 } else if (waitFlag == TRUE) {
1710 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1711 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1712 } else {
1713 pSMB->Timeout = 0;
1716 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1717 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1718 pSMB->LockType = lockType;
1719 pSMB->AndXCommand = 0xFF; /* none */
1720 pSMB->Fid = smb_file_id; /* netfid stays le */
1722 if ((numLock != 0) || (numUnlock != 0)) {
1723 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1724 /* BB where to store pid high? */
1725 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1726 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1727 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1728 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1729 count = sizeof(LOCKING_ANDX_RANGE);
1730 } else {
1731 /* oplock break */
1732 count = 0;
1734 pSMB->hdr.smb_buf_length += count;
1735 pSMB->ByteCount = cpu_to_le16(count);
1737 if (waitFlag) {
1738 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1739 (struct smb_hdr *) pSMBr, &bytes_returned);
1740 cifs_small_buf_release(pSMB);
1741 } else {
1742 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1743 timeout);
1744 /* SMB buffer freed by function above */
1746 cifs_stats_inc(&tcon->num_locks);
1747 if (rc)
1748 cFYI(1, ("Send error in Lock = %d", rc));
1750 /* Note: On -EAGAIN error only caller can retry on handle based calls
1751 since file handle passed in no longer valid */
1752 return rc;
1756 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1757 const __u16 smb_file_id, const int get_flag, const __u64 len,
1758 struct file_lock *pLockData, const __u16 lock_type,
1759 const int waitFlag)
1761 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1762 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1763 struct cifs_posix_lock *parm_data;
1764 int rc = 0;
1765 int timeout = 0;
1766 int bytes_returned = 0;
1767 int resp_buf_type = 0;
1768 __u16 params, param_offset, offset, byte_count, count;
1769 struct kvec iov[1];
1771 cFYI(1, ("Posix Lock"));
1773 if (pLockData == NULL)
1774 return EINVAL;
1776 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1778 if (rc)
1779 return rc;
1781 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1783 params = 6;
1784 pSMB->MaxSetupCount = 0;
1785 pSMB->Reserved = 0;
1786 pSMB->Flags = 0;
1787 pSMB->Reserved2 = 0;
1788 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1789 offset = param_offset + params;
1791 count = sizeof(struct cifs_posix_lock);
1792 pSMB->MaxParameterCount = cpu_to_le16(2);
1793 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1794 pSMB->SetupCount = 1;
1795 pSMB->Reserved3 = 0;
1796 if (get_flag)
1797 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1798 else
1799 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1800 byte_count = 3 /* pad */ + params + count;
1801 pSMB->DataCount = cpu_to_le16(count);
1802 pSMB->ParameterCount = cpu_to_le16(params);
1803 pSMB->TotalDataCount = pSMB->DataCount;
1804 pSMB->TotalParameterCount = pSMB->ParameterCount;
1805 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1806 parm_data = (struct cifs_posix_lock *)
1807 (((char *) &pSMB->hdr.Protocol) + offset);
1809 parm_data->lock_type = cpu_to_le16(lock_type);
1810 if (waitFlag) {
1811 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1812 parm_data->lock_flags = cpu_to_le16(1);
1813 pSMB->Timeout = cpu_to_le32(-1);
1814 } else
1815 pSMB->Timeout = 0;
1817 parm_data->pid = cpu_to_le32(current->tgid);
1818 parm_data->start = cpu_to_le64(pLockData->fl_start);
1819 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1821 pSMB->DataOffset = cpu_to_le16(offset);
1822 pSMB->Fid = smb_file_id;
1823 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1824 pSMB->Reserved4 = 0;
1825 pSMB->hdr.smb_buf_length += byte_count;
1826 pSMB->ByteCount = cpu_to_le16(byte_count);
1827 if (waitFlag) {
1828 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1829 (struct smb_hdr *) pSMBr, &bytes_returned);
1830 } else {
1831 iov[0].iov_base = (char *)pSMB;
1832 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1833 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1834 &resp_buf_type, timeout);
1835 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1836 not try to free it twice below on exit */
1837 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
1840 if (rc) {
1841 cFYI(1, ("Send error in Posix Lock = %d", rc));
1842 } else if (get_flag) {
1843 /* lock structure can be returned on get */
1844 __u16 data_offset;
1845 __u16 data_count;
1846 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1848 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1849 rc = -EIO; /* bad smb */
1850 goto plk_err_exit;
1852 if (pLockData == NULL) {
1853 rc = -EINVAL;
1854 goto plk_err_exit;
1856 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1857 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1858 if (data_count < sizeof(struct cifs_posix_lock)) {
1859 rc = -EIO;
1860 goto plk_err_exit;
1862 parm_data = (struct cifs_posix_lock *)
1863 ((char *)&pSMBr->hdr.Protocol + data_offset);
1864 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1865 pLockData->fl_type = F_UNLCK;
1868 plk_err_exit:
1869 if (pSMB)
1870 cifs_small_buf_release(pSMB);
1872 if (resp_buf_type == CIFS_SMALL_BUFFER)
1873 cifs_small_buf_release(iov[0].iov_base);
1874 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1875 cifs_buf_release(iov[0].iov_base);
1877 /* Note: On -EAGAIN error only caller can retry on handle based calls
1878 since file handle passed in no longer valid */
1880 return rc;
1885 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1887 int rc = 0;
1888 CLOSE_REQ *pSMB = NULL;
1889 cFYI(1, ("In CIFSSMBClose"));
1891 /* do not retry on dead session on close */
1892 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1893 if (rc == -EAGAIN)
1894 return 0;
1895 if (rc)
1896 return rc;
1898 pSMB->FileID = (__u16) smb_file_id;
1899 pSMB->LastWriteTime = 0xFFFFFFFF;
1900 pSMB->ByteCount = 0;
1901 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1902 cifs_stats_inc(&tcon->num_closes);
1903 if (rc) {
1904 if (rc != -EINTR) {
1905 /* EINTR is expected when user ctl-c to kill app */
1906 cERROR(1, ("Send error in Close = %d", rc));
1910 /* Since session is dead, file will be closed on server already */
1911 if (rc == -EAGAIN)
1912 rc = 0;
1914 return rc;
1918 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1919 const char *fromName, const char *toName,
1920 const struct nls_table *nls_codepage, int remap)
1922 int rc = 0;
1923 RENAME_REQ *pSMB = NULL;
1924 RENAME_RSP *pSMBr = NULL;
1925 int bytes_returned;
1926 int name_len, name_len2;
1927 __u16 count;
1929 cFYI(1, ("In CIFSSMBRename"));
1930 renameRetry:
1931 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1932 (void **) &pSMBr);
1933 if (rc)
1934 return rc;
1936 pSMB->BufferFormat = 0x04;
1937 pSMB->SearchAttributes =
1938 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1939 ATTR_DIRECTORY);
1941 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1942 name_len =
1943 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1944 PATH_MAX, nls_codepage, remap);
1945 name_len++; /* trailing null */
1946 name_len *= 2;
1947 pSMB->OldFileName[name_len] = 0x04; /* pad */
1948 /* protocol requires ASCII signature byte on Unicode string */
1949 pSMB->OldFileName[name_len + 1] = 0x00;
1950 name_len2 =
1951 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1952 toName, PATH_MAX, nls_codepage, remap);
1953 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1954 name_len2 *= 2; /* convert to bytes */
1955 } else { /* BB improve the check for buffer overruns BB */
1956 name_len = strnlen(fromName, PATH_MAX);
1957 name_len++; /* trailing null */
1958 strncpy(pSMB->OldFileName, fromName, name_len);
1959 name_len2 = strnlen(toName, PATH_MAX);
1960 name_len2++; /* trailing null */
1961 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1962 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1963 name_len2++; /* trailing null */
1964 name_len2++; /* signature byte */
1967 count = 1 /* 1st signature byte */ + name_len + name_len2;
1968 pSMB->hdr.smb_buf_length += count;
1969 pSMB->ByteCount = cpu_to_le16(count);
1971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1973 cifs_stats_inc(&tcon->num_renames);
1974 if (rc)
1975 cFYI(1, ("Send error in rename = %d", rc));
1977 cifs_buf_release(pSMB);
1979 if (rc == -EAGAIN)
1980 goto renameRetry;
1982 return rc;
1985 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1986 int netfid, char *target_name,
1987 const struct nls_table *nls_codepage, int remap)
1989 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1990 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1991 struct set_file_rename *rename_info;
1992 char *data_offset;
1993 char dummy_string[30];
1994 int rc = 0;
1995 int bytes_returned = 0;
1996 int len_of_str;
1997 __u16 params, param_offset, offset, count, byte_count;
1999 cFYI(1, ("Rename to File by handle"));
2000 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2001 (void **) &pSMBr);
2002 if (rc)
2003 return rc;
2005 params = 6;
2006 pSMB->MaxSetupCount = 0;
2007 pSMB->Reserved = 0;
2008 pSMB->Flags = 0;
2009 pSMB->Timeout = 0;
2010 pSMB->Reserved2 = 0;
2011 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2012 offset = param_offset + params;
2014 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2015 rename_info = (struct set_file_rename *) data_offset;
2016 pSMB->MaxParameterCount = cpu_to_le16(2);
2017 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2018 pSMB->SetupCount = 1;
2019 pSMB->Reserved3 = 0;
2020 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2021 byte_count = 3 /* pad */ + params;
2022 pSMB->ParameterCount = cpu_to_le16(params);
2023 pSMB->TotalParameterCount = pSMB->ParameterCount;
2024 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2025 pSMB->DataOffset = cpu_to_le16(offset);
2026 /* construct random name ".cifs_tmp<inodenum><mid>" */
2027 rename_info->overwrite = cpu_to_le32(1);
2028 rename_info->root_fid = 0;
2029 /* unicode only call */
2030 if (target_name == NULL) {
2031 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2032 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2033 dummy_string, 24, nls_codepage, remap);
2034 } else {
2035 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2036 target_name, PATH_MAX, nls_codepage,
2037 remap);
2039 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2040 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2041 byte_count += count;
2042 pSMB->DataCount = cpu_to_le16(count);
2043 pSMB->TotalDataCount = pSMB->DataCount;
2044 pSMB->Fid = netfid;
2045 pSMB->InformationLevel =
2046 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2047 pSMB->Reserved4 = 0;
2048 pSMB->hdr.smb_buf_length += byte_count;
2049 pSMB->ByteCount = cpu_to_le16(byte_count);
2050 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2052 cifs_stats_inc(&pTcon->num_t2renames);
2053 if (rc)
2054 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2056 cifs_buf_release(pSMB);
2058 /* Note: On -EAGAIN error only caller can retry on handle based calls
2059 since file handle passed in no longer valid */
2061 return rc;
2065 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2066 const __u16 target_tid, const char *toName, const int flags,
2067 const struct nls_table *nls_codepage, int remap)
2069 int rc = 0;
2070 COPY_REQ *pSMB = NULL;
2071 COPY_RSP *pSMBr = NULL;
2072 int bytes_returned;
2073 int name_len, name_len2;
2074 __u16 count;
2076 cFYI(1, ("In CIFSSMBCopy"));
2077 copyRetry:
2078 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2079 (void **) &pSMBr);
2080 if (rc)
2081 return rc;
2083 pSMB->BufferFormat = 0x04;
2084 pSMB->Tid2 = target_tid;
2086 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2088 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2089 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2090 fromName, PATH_MAX, nls_codepage,
2091 remap);
2092 name_len++; /* trailing null */
2093 name_len *= 2;
2094 pSMB->OldFileName[name_len] = 0x04; /* pad */
2095 /* protocol requires ASCII signature byte on Unicode string */
2096 pSMB->OldFileName[name_len + 1] = 0x00;
2097 name_len2 =
2098 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2099 toName, PATH_MAX, nls_codepage, remap);
2100 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2101 name_len2 *= 2; /* convert to bytes */
2102 } else { /* BB improve the check for buffer overruns BB */
2103 name_len = strnlen(fromName, PATH_MAX);
2104 name_len++; /* trailing null */
2105 strncpy(pSMB->OldFileName, fromName, name_len);
2106 name_len2 = strnlen(toName, PATH_MAX);
2107 name_len2++; /* trailing null */
2108 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2109 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2110 name_len2++; /* trailing null */
2111 name_len2++; /* signature byte */
2114 count = 1 /* 1st signature byte */ + name_len + name_len2;
2115 pSMB->hdr.smb_buf_length += count;
2116 pSMB->ByteCount = cpu_to_le16(count);
2118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2120 if (rc) {
2121 cFYI(1, ("Send error in copy = %d with %d files copied",
2122 rc, le16_to_cpu(pSMBr->CopyCount)));
2124 if (pSMB)
2125 cifs_buf_release(pSMB);
2127 if (rc == -EAGAIN)
2128 goto copyRetry;
2130 return rc;
2134 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2135 const char *fromName, const char *toName,
2136 const struct nls_table *nls_codepage)
2138 TRANSACTION2_SPI_REQ *pSMB = NULL;
2139 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2140 char *data_offset;
2141 int name_len;
2142 int name_len_target;
2143 int rc = 0;
2144 int bytes_returned = 0;
2145 __u16 params, param_offset, offset, byte_count;
2147 cFYI(1, ("In Symlink Unix style"));
2148 createSymLinkRetry:
2149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2150 (void **) &pSMBr);
2151 if (rc)
2152 return rc;
2154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2155 name_len =
2156 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2157 /* find define for this maxpathcomponent */
2158 , nls_codepage);
2159 name_len++; /* trailing null */
2160 name_len *= 2;
2162 } else { /* BB improve the check for buffer overruns BB */
2163 name_len = strnlen(fromName, PATH_MAX);
2164 name_len++; /* trailing null */
2165 strncpy(pSMB->FileName, fromName, name_len);
2167 params = 6 + name_len;
2168 pSMB->MaxSetupCount = 0;
2169 pSMB->Reserved = 0;
2170 pSMB->Flags = 0;
2171 pSMB->Timeout = 0;
2172 pSMB->Reserved2 = 0;
2173 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2174 InformationLevel) - 4;
2175 offset = param_offset + params;
2177 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2178 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2179 name_len_target =
2180 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2181 /* find define for this maxpathcomponent */
2182 , nls_codepage);
2183 name_len_target++; /* trailing null */
2184 name_len_target *= 2;
2185 } else { /* BB improve the check for buffer overruns BB */
2186 name_len_target = strnlen(toName, PATH_MAX);
2187 name_len_target++; /* trailing null */
2188 strncpy(data_offset, toName, name_len_target);
2191 pSMB->MaxParameterCount = cpu_to_le16(2);
2192 /* BB find exact max on data count below from sess */
2193 pSMB->MaxDataCount = cpu_to_le16(1000);
2194 pSMB->SetupCount = 1;
2195 pSMB->Reserved3 = 0;
2196 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2197 byte_count = 3 /* pad */ + params + name_len_target;
2198 pSMB->DataCount = cpu_to_le16(name_len_target);
2199 pSMB->ParameterCount = cpu_to_le16(params);
2200 pSMB->TotalDataCount = pSMB->DataCount;
2201 pSMB->TotalParameterCount = pSMB->ParameterCount;
2202 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2203 pSMB->DataOffset = cpu_to_le16(offset);
2204 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2205 pSMB->Reserved4 = 0;
2206 pSMB->hdr.smb_buf_length += byte_count;
2207 pSMB->ByteCount = cpu_to_le16(byte_count);
2208 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2209 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2210 cifs_stats_inc(&tcon->num_symlinks);
2211 if (rc)
2212 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2214 if (pSMB)
2215 cifs_buf_release(pSMB);
2217 if (rc == -EAGAIN)
2218 goto createSymLinkRetry;
2220 return rc;
2224 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2225 const char *fromName, const char *toName,
2226 const struct nls_table *nls_codepage, int remap)
2228 TRANSACTION2_SPI_REQ *pSMB = NULL;
2229 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2230 char *data_offset;
2231 int name_len;
2232 int name_len_target;
2233 int rc = 0;
2234 int bytes_returned = 0;
2235 __u16 params, param_offset, offset, byte_count;
2237 cFYI(1, ("In Create Hard link Unix style"));
2238 createHardLinkRetry:
2239 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2240 (void **) &pSMBr);
2241 if (rc)
2242 return rc;
2244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2245 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2246 PATH_MAX, nls_codepage, remap);
2247 name_len++; /* trailing null */
2248 name_len *= 2;
2250 } else { /* BB improve the check for buffer overruns BB */
2251 name_len = strnlen(toName, PATH_MAX);
2252 name_len++; /* trailing null */
2253 strncpy(pSMB->FileName, toName, name_len);
2255 params = 6 + name_len;
2256 pSMB->MaxSetupCount = 0;
2257 pSMB->Reserved = 0;
2258 pSMB->Flags = 0;
2259 pSMB->Timeout = 0;
2260 pSMB->Reserved2 = 0;
2261 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2262 InformationLevel) - 4;
2263 offset = param_offset + params;
2265 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2266 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2267 name_len_target =
2268 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2269 nls_codepage, remap);
2270 name_len_target++; /* trailing null */
2271 name_len_target *= 2;
2272 } else { /* BB improve the check for buffer overruns BB */
2273 name_len_target = strnlen(fromName, PATH_MAX);
2274 name_len_target++; /* trailing null */
2275 strncpy(data_offset, fromName, name_len_target);
2278 pSMB->MaxParameterCount = cpu_to_le16(2);
2279 /* BB find exact max on data count below from sess*/
2280 pSMB->MaxDataCount = cpu_to_le16(1000);
2281 pSMB->SetupCount = 1;
2282 pSMB->Reserved3 = 0;
2283 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2284 byte_count = 3 /* pad */ + params + name_len_target;
2285 pSMB->ParameterCount = cpu_to_le16(params);
2286 pSMB->TotalParameterCount = pSMB->ParameterCount;
2287 pSMB->DataCount = cpu_to_le16(name_len_target);
2288 pSMB->TotalDataCount = pSMB->DataCount;
2289 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2290 pSMB->DataOffset = cpu_to_le16(offset);
2291 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2292 pSMB->Reserved4 = 0;
2293 pSMB->hdr.smb_buf_length += byte_count;
2294 pSMB->ByteCount = cpu_to_le16(byte_count);
2295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2297 cifs_stats_inc(&tcon->num_hardlinks);
2298 if (rc)
2299 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2301 cifs_buf_release(pSMB);
2302 if (rc == -EAGAIN)
2303 goto createHardLinkRetry;
2305 return rc;
2309 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2310 const char *fromName, const char *toName,
2311 const struct nls_table *nls_codepage, int remap)
2313 int rc = 0;
2314 NT_RENAME_REQ *pSMB = NULL;
2315 RENAME_RSP *pSMBr = NULL;
2316 int bytes_returned;
2317 int name_len, name_len2;
2318 __u16 count;
2320 cFYI(1, ("In CIFSCreateHardLink"));
2321 winCreateHardLinkRetry:
2323 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2324 (void **) &pSMBr);
2325 if (rc)
2326 return rc;
2328 pSMB->SearchAttributes =
2329 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2330 ATTR_DIRECTORY);
2331 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2332 pSMB->ClusterCount = 0;
2334 pSMB->BufferFormat = 0x04;
2336 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2337 name_len =
2338 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2339 PATH_MAX, nls_codepage, remap);
2340 name_len++; /* trailing null */
2341 name_len *= 2;
2342 pSMB->OldFileName[name_len] = 0; /* pad */
2343 pSMB->OldFileName[name_len + 1] = 0x04;
2344 name_len2 =
2345 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2346 toName, PATH_MAX, nls_codepage, remap);
2347 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2348 name_len2 *= 2; /* convert to bytes */
2349 } else { /* BB improve the check for buffer overruns BB */
2350 name_len = strnlen(fromName, PATH_MAX);
2351 name_len++; /* trailing null */
2352 strncpy(pSMB->OldFileName, fromName, name_len);
2353 name_len2 = strnlen(toName, PATH_MAX);
2354 name_len2++; /* trailing null */
2355 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2356 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2357 name_len2++; /* trailing null */
2358 name_len2++; /* signature byte */
2361 count = 1 /* string type byte */ + name_len + name_len2;
2362 pSMB->hdr.smb_buf_length += count;
2363 pSMB->ByteCount = cpu_to_le16(count);
2365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2366 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2367 cifs_stats_inc(&tcon->num_hardlinks);
2368 if (rc)
2369 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2371 cifs_buf_release(pSMB);
2372 if (rc == -EAGAIN)
2373 goto winCreateHardLinkRetry;
2375 return rc;
2379 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2380 const unsigned char *searchName,
2381 char *symlinkinfo, const int buflen,
2382 const struct nls_table *nls_codepage)
2384 /* SMB_QUERY_FILE_UNIX_LINK */
2385 TRANSACTION2_QPI_REQ *pSMB = NULL;
2386 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2387 int rc = 0;
2388 int bytes_returned;
2389 int name_len;
2390 __u16 params, byte_count;
2392 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2394 querySymLinkRetry:
2395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2396 (void **) &pSMBr);
2397 if (rc)
2398 return rc;
2400 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2401 name_len =
2402 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2403 PATH_MAX, nls_codepage);
2404 name_len++; /* trailing null */
2405 name_len *= 2;
2406 } else { /* BB improve the check for buffer overruns BB */
2407 name_len = strnlen(searchName, PATH_MAX);
2408 name_len++; /* trailing null */
2409 strncpy(pSMB->FileName, searchName, name_len);
2412 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2413 pSMB->TotalDataCount = 0;
2414 pSMB->MaxParameterCount = cpu_to_le16(2);
2415 /* BB find exact max data count below from sess structure BB */
2416 pSMB->MaxDataCount = cpu_to_le16(4000);
2417 pSMB->MaxSetupCount = 0;
2418 pSMB->Reserved = 0;
2419 pSMB->Flags = 0;
2420 pSMB->Timeout = 0;
2421 pSMB->Reserved2 = 0;
2422 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2423 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2424 pSMB->DataCount = 0;
2425 pSMB->DataOffset = 0;
2426 pSMB->SetupCount = 1;
2427 pSMB->Reserved3 = 0;
2428 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2429 byte_count = params + 1 /* pad */ ;
2430 pSMB->TotalParameterCount = cpu_to_le16(params);
2431 pSMB->ParameterCount = pSMB->TotalParameterCount;
2432 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2433 pSMB->Reserved4 = 0;
2434 pSMB->hdr.smb_buf_length += byte_count;
2435 pSMB->ByteCount = cpu_to_le16(byte_count);
2437 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2439 if (rc) {
2440 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2441 } else {
2442 /* decode response */
2444 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2445 if (rc || (pSMBr->ByteCount < 2))
2446 /* BB also check enough total bytes returned */
2447 rc = -EIO; /* bad smb */
2448 else {
2449 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2450 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2452 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2453 name_len = UniStrnlen((wchar_t *) ((char *)
2454 &pSMBr->hdr.Protocol + data_offset),
2455 min_t(const int, buflen, count) / 2);
2456 /* BB FIXME investigate remapping reserved chars here */
2457 cifs_strfromUCS_le(symlinkinfo,
2458 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2459 + data_offset),
2460 name_len, nls_codepage);
2461 } else {
2462 strncpy(symlinkinfo,
2463 (char *) &pSMBr->hdr.Protocol +
2464 data_offset,
2465 min_t(const int, buflen, count));
2467 symlinkinfo[buflen] = 0;
2468 /* just in case so calling code does not go off the end of buffer */
2471 cifs_buf_release(pSMB);
2472 if (rc == -EAGAIN)
2473 goto querySymLinkRetry;
2474 return rc;
2477 #ifdef CONFIG_CIFS_EXPERIMENTAL
2478 /* Initialize NT TRANSACT SMB into small smb request buffer.
2479 This assumes that all NT TRANSACTS that we init here have
2480 total parm and data under about 400 bytes (to fit in small cifs
2481 buffer size), which is the case so far, it easily fits. NB:
2482 Setup words themselves and ByteCount
2483 MaxSetupCount (size of returned setup area) and
2484 MaxParameterCount (returned parms size) must be set by caller */
2485 static int
2486 smb_init_nttransact(const __u16 sub_command, const int setup_count,
2487 const int parm_len, struct cifsTconInfo *tcon,
2488 void **ret_buf)
2490 int rc;
2491 __u32 temp_offset;
2492 struct smb_com_ntransact_req *pSMB;
2494 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2495 (void **)&pSMB);
2496 if (rc)
2497 return rc;
2498 *ret_buf = (void *)pSMB;
2499 pSMB->Reserved = 0;
2500 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2501 pSMB->TotalDataCount = 0;
2502 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2503 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2504 pSMB->ParameterCount = pSMB->TotalParameterCount;
2505 pSMB->DataCount = pSMB->TotalDataCount;
2506 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2507 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2508 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2509 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2510 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2511 pSMB->SubCommand = cpu_to_le16(sub_command);
2512 return 0;
2515 static int
2516 validate_ntransact(char *buf, char **ppparm, char **ppdata,
2517 __u32 *pparmlen, __u32 *pdatalen)
2519 char *end_of_smb;
2520 __u32 data_count, data_offset, parm_count, parm_offset;
2521 struct smb_com_ntransact_rsp *pSMBr;
2523 *pdatalen = 0;
2524 *pparmlen = 0;
2526 if (buf == NULL)
2527 return -EINVAL;
2529 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2531 /* ByteCount was converted from little endian in SendReceive */
2532 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2533 (char *)&pSMBr->ByteCount;
2535 data_offset = le32_to_cpu(pSMBr->DataOffset);
2536 data_count = le32_to_cpu(pSMBr->DataCount);
2537 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2538 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2540 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2541 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2543 /* should we also check that parm and data areas do not overlap? */
2544 if (*ppparm > end_of_smb) {
2545 cFYI(1, ("parms start after end of smb"));
2546 return -EINVAL;
2547 } else if (parm_count + *ppparm > end_of_smb) {
2548 cFYI(1, ("parm end after end of smb"));
2549 return -EINVAL;
2550 } else if (*ppdata > end_of_smb) {
2551 cFYI(1, ("data starts after end of smb"));
2552 return -EINVAL;
2553 } else if (data_count + *ppdata > end_of_smb) {
2554 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
2555 *ppdata, data_count, (data_count + *ppdata),
2556 end_of_smb, pSMBr));
2557 return -EINVAL;
2558 } else if (parm_count + data_count > pSMBr->ByteCount) {
2559 cFYI(1, ("parm count and data count larger than SMB"));
2560 return -EINVAL;
2562 *pdatalen = data_count;
2563 *pparmlen = parm_count;
2564 return 0;
2566 #endif /* CIFS_EXPERIMENTAL */
2569 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2570 const unsigned char *searchName,
2571 char *symlinkinfo, const int buflen, __u16 fid,
2572 const struct nls_table *nls_codepage)
2574 int rc = 0;
2575 int bytes_returned;
2576 int name_len;
2577 struct smb_com_transaction_ioctl_req *pSMB;
2578 struct smb_com_transaction_ioctl_rsp *pSMBr;
2580 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2581 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2582 (void **) &pSMBr);
2583 if (rc)
2584 return rc;
2586 pSMB->TotalParameterCount = 0 ;
2587 pSMB->TotalDataCount = 0;
2588 pSMB->MaxParameterCount = cpu_to_le32(2);
2589 /* BB find exact data count max from sess structure BB */
2590 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2591 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2592 pSMB->MaxSetupCount = 4;
2593 pSMB->Reserved = 0;
2594 pSMB->ParameterOffset = 0;
2595 pSMB->DataCount = 0;
2596 pSMB->DataOffset = 0;
2597 pSMB->SetupCount = 4;
2598 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2599 pSMB->ParameterCount = pSMB->TotalParameterCount;
2600 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2601 pSMB->IsFsctl = 1; /* FSCTL */
2602 pSMB->IsRootFlag = 0;
2603 pSMB->Fid = fid; /* file handle always le */
2604 pSMB->ByteCount = 0;
2606 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2607 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2608 if (rc) {
2609 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2610 } else { /* decode response */
2611 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2612 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2613 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2614 /* BB also check enough total bytes returned */
2615 rc = -EIO; /* bad smb */
2616 else {
2617 if (data_count && (data_count < 2048)) {
2618 char *end_of_smb = 2 /* sizeof byte count */ +
2619 pSMBr->ByteCount +
2620 (char *)&pSMBr->ByteCount;
2622 struct reparse_data *reparse_buf =
2623 (struct reparse_data *)
2624 ((char *)&pSMBr->hdr.Protocol
2625 + data_offset);
2626 if ((char *)reparse_buf >= end_of_smb) {
2627 rc = -EIO;
2628 goto qreparse_out;
2630 if ((reparse_buf->LinkNamesBuf +
2631 reparse_buf->TargetNameOffset +
2632 reparse_buf->TargetNameLen) >
2633 end_of_smb) {
2634 cFYI(1, ("reparse buf beyond SMB"));
2635 rc = -EIO;
2636 goto qreparse_out;
2639 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2640 name_len = UniStrnlen((wchar_t *)
2641 (reparse_buf->LinkNamesBuf +
2642 reparse_buf->TargetNameOffset),
2643 min(buflen/2,
2644 reparse_buf->TargetNameLen / 2));
2645 cifs_strfromUCS_le(symlinkinfo,
2646 (__le16 *) (reparse_buf->LinkNamesBuf +
2647 reparse_buf->TargetNameOffset),
2648 name_len, nls_codepage);
2649 } else { /* ASCII names */
2650 strncpy(symlinkinfo,
2651 reparse_buf->LinkNamesBuf +
2652 reparse_buf->TargetNameOffset,
2653 min_t(const int, buflen,
2654 reparse_buf->TargetNameLen));
2656 } else {
2657 rc = -EIO;
2658 cFYI(1, ("Invalid return data count on "
2659 "get reparse info ioctl"));
2661 symlinkinfo[buflen] = 0; /* just in case so the caller
2662 does not go off the end of the buffer */
2663 cFYI(1, ("readlink result - %s", symlinkinfo));
2666 qreparse_out:
2667 cifs_buf_release(pSMB);
2669 /* Note: On -EAGAIN error only caller can retry on handle based calls
2670 since file handle passed in no longer valid */
2672 return rc;
2675 #ifdef CONFIG_CIFS_POSIX
2677 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2678 static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2679 struct cifs_posix_ace *cifs_ace)
2681 /* u8 cifs fields do not need le conversion */
2682 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2683 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2684 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2685 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2687 return;
2690 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2691 static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2692 const int acl_type, const int size_of_data_area)
2694 int size = 0;
2695 int i;
2696 __u16 count;
2697 struct cifs_posix_ace *pACE;
2698 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2699 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2701 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2702 return -EOPNOTSUPP;
2704 if (acl_type & ACL_TYPE_ACCESS) {
2705 count = le16_to_cpu(cifs_acl->access_entry_count);
2706 pACE = &cifs_acl->ace_array[0];
2707 size = sizeof(struct cifs_posix_acl);
2708 size += sizeof(struct cifs_posix_ace) * count;
2709 /* check if we would go beyond end of SMB */
2710 if (size_of_data_area < size) {
2711 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2712 size_of_data_area, size));
2713 return -EINVAL;
2715 } else if (acl_type & ACL_TYPE_DEFAULT) {
2716 count = le16_to_cpu(cifs_acl->access_entry_count);
2717 size = sizeof(struct cifs_posix_acl);
2718 size += sizeof(struct cifs_posix_ace) * count;
2719 /* skip past access ACEs to get to default ACEs */
2720 pACE = &cifs_acl->ace_array[count];
2721 count = le16_to_cpu(cifs_acl->default_entry_count);
2722 size += sizeof(struct cifs_posix_ace) * count;
2723 /* check if we would go beyond end of SMB */
2724 if (size_of_data_area < size)
2725 return -EINVAL;
2726 } else {
2727 /* illegal type */
2728 return -EINVAL;
2731 size = posix_acl_xattr_size(count);
2732 if ((buflen == 0) || (local_acl == NULL)) {
2733 /* used to query ACL EA size */
2734 } else if (size > buflen) {
2735 return -ERANGE;
2736 } else /* buffer big enough */ {
2737 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2738 for (i = 0; i < count ; i++) {
2739 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2740 pACE++;
2743 return size;
2746 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2747 const posix_acl_xattr_entry *local_ace)
2749 __u16 rc = 0; /* 0 = ACL converted ok */
2751 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2752 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2753 /* BB is there a better way to handle the large uid? */
2754 if (local_ace->e_id == cpu_to_le32(-1)) {
2755 /* Probably no need to le convert -1 on any arch but can not hurt */
2756 cifs_ace->cifs_uid = cpu_to_le64(-1);
2757 } else
2758 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2759 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2760 return rc;
2763 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2764 static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2765 const int buflen, const int acl_type)
2767 __u16 rc = 0;
2768 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2769 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2770 int count;
2771 int i;
2773 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2774 return 0;
2776 count = posix_acl_xattr_count((size_t)buflen);
2777 cFYI(1, ("setting acl with %d entries from buf of length %d and "
2778 "version of %d",
2779 count, buflen, le32_to_cpu(local_acl->a_version)));
2780 if (le32_to_cpu(local_acl->a_version) != 2) {
2781 cFYI(1, ("unknown POSIX ACL version %d",
2782 le32_to_cpu(local_acl->a_version)));
2783 return 0;
2785 cifs_acl->version = cpu_to_le16(1);
2786 if (acl_type == ACL_TYPE_ACCESS)
2787 cifs_acl->access_entry_count = cpu_to_le16(count);
2788 else if (acl_type == ACL_TYPE_DEFAULT)
2789 cifs_acl->default_entry_count = cpu_to_le16(count);
2790 else {
2791 cFYI(1, ("unknown ACL type %d", acl_type));
2792 return 0;
2794 for (i = 0; i < count; i++) {
2795 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2796 &local_acl->a_entries[i]);
2797 if (rc != 0) {
2798 /* ACE not converted */
2799 break;
2802 if (rc == 0) {
2803 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2804 rc += sizeof(struct cifs_posix_acl);
2805 /* BB add check to make sure ACL does not overflow SMB */
2807 return rc;
2811 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2812 const unsigned char *searchName,
2813 char *acl_inf, const int buflen, const int acl_type,
2814 const struct nls_table *nls_codepage, int remap)
2816 /* SMB_QUERY_POSIX_ACL */
2817 TRANSACTION2_QPI_REQ *pSMB = NULL;
2818 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2819 int rc = 0;
2820 int bytes_returned;
2821 int name_len;
2822 __u16 params, byte_count;
2824 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2826 queryAclRetry:
2827 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2828 (void **) &pSMBr);
2829 if (rc)
2830 return rc;
2832 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2833 name_len =
2834 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2835 PATH_MAX, nls_codepage, remap);
2836 name_len++; /* trailing null */
2837 name_len *= 2;
2838 pSMB->FileName[name_len] = 0;
2839 pSMB->FileName[name_len+1] = 0;
2840 } else { /* BB improve the check for buffer overruns BB */
2841 name_len = strnlen(searchName, PATH_MAX);
2842 name_len++; /* trailing null */
2843 strncpy(pSMB->FileName, searchName, name_len);
2846 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2847 pSMB->TotalDataCount = 0;
2848 pSMB->MaxParameterCount = cpu_to_le16(2);
2849 /* BB find exact max data count below from sess structure BB */
2850 pSMB->MaxDataCount = cpu_to_le16(4000);
2851 pSMB->MaxSetupCount = 0;
2852 pSMB->Reserved = 0;
2853 pSMB->Flags = 0;
2854 pSMB->Timeout = 0;
2855 pSMB->Reserved2 = 0;
2856 pSMB->ParameterOffset = cpu_to_le16(
2857 offsetof(struct smb_com_transaction2_qpi_req,
2858 InformationLevel) - 4);
2859 pSMB->DataCount = 0;
2860 pSMB->DataOffset = 0;
2861 pSMB->SetupCount = 1;
2862 pSMB->Reserved3 = 0;
2863 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2864 byte_count = params + 1 /* pad */ ;
2865 pSMB->TotalParameterCount = cpu_to_le16(params);
2866 pSMB->ParameterCount = pSMB->TotalParameterCount;
2867 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2868 pSMB->Reserved4 = 0;
2869 pSMB->hdr.smb_buf_length += byte_count;
2870 pSMB->ByteCount = cpu_to_le16(byte_count);
2872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2874 cifs_stats_inc(&tcon->num_acl_get);
2875 if (rc) {
2876 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2877 } else {
2878 /* decode response */
2880 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2881 if (rc || (pSMBr->ByteCount < 2))
2882 /* BB also check enough total bytes returned */
2883 rc = -EIO; /* bad smb */
2884 else {
2885 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2886 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2887 rc = cifs_copy_posix_acl(acl_inf,
2888 (char *)&pSMBr->hdr.Protocol+data_offset,
2889 buflen, acl_type, count);
2892 cifs_buf_release(pSMB);
2893 if (rc == -EAGAIN)
2894 goto queryAclRetry;
2895 return rc;
2899 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2900 const unsigned char *fileName,
2901 const char *local_acl, const int buflen,
2902 const int acl_type,
2903 const struct nls_table *nls_codepage, int remap)
2905 struct smb_com_transaction2_spi_req *pSMB = NULL;
2906 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2907 char *parm_data;
2908 int name_len;
2909 int rc = 0;
2910 int bytes_returned = 0;
2911 __u16 params, byte_count, data_count, param_offset, offset;
2913 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2914 setAclRetry:
2915 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2916 (void **) &pSMBr);
2917 if (rc)
2918 return rc;
2919 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2920 name_len =
2921 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2922 PATH_MAX, nls_codepage, remap);
2923 name_len++; /* trailing null */
2924 name_len *= 2;
2925 } else { /* BB improve the check for buffer overruns BB */
2926 name_len = strnlen(fileName, PATH_MAX);
2927 name_len++; /* trailing null */
2928 strncpy(pSMB->FileName, fileName, name_len);
2930 params = 6 + name_len;
2931 pSMB->MaxParameterCount = cpu_to_le16(2);
2932 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2933 pSMB->MaxSetupCount = 0;
2934 pSMB->Reserved = 0;
2935 pSMB->Flags = 0;
2936 pSMB->Timeout = 0;
2937 pSMB->Reserved2 = 0;
2938 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2939 InformationLevel) - 4;
2940 offset = param_offset + params;
2941 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2942 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2944 /* convert to on the wire format for POSIX ACL */
2945 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2947 if (data_count == 0) {
2948 rc = -EOPNOTSUPP;
2949 goto setACLerrorExit;
2951 pSMB->DataOffset = cpu_to_le16(offset);
2952 pSMB->SetupCount = 1;
2953 pSMB->Reserved3 = 0;
2954 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2955 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2956 byte_count = 3 /* pad */ + params + data_count;
2957 pSMB->DataCount = cpu_to_le16(data_count);
2958 pSMB->TotalDataCount = pSMB->DataCount;
2959 pSMB->ParameterCount = cpu_to_le16(params);
2960 pSMB->TotalParameterCount = pSMB->ParameterCount;
2961 pSMB->Reserved4 = 0;
2962 pSMB->hdr.smb_buf_length += byte_count;
2963 pSMB->ByteCount = cpu_to_le16(byte_count);
2964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2966 if (rc)
2967 cFYI(1, ("Set POSIX ACL returned %d", rc));
2969 setACLerrorExit:
2970 cifs_buf_release(pSMB);
2971 if (rc == -EAGAIN)
2972 goto setAclRetry;
2973 return rc;
2976 /* BB fix tabs in this function FIXME BB */
2978 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2979 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
2981 int rc = 0;
2982 struct smb_t2_qfi_req *pSMB = NULL;
2983 struct smb_t2_qfi_rsp *pSMBr = NULL;
2984 int bytes_returned;
2985 __u16 params, byte_count;
2987 cFYI(1, ("In GetExtAttr"));
2988 if (tcon == NULL)
2989 return -ENODEV;
2991 GetExtAttrRetry:
2992 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2993 (void **) &pSMBr);
2994 if (rc)
2995 return rc;
2997 params = 2 /* level */ + 2 /* fid */;
2998 pSMB->t2.TotalDataCount = 0;
2999 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3000 /* BB find exact max data count below from sess structure BB */
3001 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3002 pSMB->t2.MaxSetupCount = 0;
3003 pSMB->t2.Reserved = 0;
3004 pSMB->t2.Flags = 0;
3005 pSMB->t2.Timeout = 0;
3006 pSMB->t2.Reserved2 = 0;
3007 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3008 Fid) - 4);
3009 pSMB->t2.DataCount = 0;
3010 pSMB->t2.DataOffset = 0;
3011 pSMB->t2.SetupCount = 1;
3012 pSMB->t2.Reserved3 = 0;
3013 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3014 byte_count = params + 1 /* pad */ ;
3015 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3016 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3017 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3018 pSMB->Pad = 0;
3019 pSMB->Fid = netfid;
3020 pSMB->hdr.smb_buf_length += byte_count;
3021 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3023 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3024 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3025 if (rc) {
3026 cFYI(1, ("error %d in GetExtAttr", rc));
3027 } else {
3028 /* decode response */
3029 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3030 if (rc || (pSMBr->ByteCount < 2))
3031 /* BB also check enough total bytes returned */
3032 /* If rc should we check for EOPNOSUPP and
3033 disable the srvino flag? or in caller? */
3034 rc = -EIO; /* bad smb */
3035 else {
3036 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3037 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3038 struct file_chattr_info *pfinfo;
3039 /* BB Do we need a cast or hash here ? */
3040 if (count != 16) {
3041 cFYI(1, ("Illegal size ret in GetExtAttr"));
3042 rc = -EIO;
3043 goto GetExtAttrOut;
3045 pfinfo = (struct file_chattr_info *)
3046 (data_offset + (char *) &pSMBr->hdr.Protocol);
3047 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3048 *pMask = le64_to_cpu(pfinfo->mask);
3051 GetExtAttrOut:
3052 cifs_buf_release(pSMB);
3053 if (rc == -EAGAIN)
3054 goto GetExtAttrRetry;
3055 return rc;
3058 #endif /* CONFIG_POSIX */
3060 #ifdef CONFIG_CIFS_EXPERIMENTAL
3061 /* Get Security Descriptor (by handle) from remote server for a file or dir */
3063 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3064 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3066 int rc = 0;
3067 int buf_type = 0;
3068 QUERY_SEC_DESC_REQ *pSMB;
3069 struct kvec iov[1];
3071 cFYI(1, ("GetCifsACL"));
3073 *pbuflen = 0;
3074 *acl_inf = NULL;
3076 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3077 8 /* parm len */, tcon, (void **) &pSMB);
3078 if (rc)
3079 return rc;
3081 pSMB->MaxParameterCount = cpu_to_le32(4);
3082 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3083 pSMB->MaxSetupCount = 0;
3084 pSMB->Fid = fid; /* file handle always le */
3085 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3086 CIFS_ACL_DACL);
3087 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3088 pSMB->hdr.smb_buf_length += 11;
3089 iov[0].iov_base = (char *)pSMB;
3090 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3092 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3093 CIFS_STD_OP);
3094 cifs_stats_inc(&tcon->num_acl_get);
3095 if (rc) {
3096 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3097 } else { /* decode response */
3098 __le32 *parm;
3099 __u32 parm_len;
3100 __u32 acl_len;
3101 struct smb_com_ntransact_rsp *pSMBr;
3102 char *pdata;
3104 /* validate_nttransact */
3105 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3106 &pdata, &parm_len, pbuflen);
3107 if (rc)
3108 goto qsec_out;
3109 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3111 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
3113 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3114 rc = -EIO; /* bad smb */
3115 *pbuflen = 0;
3116 goto qsec_out;
3119 /* BB check that data area is minimum length and as big as acl_len */
3121 acl_len = le32_to_cpu(*parm);
3122 if (acl_len != *pbuflen) {
3123 cERROR(1, ("acl length %d does not match %d",
3124 acl_len, *pbuflen));
3125 if (*pbuflen > acl_len)
3126 *pbuflen = acl_len;
3129 /* check if buffer is big enough for the acl
3130 header followed by the smallest SID */
3131 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3132 (*pbuflen >= 64 * 1024)) {
3133 cERROR(1, ("bad acl length %d", *pbuflen));
3134 rc = -EINVAL;
3135 *pbuflen = 0;
3136 } else {
3137 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3138 if (*acl_inf == NULL) {
3139 *pbuflen = 0;
3140 rc = -ENOMEM;
3142 memcpy(*acl_inf, pdata, *pbuflen);
3145 qsec_out:
3146 if (buf_type == CIFS_SMALL_BUFFER)
3147 cifs_small_buf_release(iov[0].iov_base);
3148 else if (buf_type == CIFS_LARGE_BUFFER)
3149 cifs_buf_release(iov[0].iov_base);
3150 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3151 return rc;
3155 CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3156 struct cifs_ntsd *pntsd, __u32 acllen)
3158 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3159 int rc = 0;
3160 int bytes_returned = 0;
3161 SET_SEC_DESC_REQ *pSMB = NULL;
3162 NTRANSACT_RSP *pSMBr = NULL;
3164 setCifsAclRetry:
3165 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3166 (void **) &pSMBr);
3167 if (rc)
3168 return (rc);
3170 pSMB->MaxSetupCount = 0;
3171 pSMB->Reserved = 0;
3173 param_count = 8;
3174 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3175 data_count = acllen;
3176 data_offset = param_offset + param_count;
3177 byte_count = 3 /* pad */ + param_count;
3179 pSMB->DataCount = cpu_to_le32(data_count);
3180 pSMB->TotalDataCount = pSMB->DataCount;
3181 pSMB->MaxParameterCount = cpu_to_le32(4);
3182 pSMB->MaxDataCount = cpu_to_le32(16384);
3183 pSMB->ParameterCount = cpu_to_le32(param_count);
3184 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3185 pSMB->TotalParameterCount = pSMB->ParameterCount;
3186 pSMB->DataOffset = cpu_to_le32(data_offset);
3187 pSMB->SetupCount = 0;
3188 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3189 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3191 pSMB->Fid = fid; /* file handle always le */
3192 pSMB->Reserved2 = 0;
3193 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3195 if (pntsd && acllen) {
3196 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3197 (char *) pntsd,
3198 acllen);
3199 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3201 } else
3202 pSMB->hdr.smb_buf_length += byte_count;
3204 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3205 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3207 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3208 if (rc)
3209 cFYI(1, ("Set CIFS ACL returned %d", rc));
3210 cifs_buf_release(pSMB);
3212 if (rc == -EAGAIN)
3213 goto setCifsAclRetry;
3215 return (rc);
3218 #endif /* CONFIG_CIFS_EXPERIMENTAL */
3220 /* Legacy Query Path Information call for lookup to old servers such
3221 as Win9x/WinME */
3222 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3223 const unsigned char *searchName,
3224 FILE_ALL_INFO *pFinfo,
3225 const struct nls_table *nls_codepage, int remap)
3227 QUERY_INFORMATION_REQ *pSMB;
3228 QUERY_INFORMATION_RSP *pSMBr;
3229 int rc = 0;
3230 int bytes_returned;
3231 int name_len;
3233 cFYI(1, ("In SMBQPath path %s", searchName));
3234 QInfRetry:
3235 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3236 (void **) &pSMBr);
3237 if (rc)
3238 return rc;
3240 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3241 name_len =
3242 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3243 PATH_MAX, nls_codepage, remap);
3244 name_len++; /* trailing null */
3245 name_len *= 2;
3246 } else {
3247 name_len = strnlen(searchName, PATH_MAX);
3248 name_len++; /* trailing null */
3249 strncpy(pSMB->FileName, searchName, name_len);
3251 pSMB->BufferFormat = 0x04;
3252 name_len++; /* account for buffer type byte */
3253 pSMB->hdr.smb_buf_length += (__u16) name_len;
3254 pSMB->ByteCount = cpu_to_le16(name_len);
3256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3258 if (rc) {
3259 cFYI(1, ("Send error in QueryInfo = %d", rc));
3260 } else if (pFinfo) {
3261 struct timespec ts;
3262 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3264 /* decode response */
3265 /* BB FIXME - add time zone adjustment BB */
3266 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3267 ts.tv_nsec = 0;
3268 ts.tv_sec = time;
3269 /* decode time fields */
3270 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3271 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3272 pFinfo->LastAccessTime = 0;
3273 pFinfo->AllocationSize =
3274 cpu_to_le64(le32_to_cpu(pSMBr->size));
3275 pFinfo->EndOfFile = pFinfo->AllocationSize;
3276 pFinfo->Attributes =
3277 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3278 } else
3279 rc = -EIO; /* bad buffer passed in */
3281 cifs_buf_release(pSMB);
3283 if (rc == -EAGAIN)
3284 goto QInfRetry;
3286 return rc;
3293 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3294 const unsigned char *searchName,
3295 FILE_ALL_INFO *pFindData,
3296 int legacy /* old style infolevel */,
3297 const struct nls_table *nls_codepage, int remap)
3299 /* level 263 SMB_QUERY_FILE_ALL_INFO */
3300 TRANSACTION2_QPI_REQ *pSMB = NULL;
3301 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3302 int rc = 0;
3303 int bytes_returned;
3304 int name_len;
3305 __u16 params, byte_count;
3307 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
3308 QPathInfoRetry:
3309 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3310 (void **) &pSMBr);
3311 if (rc)
3312 return rc;
3314 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3315 name_len =
3316 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3317 PATH_MAX, nls_codepage, remap);
3318 name_len++; /* trailing null */
3319 name_len *= 2;
3320 } else { /* BB improve the check for buffer overruns BB */
3321 name_len = strnlen(searchName, PATH_MAX);
3322 name_len++; /* trailing null */
3323 strncpy(pSMB->FileName, searchName, name_len);
3326 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3327 pSMB->TotalDataCount = 0;
3328 pSMB->MaxParameterCount = cpu_to_le16(2);
3329 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3330 pSMB->MaxSetupCount = 0;
3331 pSMB->Reserved = 0;
3332 pSMB->Flags = 0;
3333 pSMB->Timeout = 0;
3334 pSMB->Reserved2 = 0;
3335 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3336 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3337 pSMB->DataCount = 0;
3338 pSMB->DataOffset = 0;
3339 pSMB->SetupCount = 1;
3340 pSMB->Reserved3 = 0;
3341 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3342 byte_count = params + 1 /* pad */ ;
3343 pSMB->TotalParameterCount = cpu_to_le16(params);
3344 pSMB->ParameterCount = pSMB->TotalParameterCount;
3345 if (legacy)
3346 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3347 else
3348 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3349 pSMB->Reserved4 = 0;
3350 pSMB->hdr.smb_buf_length += byte_count;
3351 pSMB->ByteCount = cpu_to_le16(byte_count);
3353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3355 if (rc) {
3356 cFYI(1, ("Send error in QPathInfo = %d", rc));
3357 } else { /* decode response */
3358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3360 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3361 rc = -EIO;
3362 else if (!legacy && (pSMBr->ByteCount < 40))
3363 rc = -EIO; /* bad smb */
3364 else if (legacy && (pSMBr->ByteCount < 24))
3365 rc = -EIO; /* 24 or 26 expected but we do not read
3366 last field */
3367 else if (pFindData) {
3368 int size;
3369 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3371 /* On legacy responses we do not read the last field,
3372 EAsize, fortunately since it varies by subdialect and
3373 also note it differs on Set vs. Get, ie two bytes or 4
3374 bytes depending but we don't care here */
3375 if (legacy)
3376 size = sizeof(FILE_INFO_STANDARD);
3377 else
3378 size = sizeof(FILE_ALL_INFO);
3379 memcpy((char *) pFindData,
3380 (char *) &pSMBr->hdr.Protocol +
3381 data_offset, size);
3382 } else
3383 rc = -ENOMEM;
3385 cifs_buf_release(pSMB);
3386 if (rc == -EAGAIN)
3387 goto QPathInfoRetry;
3389 return rc;
3393 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3394 const unsigned char *searchName,
3395 FILE_UNIX_BASIC_INFO * pFindData,
3396 const struct nls_table *nls_codepage, int remap)
3398 /* SMB_QUERY_FILE_UNIX_BASIC */
3399 TRANSACTION2_QPI_REQ *pSMB = NULL;
3400 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3401 int rc = 0;
3402 int bytes_returned = 0;
3403 int name_len;
3404 __u16 params, byte_count;
3406 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3407 UnixQPathInfoRetry:
3408 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3409 (void **) &pSMBr);
3410 if (rc)
3411 return rc;
3413 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3414 name_len =
3415 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3416 PATH_MAX, nls_codepage, remap);
3417 name_len++; /* trailing null */
3418 name_len *= 2;
3419 } else { /* BB improve the check for buffer overruns BB */
3420 name_len = strnlen(searchName, PATH_MAX);
3421 name_len++; /* trailing null */
3422 strncpy(pSMB->FileName, searchName, name_len);
3425 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3426 pSMB->TotalDataCount = 0;
3427 pSMB->MaxParameterCount = cpu_to_le16(2);
3428 /* BB find exact max SMB PDU from sess structure BB */
3429 pSMB->MaxDataCount = cpu_to_le16(4000);
3430 pSMB->MaxSetupCount = 0;
3431 pSMB->Reserved = 0;
3432 pSMB->Flags = 0;
3433 pSMB->Timeout = 0;
3434 pSMB->Reserved2 = 0;
3435 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3436 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3437 pSMB->DataCount = 0;
3438 pSMB->DataOffset = 0;
3439 pSMB->SetupCount = 1;
3440 pSMB->Reserved3 = 0;
3441 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3442 byte_count = params + 1 /* pad */ ;
3443 pSMB->TotalParameterCount = cpu_to_le16(params);
3444 pSMB->ParameterCount = pSMB->TotalParameterCount;
3445 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3446 pSMB->Reserved4 = 0;
3447 pSMB->hdr.smb_buf_length += byte_count;
3448 pSMB->ByteCount = cpu_to_le16(byte_count);
3450 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3451 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3452 if (rc) {
3453 cFYI(1, ("Send error in QPathInfo = %d", rc));
3454 } else { /* decode response */
3455 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3457 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3458 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3459 "Unix Extensions can be disabled on mount "
3460 "by specifying the nosfu mount option."));
3461 rc = -EIO; /* bad smb */
3462 } else {
3463 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3464 memcpy((char *) pFindData,
3465 (char *) &pSMBr->hdr.Protocol +
3466 data_offset,
3467 sizeof(FILE_UNIX_BASIC_INFO));
3470 cifs_buf_release(pSMB);
3471 if (rc == -EAGAIN)
3472 goto UnixQPathInfoRetry;
3474 return rc;
3477 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3479 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3480 const char *searchName,
3481 const struct nls_table *nls_codepage,
3482 __u16 *pnetfid,
3483 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3485 /* level 257 SMB_ */
3486 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3487 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3488 T2_FFIRST_RSP_PARMS *parms;
3489 int rc = 0;
3490 int bytes_returned = 0;
3491 int name_len;
3492 __u16 params, byte_count;
3494 cFYI(1, ("In FindFirst for %s", searchName));
3496 findFirstRetry:
3497 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3498 (void **) &pSMBr);
3499 if (rc)
3500 return rc;
3502 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3503 name_len =
3504 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3505 PATH_MAX, nls_codepage, remap);
3506 /* We can not add the asterik earlier in case
3507 it got remapped to 0xF03A as if it were part of the
3508 directory name instead of a wildcard */
3509 name_len *= 2;
3510 pSMB->FileName[name_len] = dirsep;
3511 pSMB->FileName[name_len+1] = 0;
3512 pSMB->FileName[name_len+2] = '*';
3513 pSMB->FileName[name_len+3] = 0;
3514 name_len += 4; /* now the trailing null */
3515 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3516 pSMB->FileName[name_len+1] = 0;
3517 name_len += 2;
3518 } else { /* BB add check for overrun of SMB buf BB */
3519 name_len = strnlen(searchName, PATH_MAX);
3520 /* BB fix here and in unicode clause above ie
3521 if (name_len > buffersize-header)
3522 free buffer exit; BB */
3523 strncpy(pSMB->FileName, searchName, name_len);
3524 pSMB->FileName[name_len] = dirsep;
3525 pSMB->FileName[name_len+1] = '*';
3526 pSMB->FileName[name_len+2] = 0;
3527 name_len += 3;
3530 params = 12 + name_len /* includes null */ ;
3531 pSMB->TotalDataCount = 0; /* no EAs */
3532 pSMB->MaxParameterCount = cpu_to_le16(10);
3533 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3534 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3535 pSMB->MaxSetupCount = 0;
3536 pSMB->Reserved = 0;
3537 pSMB->Flags = 0;
3538 pSMB->Timeout = 0;
3539 pSMB->Reserved2 = 0;
3540 byte_count = params + 1 /* pad */ ;
3541 pSMB->TotalParameterCount = cpu_to_le16(params);
3542 pSMB->ParameterCount = pSMB->TotalParameterCount;
3543 pSMB->ParameterOffset = cpu_to_le16(
3544 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3545 - 4);
3546 pSMB->DataCount = 0;
3547 pSMB->DataOffset = 0;
3548 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3549 pSMB->Reserved3 = 0;
3550 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3551 pSMB->SearchAttributes =
3552 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3553 ATTR_DIRECTORY);
3554 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3555 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3556 CIFS_SEARCH_RETURN_RESUME);
3557 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3559 /* BB what should we set StorageType to? Does it matter? BB */
3560 pSMB->SearchStorageType = 0;
3561 pSMB->hdr.smb_buf_length += byte_count;
3562 pSMB->ByteCount = cpu_to_le16(byte_count);
3564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3566 cifs_stats_inc(&tcon->num_ffirst);
3568 if (rc) {/* BB add logic to retry regular search if Unix search
3569 rejected unexpectedly by server */
3570 /* BB Add code to handle unsupported level rc */
3571 cFYI(1, ("Error in FindFirst = %d", rc));
3573 cifs_buf_release(pSMB);
3575 /* BB eventually could optimize out free and realloc of buf */
3576 /* for this case */
3577 if (rc == -EAGAIN)
3578 goto findFirstRetry;
3579 } else { /* decode response */
3580 /* BB remember to free buffer if error BB */
3581 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3582 if (rc == 0) {
3583 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3584 psrch_inf->unicode = TRUE;
3585 else
3586 psrch_inf->unicode = FALSE;
3588 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3589 psrch_inf->smallBuf = 0;
3590 psrch_inf->srch_entries_start =
3591 (char *) &pSMBr->hdr.Protocol +
3592 le16_to_cpu(pSMBr->t2.DataOffset);
3593 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3594 le16_to_cpu(pSMBr->t2.ParameterOffset));
3596 if (parms->EndofSearch)
3597 psrch_inf->endOfSearch = TRUE;
3598 else
3599 psrch_inf->endOfSearch = FALSE;
3601 psrch_inf->entries_in_buffer =
3602 le16_to_cpu(parms->SearchCount);
3603 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3604 psrch_inf->entries_in_buffer;
3605 *pnetfid = parms->SearchHandle;
3606 } else {
3607 cifs_buf_release(pSMB);
3611 return rc;
3614 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3615 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3617 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3618 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3619 T2_FNEXT_RSP_PARMS *parms;
3620 char *response_data;
3621 int rc = 0;
3622 int bytes_returned, name_len;
3623 __u16 params, byte_count;
3625 cFYI(1, ("In FindNext"));
3627 if (psrch_inf->endOfSearch == TRUE)
3628 return -ENOENT;
3630 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3631 (void **) &pSMBr);
3632 if (rc)
3633 return rc;
3635 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3636 byte_count = 0;
3637 pSMB->TotalDataCount = 0; /* no EAs */
3638 pSMB->MaxParameterCount = cpu_to_le16(8);
3639 pSMB->MaxDataCount =
3640 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3641 0xFFFFFF00);
3642 pSMB->MaxSetupCount = 0;
3643 pSMB->Reserved = 0;
3644 pSMB->Flags = 0;
3645 pSMB->Timeout = 0;
3646 pSMB->Reserved2 = 0;
3647 pSMB->ParameterOffset = cpu_to_le16(
3648 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3649 pSMB->DataCount = 0;
3650 pSMB->DataOffset = 0;
3651 pSMB->SetupCount = 1;
3652 pSMB->Reserved3 = 0;
3653 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3654 pSMB->SearchHandle = searchHandle; /* always kept as le */
3655 pSMB->SearchCount =
3656 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
3657 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3658 pSMB->ResumeKey = psrch_inf->resume_key;
3659 pSMB->SearchFlags =
3660 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3662 name_len = psrch_inf->resume_name_len;
3663 params += name_len;
3664 if (name_len < PATH_MAX) {
3665 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3666 byte_count += name_len;
3667 /* 14 byte parm len above enough for 2 byte null terminator */
3668 pSMB->ResumeFileName[name_len] = 0;
3669 pSMB->ResumeFileName[name_len+1] = 0;
3670 } else {
3671 rc = -EINVAL;
3672 goto FNext2_err_exit;
3674 byte_count = params + 1 /* pad */ ;
3675 pSMB->TotalParameterCount = cpu_to_le16(params);
3676 pSMB->ParameterCount = pSMB->TotalParameterCount;
3677 pSMB->hdr.smb_buf_length += byte_count;
3678 pSMB->ByteCount = cpu_to_le16(byte_count);
3680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3682 cifs_stats_inc(&tcon->num_fnext);
3683 if (rc) {
3684 if (rc == -EBADF) {
3685 psrch_inf->endOfSearch = TRUE;
3686 rc = 0; /* search probably was closed at end of search*/
3687 } else
3688 cFYI(1, ("FindNext returned = %d", rc));
3689 } else { /* decode response */
3690 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3692 if (rc == 0) {
3693 /* BB fixme add lock for file (srch_info) struct here */
3694 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3695 psrch_inf->unicode = TRUE;
3696 else
3697 psrch_inf->unicode = FALSE;
3698 response_data = (char *) &pSMBr->hdr.Protocol +
3699 le16_to_cpu(pSMBr->t2.ParameterOffset);
3700 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3701 response_data = (char *)&pSMBr->hdr.Protocol +
3702 le16_to_cpu(pSMBr->t2.DataOffset);
3703 if (psrch_inf->smallBuf)
3704 cifs_small_buf_release(
3705 psrch_inf->ntwrk_buf_start);
3706 else
3707 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3708 psrch_inf->srch_entries_start = response_data;
3709 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3710 psrch_inf->smallBuf = 0;
3711 if (parms->EndofSearch)
3712 psrch_inf->endOfSearch = TRUE;
3713 else
3714 psrch_inf->endOfSearch = FALSE;
3715 psrch_inf->entries_in_buffer =
3716 le16_to_cpu(parms->SearchCount);
3717 psrch_inf->index_of_last_entry +=
3718 psrch_inf->entries_in_buffer;
3719 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3720 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3722 /* BB fixme add unlock here */
3727 /* BB On error, should we leave previous search buf (and count and
3728 last entry fields) intact or free the previous one? */
3730 /* Note: On -EAGAIN error only caller can retry on handle based calls
3731 since file handle passed in no longer valid */
3732 FNext2_err_exit:
3733 if (rc != 0)
3734 cifs_buf_release(pSMB);
3735 return rc;
3739 CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3740 const __u16 searchHandle)
3742 int rc = 0;
3743 FINDCLOSE_REQ *pSMB = NULL;
3745 cFYI(1, ("In CIFSSMBFindClose"));
3746 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3748 /* no sense returning error if session restarted
3749 as file handle has been closed */
3750 if (rc == -EAGAIN)
3751 return 0;
3752 if (rc)
3753 return rc;
3755 pSMB->FileID = searchHandle;
3756 pSMB->ByteCount = 0;
3757 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
3758 if (rc)
3759 cERROR(1, ("Send error in FindClose = %d", rc));
3761 cifs_stats_inc(&tcon->num_fclose);
3763 /* Since session is dead, search handle closed on server already */
3764 if (rc == -EAGAIN)
3765 rc = 0;
3767 return rc;
3771 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3772 const unsigned char *searchName,
3773 __u64 *inode_number,
3774 const struct nls_table *nls_codepage, int remap)
3776 int rc = 0;
3777 TRANSACTION2_QPI_REQ *pSMB = NULL;
3778 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3779 int name_len, bytes_returned;
3780 __u16 params, byte_count;
3782 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3783 if (tcon == NULL)
3784 return -ENODEV;
3786 GetInodeNumberRetry:
3787 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3788 (void **) &pSMBr);
3789 if (rc)
3790 return rc;
3792 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3793 name_len =
3794 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3795 PATH_MAX, nls_codepage, remap);
3796 name_len++; /* trailing null */
3797 name_len *= 2;
3798 } else { /* BB improve the check for buffer overruns BB */
3799 name_len = strnlen(searchName, PATH_MAX);
3800 name_len++; /* trailing null */
3801 strncpy(pSMB->FileName, searchName, name_len);
3804 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3805 pSMB->TotalDataCount = 0;
3806 pSMB->MaxParameterCount = cpu_to_le16(2);
3807 /* BB find exact max data count below from sess structure BB */
3808 pSMB->MaxDataCount = cpu_to_le16(4000);
3809 pSMB->MaxSetupCount = 0;
3810 pSMB->Reserved = 0;
3811 pSMB->Flags = 0;
3812 pSMB->Timeout = 0;
3813 pSMB->Reserved2 = 0;
3814 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3815 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3816 pSMB->DataCount = 0;
3817 pSMB->DataOffset = 0;
3818 pSMB->SetupCount = 1;
3819 pSMB->Reserved3 = 0;
3820 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3821 byte_count = params + 1 /* pad */ ;
3822 pSMB->TotalParameterCount = cpu_to_le16(params);
3823 pSMB->ParameterCount = pSMB->TotalParameterCount;
3824 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3825 pSMB->Reserved4 = 0;
3826 pSMB->hdr.smb_buf_length += byte_count;
3827 pSMB->ByteCount = cpu_to_le16(byte_count);
3829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3831 if (rc) {
3832 cFYI(1, ("error %d in QueryInternalInfo", rc));
3833 } else {
3834 /* decode response */
3835 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3836 if (rc || (pSMBr->ByteCount < 2))
3837 /* BB also check enough total bytes returned */
3838 /* If rc should we check for EOPNOSUPP and
3839 disable the srvino flag? or in caller? */
3840 rc = -EIO; /* bad smb */
3841 else {
3842 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3843 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3844 struct file_internal_info *pfinfo;
3845 /* BB Do we need a cast or hash here ? */
3846 if (count < 8) {
3847 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3848 rc = -EIO;
3849 goto GetInodeNumOut;
3851 pfinfo = (struct file_internal_info *)
3852 (data_offset + (char *) &pSMBr->hdr.Protocol);
3853 *inode_number = pfinfo->UniqueId;
3856 GetInodeNumOut:
3857 cifs_buf_release(pSMB);
3858 if (rc == -EAGAIN)
3859 goto GetInodeNumberRetry;
3860 return rc;
3864 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3865 const unsigned char *searchName,
3866 unsigned char **targetUNCs,
3867 unsigned int *number_of_UNC_in_array,
3868 const struct nls_table *nls_codepage, int remap)
3870 /* TRANS2_GET_DFS_REFERRAL */
3871 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3872 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3873 struct dfs_referral_level_3 *referrals = NULL;
3874 int rc = 0;
3875 int bytes_returned;
3876 int name_len;
3877 unsigned int i;
3878 char *temp;
3879 __u16 params, byte_count;
3880 *number_of_UNC_in_array = 0;
3881 *targetUNCs = NULL;
3883 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3884 if (ses == NULL)
3885 return -ENODEV;
3886 getDFSRetry:
3887 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3888 (void **) &pSMBr);
3889 if (rc)
3890 return rc;
3892 /* server pointer checked in called function,
3893 but should never be null here anyway */
3894 pSMB->hdr.Mid = GetNextMid(ses->server);
3895 pSMB->hdr.Tid = ses->ipc_tid;
3896 pSMB->hdr.Uid = ses->Suid;
3897 if (ses->capabilities & CAP_STATUS32)
3898 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3899 if (ses->capabilities & CAP_DFS)
3900 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3902 if (ses->capabilities & CAP_UNICODE) {
3903 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3904 name_len =
3905 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3906 searchName, PATH_MAX, nls_codepage, remap);
3907 name_len++; /* trailing null */
3908 name_len *= 2;
3909 } else { /* BB improve the check for buffer overruns BB */
3910 name_len = strnlen(searchName, PATH_MAX);
3911 name_len++; /* trailing null */
3912 strncpy(pSMB->RequestFileName, searchName, name_len);
3915 if (ses->server) {
3916 if (ses->server->secMode &
3917 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3918 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3921 pSMB->hdr.Uid = ses->Suid;
3923 params = 2 /* level */ + name_len /*includes null */ ;
3924 pSMB->TotalDataCount = 0;
3925 pSMB->DataCount = 0;
3926 pSMB->DataOffset = 0;
3927 pSMB->MaxParameterCount = 0;
3928 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3929 pSMB->MaxSetupCount = 0;
3930 pSMB->Reserved = 0;
3931 pSMB->Flags = 0;
3932 pSMB->Timeout = 0;
3933 pSMB->Reserved2 = 0;
3934 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3935 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3936 pSMB->SetupCount = 1;
3937 pSMB->Reserved3 = 0;
3938 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3939 byte_count = params + 3 /* pad */ ;
3940 pSMB->ParameterCount = cpu_to_le16(params);
3941 pSMB->TotalParameterCount = pSMB->ParameterCount;
3942 pSMB->MaxReferralLevel = cpu_to_le16(3);
3943 pSMB->hdr.smb_buf_length += byte_count;
3944 pSMB->ByteCount = cpu_to_le16(byte_count);
3946 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3948 if (rc) {
3949 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3950 } else { /* decode response */
3951 /* BB Add logic to parse referrals here */
3952 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3954 /* BB Also check if enough total bytes returned? */
3955 if (rc || (pSMBr->ByteCount < 17))
3956 rc = -EIO; /* bad smb */
3957 else {
3958 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3959 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3961 cFYI(1,
3962 ("Decoding GetDFSRefer response BCC: %d Offset %d",
3963 pSMBr->ByteCount, data_offset));
3964 referrals =
3965 (struct dfs_referral_level_3 *)
3966 (8 /* sizeof start of data block */ +
3967 data_offset +
3968 (char *) &pSMBr->hdr.Protocol);
3969 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
3970 "for referral one refer size: 0x%x srv "
3971 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3972 le16_to_cpu(pSMBr->NumberOfReferrals),
3973 le16_to_cpu(pSMBr->DFSFlags),
3974 le16_to_cpu(referrals->ReferralSize),
3975 le16_to_cpu(referrals->ServerType),
3976 le16_to_cpu(referrals->ReferralFlags),
3977 le16_to_cpu(referrals->TimeToLive)));
3978 /* BB This field is actually two bytes in from start of
3979 data block so we could do safety check that DataBlock
3980 begins at address of pSMBr->NumberOfReferrals */
3981 *number_of_UNC_in_array =
3982 le16_to_cpu(pSMBr->NumberOfReferrals);
3984 /* BB Fix below so can return more than one referral */
3985 if (*number_of_UNC_in_array > 1)
3986 *number_of_UNC_in_array = 1;
3988 /* get the length of the strings describing refs */
3989 name_len = 0;
3990 for (i = 0; i < *number_of_UNC_in_array; i++) {
3991 /* make sure that DfsPathOffset not past end */
3992 __u16 offset =
3993 le16_to_cpu(referrals->DfsPathOffset);
3994 if (offset > data_count) {
3995 /* if invalid referral, stop here and do
3996 not try to copy any more */
3997 *number_of_UNC_in_array = i;
3998 break;
4000 temp = ((char *)referrals) + offset;
4002 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4003 name_len += UniStrnlen((wchar_t *)temp,
4004 data_count);
4005 } else {
4006 name_len += strnlen(temp, data_count);
4008 referrals++;
4009 /* BB add check that referral pointer does
4010 not fall off end PDU */
4012 /* BB add check for name_len bigger than bcc */
4013 *targetUNCs =
4014 kmalloc(name_len+1+(*number_of_UNC_in_array),
4015 GFP_KERNEL);
4016 if (*targetUNCs == NULL) {
4017 rc = -ENOMEM;
4018 goto GetDFSRefExit;
4020 /* copy the ref strings */
4021 referrals = (struct dfs_referral_level_3 *)
4022 (8 /* sizeof data hdr */ + data_offset +
4023 (char *) &pSMBr->hdr.Protocol);
4025 for (i = 0; i < *number_of_UNC_in_array; i++) {
4026 temp = ((char *)referrals) +
4027 le16_to_cpu(referrals->DfsPathOffset);
4028 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4029 cifs_strfromUCS_le(*targetUNCs,
4030 (__le16 *) temp,
4031 name_len,
4032 nls_codepage);
4033 } else {
4034 strncpy(*targetUNCs, temp, name_len);
4036 /* BB update target_uncs pointers */
4037 referrals++;
4039 temp = *targetUNCs;
4040 temp[name_len] = 0;
4044 GetDFSRefExit:
4045 if (pSMB)
4046 cifs_buf_release(pSMB);
4048 if (rc == -EAGAIN)
4049 goto getDFSRetry;
4051 return rc;
4054 /* Query File System Info such as free space to old servers such as Win 9x */
4056 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4058 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4059 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4060 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4061 FILE_SYSTEM_ALLOC_INFO *response_data;
4062 int rc = 0;
4063 int bytes_returned = 0;
4064 __u16 params, byte_count;
4066 cFYI(1, ("OldQFSInfo"));
4067 oldQFSInfoRetry:
4068 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4069 (void **) &pSMBr);
4070 if (rc)
4071 return rc;
4073 params = 2; /* level */
4074 pSMB->TotalDataCount = 0;
4075 pSMB->MaxParameterCount = cpu_to_le16(2);
4076 pSMB->MaxDataCount = cpu_to_le16(1000);
4077 pSMB->MaxSetupCount = 0;
4078 pSMB->Reserved = 0;
4079 pSMB->Flags = 0;
4080 pSMB->Timeout = 0;
4081 pSMB->Reserved2 = 0;
4082 byte_count = params + 1 /* pad */ ;
4083 pSMB->TotalParameterCount = cpu_to_le16(params);
4084 pSMB->ParameterCount = pSMB->TotalParameterCount;
4085 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4086 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4087 pSMB->DataCount = 0;
4088 pSMB->DataOffset = 0;
4089 pSMB->SetupCount = 1;
4090 pSMB->Reserved3 = 0;
4091 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4092 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4093 pSMB->hdr.smb_buf_length += byte_count;
4094 pSMB->ByteCount = cpu_to_le16(byte_count);
4096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4098 if (rc) {
4099 cFYI(1, ("Send error in QFSInfo = %d", rc));
4100 } else { /* decode response */
4101 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4103 if (rc || (pSMBr->ByteCount < 18))
4104 rc = -EIO; /* bad smb */
4105 else {
4106 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4107 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4108 pSMBr->ByteCount, data_offset));
4110 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4111 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4112 FSData->f_bsize =
4113 le16_to_cpu(response_data->BytesPerSector) *
4114 le32_to_cpu(response_data->
4115 SectorsPerAllocationUnit);
4116 FSData->f_blocks =
4117 le32_to_cpu(response_data->TotalAllocationUnits);
4118 FSData->f_bfree = FSData->f_bavail =
4119 le32_to_cpu(response_data->FreeAllocationUnits);
4120 cFYI(1,
4121 ("Blocks: %lld Free: %lld Block size %ld",
4122 (unsigned long long)FSData->f_blocks,
4123 (unsigned long long)FSData->f_bfree,
4124 FSData->f_bsize));
4127 cifs_buf_release(pSMB);
4129 if (rc == -EAGAIN)
4130 goto oldQFSInfoRetry;
4132 return rc;
4136 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4138 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4139 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4140 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4141 FILE_SYSTEM_INFO *response_data;
4142 int rc = 0;
4143 int bytes_returned = 0;
4144 __u16 params, byte_count;
4146 cFYI(1, ("In QFSInfo"));
4147 QFSInfoRetry:
4148 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4149 (void **) &pSMBr);
4150 if (rc)
4151 return rc;
4153 params = 2; /* level */
4154 pSMB->TotalDataCount = 0;
4155 pSMB->MaxParameterCount = cpu_to_le16(2);
4156 pSMB->MaxDataCount = cpu_to_le16(1000);
4157 pSMB->MaxSetupCount = 0;
4158 pSMB->Reserved = 0;
4159 pSMB->Flags = 0;
4160 pSMB->Timeout = 0;
4161 pSMB->Reserved2 = 0;
4162 byte_count = params + 1 /* pad */ ;
4163 pSMB->TotalParameterCount = cpu_to_le16(params);
4164 pSMB->ParameterCount = pSMB->TotalParameterCount;
4165 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4166 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4167 pSMB->DataCount = 0;
4168 pSMB->DataOffset = 0;
4169 pSMB->SetupCount = 1;
4170 pSMB->Reserved3 = 0;
4171 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4172 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4173 pSMB->hdr.smb_buf_length += byte_count;
4174 pSMB->ByteCount = cpu_to_le16(byte_count);
4176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4178 if (rc) {
4179 cFYI(1, ("Send error in QFSInfo = %d", rc));
4180 } else { /* decode response */
4181 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4183 if (rc || (pSMBr->ByteCount < 24))
4184 rc = -EIO; /* bad smb */
4185 else {
4186 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4188 response_data =
4189 (FILE_SYSTEM_INFO
4190 *) (((char *) &pSMBr->hdr.Protocol) +
4191 data_offset);
4192 FSData->f_bsize =
4193 le32_to_cpu(response_data->BytesPerSector) *
4194 le32_to_cpu(response_data->
4195 SectorsPerAllocationUnit);
4196 FSData->f_blocks =
4197 le64_to_cpu(response_data->TotalAllocationUnits);
4198 FSData->f_bfree = FSData->f_bavail =
4199 le64_to_cpu(response_data->FreeAllocationUnits);
4200 cFYI(1,
4201 ("Blocks: %lld Free: %lld Block size %ld",
4202 (unsigned long long)FSData->f_blocks,
4203 (unsigned long long)FSData->f_bfree,
4204 FSData->f_bsize));
4207 cifs_buf_release(pSMB);
4209 if (rc == -EAGAIN)
4210 goto QFSInfoRetry;
4212 return rc;
4216 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4218 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4219 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4220 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4221 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4222 int rc = 0;
4223 int bytes_returned = 0;
4224 __u16 params, byte_count;
4226 cFYI(1, ("In QFSAttributeInfo"));
4227 QFSAttributeRetry:
4228 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4229 (void **) &pSMBr);
4230 if (rc)
4231 return rc;
4233 params = 2; /* level */
4234 pSMB->TotalDataCount = 0;
4235 pSMB->MaxParameterCount = cpu_to_le16(2);
4236 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4237 pSMB->MaxSetupCount = 0;
4238 pSMB->Reserved = 0;
4239 pSMB->Flags = 0;
4240 pSMB->Timeout = 0;
4241 pSMB->Reserved2 = 0;
4242 byte_count = params + 1 /* pad */ ;
4243 pSMB->TotalParameterCount = cpu_to_le16(params);
4244 pSMB->ParameterCount = pSMB->TotalParameterCount;
4245 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4246 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4247 pSMB->DataCount = 0;
4248 pSMB->DataOffset = 0;
4249 pSMB->SetupCount = 1;
4250 pSMB->Reserved3 = 0;
4251 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4252 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4253 pSMB->hdr.smb_buf_length += byte_count;
4254 pSMB->ByteCount = cpu_to_le16(byte_count);
4256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4258 if (rc) {
4259 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4260 } else { /* decode response */
4261 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4263 if (rc || (pSMBr->ByteCount < 13)) {
4264 /* BB also check if enough bytes returned */
4265 rc = -EIO; /* bad smb */
4266 } else {
4267 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4268 response_data =
4269 (FILE_SYSTEM_ATTRIBUTE_INFO
4270 *) (((char *) &pSMBr->hdr.Protocol) +
4271 data_offset);
4272 memcpy(&tcon->fsAttrInfo, response_data,
4273 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
4276 cifs_buf_release(pSMB);
4278 if (rc == -EAGAIN)
4279 goto QFSAttributeRetry;
4281 return rc;
4285 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4287 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4288 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4289 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4290 FILE_SYSTEM_DEVICE_INFO *response_data;
4291 int rc = 0;
4292 int bytes_returned = 0;
4293 __u16 params, byte_count;
4295 cFYI(1, ("In QFSDeviceInfo"));
4296 QFSDeviceRetry:
4297 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4298 (void **) &pSMBr);
4299 if (rc)
4300 return rc;
4302 params = 2; /* level */
4303 pSMB->TotalDataCount = 0;
4304 pSMB->MaxParameterCount = cpu_to_le16(2);
4305 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4306 pSMB->MaxSetupCount = 0;
4307 pSMB->Reserved = 0;
4308 pSMB->Flags = 0;
4309 pSMB->Timeout = 0;
4310 pSMB->Reserved2 = 0;
4311 byte_count = params + 1 /* pad */ ;
4312 pSMB->TotalParameterCount = cpu_to_le16(params);
4313 pSMB->ParameterCount = pSMB->TotalParameterCount;
4314 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4315 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4317 pSMB->DataCount = 0;
4318 pSMB->DataOffset = 0;
4319 pSMB->SetupCount = 1;
4320 pSMB->Reserved3 = 0;
4321 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4322 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4323 pSMB->hdr.smb_buf_length += byte_count;
4324 pSMB->ByteCount = cpu_to_le16(byte_count);
4326 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4327 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4328 if (rc) {
4329 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4330 } else { /* decode response */
4331 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4333 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
4334 rc = -EIO; /* bad smb */
4335 else {
4336 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4337 response_data =
4338 (FILE_SYSTEM_DEVICE_INFO *)
4339 (((char *) &pSMBr->hdr.Protocol) +
4340 data_offset);
4341 memcpy(&tcon->fsDevInfo, response_data,
4342 sizeof(FILE_SYSTEM_DEVICE_INFO));
4345 cifs_buf_release(pSMB);
4347 if (rc == -EAGAIN)
4348 goto QFSDeviceRetry;
4350 return rc;
4354 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4356 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4357 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4358 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4359 FILE_SYSTEM_UNIX_INFO *response_data;
4360 int rc = 0;
4361 int bytes_returned = 0;
4362 __u16 params, byte_count;
4364 cFYI(1, ("In QFSUnixInfo"));
4365 QFSUnixRetry:
4366 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4367 (void **) &pSMBr);
4368 if (rc)
4369 return rc;
4371 params = 2; /* level */
4372 pSMB->TotalDataCount = 0;
4373 pSMB->DataCount = 0;
4374 pSMB->DataOffset = 0;
4375 pSMB->MaxParameterCount = cpu_to_le16(2);
4376 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4377 pSMB->MaxSetupCount = 0;
4378 pSMB->Reserved = 0;
4379 pSMB->Flags = 0;
4380 pSMB->Timeout = 0;
4381 pSMB->Reserved2 = 0;
4382 byte_count = params + 1 /* pad */ ;
4383 pSMB->ParameterCount = cpu_to_le16(params);
4384 pSMB->TotalParameterCount = pSMB->ParameterCount;
4385 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4386 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4387 pSMB->SetupCount = 1;
4388 pSMB->Reserved3 = 0;
4389 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4390 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4391 pSMB->hdr.smb_buf_length += byte_count;
4392 pSMB->ByteCount = cpu_to_le16(byte_count);
4394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4395 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4396 if (rc) {
4397 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4398 } else { /* decode response */
4399 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4401 if (rc || (pSMBr->ByteCount < 13)) {
4402 rc = -EIO; /* bad smb */
4403 } else {
4404 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4405 response_data =
4406 (FILE_SYSTEM_UNIX_INFO
4407 *) (((char *) &pSMBr->hdr.Protocol) +
4408 data_offset);
4409 memcpy(&tcon->fsUnixInfo, response_data,
4410 sizeof(FILE_SYSTEM_UNIX_INFO));
4413 cifs_buf_release(pSMB);
4415 if (rc == -EAGAIN)
4416 goto QFSUnixRetry;
4419 return rc;
4423 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4425 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4426 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4427 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4428 int rc = 0;
4429 int bytes_returned = 0;
4430 __u16 params, param_offset, offset, byte_count;
4432 cFYI(1, ("In SETFSUnixInfo"));
4433 SETFSUnixRetry:
4434 /* BB switch to small buf init to save memory */
4435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4436 (void **) &pSMBr);
4437 if (rc)
4438 return rc;
4440 params = 4; /* 2 bytes zero followed by info level. */
4441 pSMB->MaxSetupCount = 0;
4442 pSMB->Reserved = 0;
4443 pSMB->Flags = 0;
4444 pSMB->Timeout = 0;
4445 pSMB->Reserved2 = 0;
4446 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4447 - 4;
4448 offset = param_offset + params;
4450 pSMB->MaxParameterCount = cpu_to_le16(4);
4451 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4452 pSMB->SetupCount = 1;
4453 pSMB->Reserved3 = 0;
4454 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4455 byte_count = 1 /* pad */ + params + 12;
4457 pSMB->DataCount = cpu_to_le16(12);
4458 pSMB->ParameterCount = cpu_to_le16(params);
4459 pSMB->TotalDataCount = pSMB->DataCount;
4460 pSMB->TotalParameterCount = pSMB->ParameterCount;
4461 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4462 pSMB->DataOffset = cpu_to_le16(offset);
4464 /* Params. */
4465 pSMB->FileNum = 0;
4466 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4468 /* Data. */
4469 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4470 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4471 pSMB->ClientUnixCap = cpu_to_le64(cap);
4473 pSMB->hdr.smb_buf_length += byte_count;
4474 pSMB->ByteCount = cpu_to_le16(byte_count);
4476 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4477 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4478 if (rc) {
4479 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4480 } else { /* decode response */
4481 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4482 if (rc)
4483 rc = -EIO; /* bad smb */
4485 cifs_buf_release(pSMB);
4487 if (rc == -EAGAIN)
4488 goto SETFSUnixRetry;
4490 return rc;
4496 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4497 struct kstatfs *FSData)
4499 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4500 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4501 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4502 FILE_SYSTEM_POSIX_INFO *response_data;
4503 int rc = 0;
4504 int bytes_returned = 0;
4505 __u16 params, byte_count;
4507 cFYI(1, ("In QFSPosixInfo"));
4508 QFSPosixRetry:
4509 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4510 (void **) &pSMBr);
4511 if (rc)
4512 return rc;
4514 params = 2; /* level */
4515 pSMB->TotalDataCount = 0;
4516 pSMB->DataCount = 0;
4517 pSMB->DataOffset = 0;
4518 pSMB->MaxParameterCount = cpu_to_le16(2);
4519 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4520 pSMB->MaxSetupCount = 0;
4521 pSMB->Reserved = 0;
4522 pSMB->Flags = 0;
4523 pSMB->Timeout = 0;
4524 pSMB->Reserved2 = 0;
4525 byte_count = params + 1 /* pad */ ;
4526 pSMB->ParameterCount = cpu_to_le16(params);
4527 pSMB->TotalParameterCount = pSMB->ParameterCount;
4528 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4529 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4530 pSMB->SetupCount = 1;
4531 pSMB->Reserved3 = 0;
4532 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4533 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4534 pSMB->hdr.smb_buf_length += byte_count;
4535 pSMB->ByteCount = cpu_to_le16(byte_count);
4537 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4538 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4539 if (rc) {
4540 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4541 } else { /* decode response */
4542 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4544 if (rc || (pSMBr->ByteCount < 13)) {
4545 rc = -EIO; /* bad smb */
4546 } else {
4547 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4548 response_data =
4549 (FILE_SYSTEM_POSIX_INFO
4550 *) (((char *) &pSMBr->hdr.Protocol) +
4551 data_offset);
4552 FSData->f_bsize =
4553 le32_to_cpu(response_data->BlockSize);
4554 FSData->f_blocks =
4555 le64_to_cpu(response_data->TotalBlocks);
4556 FSData->f_bfree =
4557 le64_to_cpu(response_data->BlocksAvail);
4558 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4559 FSData->f_bavail = FSData->f_bfree;
4560 } else {
4561 FSData->f_bavail =
4562 le64_to_cpu(response_data->UserBlocksAvail);
4564 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4565 FSData->f_files =
4566 le64_to_cpu(response_data->TotalFileNodes);
4567 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4568 FSData->f_ffree =
4569 le64_to_cpu(response_data->FreeFileNodes);
4572 cifs_buf_release(pSMB);
4574 if (rc == -EAGAIN)
4575 goto QFSPosixRetry;
4577 return rc;
4581 /* We can not use write of zero bytes trick to
4582 set file size due to need for large file support. Also note that
4583 this SetPathInfo is preferred to SetFileInfo based method in next
4584 routine which is only needed to work around a sharing violation bug
4585 in Samba which this routine can run into */
4588 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4589 __u64 size, int SetAllocation,
4590 const struct nls_table *nls_codepage, int remap)
4592 struct smb_com_transaction2_spi_req *pSMB = NULL;
4593 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4594 struct file_end_of_file_info *parm_data;
4595 int name_len;
4596 int rc = 0;
4597 int bytes_returned = 0;
4598 __u16 params, byte_count, data_count, param_offset, offset;
4600 cFYI(1, ("In SetEOF"));
4601 SetEOFRetry:
4602 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4603 (void **) &pSMBr);
4604 if (rc)
4605 return rc;
4607 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4608 name_len =
4609 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4610 PATH_MAX, nls_codepage, remap);
4611 name_len++; /* trailing null */
4612 name_len *= 2;
4613 } else { /* BB improve the check for buffer overruns BB */
4614 name_len = strnlen(fileName, PATH_MAX);
4615 name_len++; /* trailing null */
4616 strncpy(pSMB->FileName, fileName, name_len);
4618 params = 6 + name_len;
4619 data_count = sizeof(struct file_end_of_file_info);
4620 pSMB->MaxParameterCount = cpu_to_le16(2);
4621 pSMB->MaxDataCount = cpu_to_le16(4100);
4622 pSMB->MaxSetupCount = 0;
4623 pSMB->Reserved = 0;
4624 pSMB->Flags = 0;
4625 pSMB->Timeout = 0;
4626 pSMB->Reserved2 = 0;
4627 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4628 InformationLevel) - 4;
4629 offset = param_offset + params;
4630 if (SetAllocation) {
4631 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4632 pSMB->InformationLevel =
4633 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4634 else
4635 pSMB->InformationLevel =
4636 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4637 } else /* Set File Size */ {
4638 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4639 pSMB->InformationLevel =
4640 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4641 else
4642 pSMB->InformationLevel =
4643 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4646 parm_data =
4647 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4648 offset);
4649 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4650 pSMB->DataOffset = cpu_to_le16(offset);
4651 pSMB->SetupCount = 1;
4652 pSMB->Reserved3 = 0;
4653 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4654 byte_count = 3 /* pad */ + params + data_count;
4655 pSMB->DataCount = cpu_to_le16(data_count);
4656 pSMB->TotalDataCount = pSMB->DataCount;
4657 pSMB->ParameterCount = cpu_to_le16(params);
4658 pSMB->TotalParameterCount = pSMB->ParameterCount;
4659 pSMB->Reserved4 = 0;
4660 pSMB->hdr.smb_buf_length += byte_count;
4661 parm_data->FileSize = cpu_to_le64(size);
4662 pSMB->ByteCount = cpu_to_le16(byte_count);
4663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4664 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4665 if (rc)
4666 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4668 cifs_buf_release(pSMB);
4670 if (rc == -EAGAIN)
4671 goto SetEOFRetry;
4673 return rc;
4677 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4678 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4680 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4681 char *data_offset;
4682 struct file_end_of_file_info *parm_data;
4683 int rc = 0;
4684 __u16 params, param_offset, offset, byte_count, count;
4686 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4687 (long long)size));
4688 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4690 if (rc)
4691 return rc;
4693 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4694 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4696 params = 6;
4697 pSMB->MaxSetupCount = 0;
4698 pSMB->Reserved = 0;
4699 pSMB->Flags = 0;
4700 pSMB->Timeout = 0;
4701 pSMB->Reserved2 = 0;
4702 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4703 offset = param_offset + params;
4705 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4707 count = sizeof(struct file_end_of_file_info);
4708 pSMB->MaxParameterCount = cpu_to_le16(2);
4709 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4710 pSMB->SetupCount = 1;
4711 pSMB->Reserved3 = 0;
4712 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4713 byte_count = 3 /* pad */ + params + count;
4714 pSMB->DataCount = cpu_to_le16(count);
4715 pSMB->ParameterCount = cpu_to_le16(params);
4716 pSMB->TotalDataCount = pSMB->DataCount;
4717 pSMB->TotalParameterCount = pSMB->ParameterCount;
4718 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4719 parm_data =
4720 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4721 + offset);
4722 pSMB->DataOffset = cpu_to_le16(offset);
4723 parm_data->FileSize = cpu_to_le64(size);
4724 pSMB->Fid = fid;
4725 if (SetAllocation) {
4726 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4727 pSMB->InformationLevel =
4728 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4729 else
4730 pSMB->InformationLevel =
4731 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4732 } else /* Set File Size */ {
4733 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4734 pSMB->InformationLevel =
4735 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4736 else
4737 pSMB->InformationLevel =
4738 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4740 pSMB->Reserved4 = 0;
4741 pSMB->hdr.smb_buf_length += byte_count;
4742 pSMB->ByteCount = cpu_to_le16(byte_count);
4743 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4744 if (rc) {
4745 cFYI(1,
4746 ("Send error in SetFileInfo (SetFileSize) = %d",
4747 rc));
4750 /* Note: On -EAGAIN error only caller can retry on handle based calls
4751 since file handle passed in no longer valid */
4753 return rc;
4756 /* Some legacy servers such as NT4 require that the file times be set on
4757 an open handle, rather than by pathname - this is awkward due to
4758 potential access conflicts on the open, but it is unavoidable for these
4759 old servers since the only other choice is to go from 100 nanosecond DCE
4760 time and resort to the original setpathinfo level which takes the ancient
4761 DOS time format with 2 second granularity */
4763 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4764 const FILE_BASIC_INFO *data, __u16 fid)
4766 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4767 char *data_offset;
4768 int rc = 0;
4769 __u16 params, param_offset, offset, byte_count, count;
4771 cFYI(1, ("Set Times (via SetFileInfo)"));
4772 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4774 if (rc)
4775 return rc;
4777 /* At this point there is no need to override the current pid
4778 with the pid of the opener, but that could change if we someday
4779 use an existing handle (rather than opening one on the fly) */
4780 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4781 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4783 params = 6;
4784 pSMB->MaxSetupCount = 0;
4785 pSMB->Reserved = 0;
4786 pSMB->Flags = 0;
4787 pSMB->Timeout = 0;
4788 pSMB->Reserved2 = 0;
4789 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4790 offset = param_offset + params;
4792 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4794 count = sizeof(FILE_BASIC_INFO);
4795 pSMB->MaxParameterCount = cpu_to_le16(2);
4796 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
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 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4864 pSMB->MaxSetupCount = 0;
4865 pSMB->Reserved = 0;
4866 pSMB->Flags = 0;
4867 pSMB->Timeout = 0;
4868 pSMB->Reserved2 = 0;
4869 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4870 InformationLevel) - 4;
4871 offset = param_offset + params;
4872 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4873 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4874 pSMB->DataOffset = cpu_to_le16(offset);
4875 pSMB->SetupCount = 1;
4876 pSMB->Reserved3 = 0;
4877 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4878 byte_count = 3 /* pad */ + params + count;
4880 pSMB->DataCount = cpu_to_le16(count);
4881 pSMB->ParameterCount = cpu_to_le16(params);
4882 pSMB->TotalDataCount = pSMB->DataCount;
4883 pSMB->TotalParameterCount = pSMB->ParameterCount;
4884 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4885 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4886 else
4887 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4888 pSMB->Reserved4 = 0;
4889 pSMB->hdr.smb_buf_length += byte_count;
4890 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4891 pSMB->ByteCount = cpu_to_le16(byte_count);
4892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4894 if (rc)
4895 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4897 cifs_buf_release(pSMB);
4899 if (rc == -EAGAIN)
4900 goto SetTimesRetry;
4902 return rc;
4905 /* Can not be used to set time stamps yet (due to old DOS time format) */
4906 /* Can be used to set attributes */
4907 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4908 handling it anyway and NT4 was what we thought it would be needed for
4909 Do not delete it until we prove whether needed for Win9x though */
4911 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4912 __u16 dos_attrs, const struct nls_table *nls_codepage)
4914 SETATTR_REQ *pSMB = NULL;
4915 SETATTR_RSP *pSMBr = NULL;
4916 int rc = 0;
4917 int bytes_returned;
4918 int name_len;
4920 cFYI(1, ("In SetAttrLegacy"));
4922 SetAttrLgcyRetry:
4923 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4924 (void **) &pSMBr);
4925 if (rc)
4926 return rc;
4928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4929 name_len =
4930 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4931 PATH_MAX, nls_codepage);
4932 name_len++; /* trailing null */
4933 name_len *= 2;
4934 } else { /* BB improve the check for buffer overruns BB */
4935 name_len = strnlen(fileName, PATH_MAX);
4936 name_len++; /* trailing null */
4937 strncpy(pSMB->fileName, fileName, name_len);
4939 pSMB->attr = cpu_to_le16(dos_attrs);
4940 pSMB->BufferFormat = 0x04;
4941 pSMB->hdr.smb_buf_length += name_len + 1;
4942 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4943 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4944 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4945 if (rc)
4946 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4948 cifs_buf_release(pSMB);
4950 if (rc == -EAGAIN)
4951 goto SetAttrLgcyRetry;
4953 return rc;
4955 #endif /* temporarily unneeded SetAttr legacy function */
4958 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4959 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4960 dev_t device, const struct nls_table *nls_codepage,
4961 int remap)
4963 TRANSACTION2_SPI_REQ *pSMB = NULL;
4964 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4965 int name_len;
4966 int rc = 0;
4967 int bytes_returned = 0;
4968 FILE_UNIX_BASIC_INFO *data_offset;
4969 __u16 params, param_offset, offset, count, byte_count;
4971 cFYI(1, ("In SetUID/GID/Mode"));
4972 setPermsRetry:
4973 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4974 (void **) &pSMBr);
4975 if (rc)
4976 return rc;
4978 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4979 name_len =
4980 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4981 PATH_MAX, nls_codepage, remap);
4982 name_len++; /* trailing null */
4983 name_len *= 2;
4984 } else { /* BB improve the check for buffer overruns BB */
4985 name_len = strnlen(fileName, PATH_MAX);
4986 name_len++; /* trailing null */
4987 strncpy(pSMB->FileName, fileName, name_len);
4990 params = 6 + name_len;
4991 count = sizeof(FILE_UNIX_BASIC_INFO);
4992 pSMB->MaxParameterCount = cpu_to_le16(2);
4993 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4994 pSMB->MaxSetupCount = 0;
4995 pSMB->Reserved = 0;
4996 pSMB->Flags = 0;
4997 pSMB->Timeout = 0;
4998 pSMB->Reserved2 = 0;
4999 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5000 InformationLevel) - 4;
5001 offset = param_offset + params;
5002 data_offset =
5003 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5004 offset);
5005 memset(data_offset, 0, count);
5006 pSMB->DataOffset = cpu_to_le16(offset);
5007 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5008 pSMB->SetupCount = 1;
5009 pSMB->Reserved3 = 0;
5010 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5011 byte_count = 3 /* pad */ + params + count;
5012 pSMB->ParameterCount = cpu_to_le16(params);
5013 pSMB->DataCount = cpu_to_le16(count);
5014 pSMB->TotalParameterCount = pSMB->ParameterCount;
5015 pSMB->TotalDataCount = pSMB->DataCount;
5016 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5017 pSMB->Reserved4 = 0;
5018 pSMB->hdr.smb_buf_length += byte_count;
5019 /* Samba server ignores set of file size to zero due to bugs in some
5020 older clients, but we should be precise - we use SetFileSize to
5021 set file size and do not want to truncate file size to zero
5022 accidently as happened on one Samba server beta by putting
5023 zero instead of -1 here */
5024 data_offset->EndOfFile = NO_CHANGE_64;
5025 data_offset->NumOfBytes = NO_CHANGE_64;
5026 data_offset->LastStatusChange = NO_CHANGE_64;
5027 data_offset->LastAccessTime = NO_CHANGE_64;
5028 data_offset->LastModificationTime = NO_CHANGE_64;
5029 data_offset->Uid = cpu_to_le64(uid);
5030 data_offset->Gid = cpu_to_le64(gid);
5031 /* better to leave device as zero when it is */
5032 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5033 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5034 data_offset->Permissions = cpu_to_le64(mode);
5036 if (S_ISREG(mode))
5037 data_offset->Type = cpu_to_le32(UNIX_FILE);
5038 else if (S_ISDIR(mode))
5039 data_offset->Type = cpu_to_le32(UNIX_DIR);
5040 else if (S_ISLNK(mode))
5041 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5042 else if (S_ISCHR(mode))
5043 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5044 else if (S_ISBLK(mode))
5045 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5046 else if (S_ISFIFO(mode))
5047 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5048 else if (S_ISSOCK(mode))
5049 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5052 pSMB->ByteCount = cpu_to_le16(byte_count);
5053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5055 if (rc)
5056 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5058 if (pSMB)
5059 cifs_buf_release(pSMB);
5060 if (rc == -EAGAIN)
5061 goto setPermsRetry;
5062 return rc;
5065 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5066 const int notify_subdirs, const __u16 netfid,
5067 __u32 filter, struct file *pfile, int multishot,
5068 const struct nls_table *nls_codepage)
5070 int rc = 0;
5071 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5072 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5073 struct dir_notify_req *dnotify_req;
5074 int bytes_returned;
5076 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5077 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5078 (void **) &pSMBr);
5079 if (rc)
5080 return rc;
5082 pSMB->TotalParameterCount = 0 ;
5083 pSMB->TotalDataCount = 0;
5084 pSMB->MaxParameterCount = cpu_to_le32(2);
5085 /* BB find exact data count max from sess structure BB */
5086 pSMB->MaxDataCount = 0; /* same in little endian or be */
5087 /* BB VERIFY verify which is correct for above BB */
5088 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5089 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5091 pSMB->MaxSetupCount = 4;
5092 pSMB->Reserved = 0;
5093 pSMB->ParameterOffset = 0;
5094 pSMB->DataCount = 0;
5095 pSMB->DataOffset = 0;
5096 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5097 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5098 pSMB->ParameterCount = pSMB->TotalParameterCount;
5099 if (notify_subdirs)
5100 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5101 pSMB->Reserved2 = 0;
5102 pSMB->CompletionFilter = cpu_to_le32(filter);
5103 pSMB->Fid = netfid; /* file handle always le */
5104 pSMB->ByteCount = 0;
5106 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5107 (struct smb_hdr *)pSMBr, &bytes_returned,
5108 CIFS_ASYNC_OP);
5109 if (rc) {
5110 cFYI(1, ("Error in Notify = %d", rc));
5111 } else {
5112 /* Add file to outstanding requests */
5113 /* BB change to kmem cache alloc */
5114 dnotify_req = kmalloc(
5115 sizeof(struct dir_notify_req),
5116 GFP_KERNEL);
5117 if (dnotify_req) {
5118 dnotify_req->Pid = pSMB->hdr.Pid;
5119 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5120 dnotify_req->Mid = pSMB->hdr.Mid;
5121 dnotify_req->Tid = pSMB->hdr.Tid;
5122 dnotify_req->Uid = pSMB->hdr.Uid;
5123 dnotify_req->netfid = netfid;
5124 dnotify_req->pfile = pfile;
5125 dnotify_req->filter = filter;
5126 dnotify_req->multishot = multishot;
5127 spin_lock(&GlobalMid_Lock);
5128 list_add_tail(&dnotify_req->lhead,
5129 &GlobalDnotifyReqList);
5130 spin_unlock(&GlobalMid_Lock);
5131 } else
5132 rc = -ENOMEM;
5134 cifs_buf_release(pSMB);
5135 return rc;
5137 #ifdef CONFIG_CIFS_XATTR
5138 ssize_t
5139 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5140 const unsigned char *searchName,
5141 char *EAData, size_t buf_size,
5142 const struct nls_table *nls_codepage, int remap)
5144 /* BB assumes one setup word */
5145 TRANSACTION2_QPI_REQ *pSMB = NULL;
5146 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5147 int rc = 0;
5148 int bytes_returned;
5149 int name_len;
5150 struct fea *temp_fea;
5151 char *temp_ptr;
5152 __u16 params, byte_count;
5154 cFYI(1, ("In Query All EAs path %s", searchName));
5155 QAllEAsRetry:
5156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5157 (void **) &pSMBr);
5158 if (rc)
5159 return rc;
5161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5162 name_len =
5163 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5164 PATH_MAX, nls_codepage, remap);
5165 name_len++; /* trailing null */
5166 name_len *= 2;
5167 } else { /* BB improve the check for buffer overruns BB */
5168 name_len = strnlen(searchName, PATH_MAX);
5169 name_len++; /* trailing null */
5170 strncpy(pSMB->FileName, searchName, name_len);
5173 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5174 pSMB->TotalDataCount = 0;
5175 pSMB->MaxParameterCount = cpu_to_le16(2);
5176 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5177 pSMB->MaxSetupCount = 0;
5178 pSMB->Reserved = 0;
5179 pSMB->Flags = 0;
5180 pSMB->Timeout = 0;
5181 pSMB->Reserved2 = 0;
5182 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5183 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5184 pSMB->DataCount = 0;
5185 pSMB->DataOffset = 0;
5186 pSMB->SetupCount = 1;
5187 pSMB->Reserved3 = 0;
5188 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5189 byte_count = params + 1 /* pad */ ;
5190 pSMB->TotalParameterCount = cpu_to_le16(params);
5191 pSMB->ParameterCount = pSMB->TotalParameterCount;
5192 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5193 pSMB->Reserved4 = 0;
5194 pSMB->hdr.smb_buf_length += byte_count;
5195 pSMB->ByteCount = cpu_to_le16(byte_count);
5197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5199 if (rc) {
5200 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5201 } else { /* decode response */
5202 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5204 /* BB also check enough total bytes returned */
5205 /* BB we need to improve the validity checking
5206 of these trans2 responses */
5207 if (rc || (pSMBr->ByteCount < 4))
5208 rc = -EIO; /* bad smb */
5209 /* else if (pFindData){
5210 memcpy((char *) pFindData,
5211 (char *) &pSMBr->hdr.Protocol +
5212 data_offset, kl);
5213 }*/ else {
5214 /* check that length of list is not more than bcc */
5215 /* check that each entry does not go beyond length
5216 of list */
5217 /* check that each element of each entry does not
5218 go beyond end of list */
5219 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5220 struct fealist *ea_response_data;
5221 rc = 0;
5222 /* validate_trans2_offsets() */
5223 /* BB check if start of smb + data_offset > &bcc+ bcc */
5224 ea_response_data = (struct fealist *)
5225 (((char *) &pSMBr->hdr.Protocol) +
5226 data_offset);
5227 name_len = le32_to_cpu(ea_response_data->list_len);
5228 cFYI(1, ("ea length %d", name_len));
5229 if (name_len <= 8) {
5230 /* returned EA size zeroed at top of function */
5231 cFYI(1, ("empty EA list returned from server"));
5232 } else {
5233 /* account for ea list len */
5234 name_len -= 4;
5235 temp_fea = ea_response_data->list;
5236 temp_ptr = (char *)temp_fea;
5237 while (name_len > 0) {
5238 __u16 value_len;
5239 name_len -= 4;
5240 temp_ptr += 4;
5241 rc += temp_fea->name_len;
5242 /* account for prefix user. and trailing null */
5243 rc = rc + 5 + 1;
5244 if (rc < (int)buf_size) {
5245 memcpy(EAData, "user.", 5);
5246 EAData += 5;
5247 memcpy(EAData, temp_ptr,
5248 temp_fea->name_len);
5249 EAData += temp_fea->name_len;
5250 /* null terminate name */
5251 *EAData = 0;
5252 EAData = EAData + 1;
5253 } else if (buf_size == 0) {
5254 /* skip copy - calc size only */
5255 } else {
5256 /* stop before overrun buffer */
5257 rc = -ERANGE;
5258 break;
5260 name_len -= temp_fea->name_len;
5261 temp_ptr += temp_fea->name_len;
5262 /* account for trailing null */
5263 name_len--;
5264 temp_ptr++;
5265 value_len =
5266 le16_to_cpu(temp_fea->value_len);
5267 name_len -= value_len;
5268 temp_ptr += value_len;
5269 /* BB check that temp_ptr is still
5270 within the SMB BB*/
5272 /* no trailing null to account for
5273 in value len */
5274 /* go on to next EA */
5275 temp_fea = (struct fea *)temp_ptr;
5280 if (pSMB)
5281 cifs_buf_release(pSMB);
5282 if (rc == -EAGAIN)
5283 goto QAllEAsRetry;
5285 return (ssize_t)rc;
5288 ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5289 const unsigned char *searchName, const unsigned char *ea_name,
5290 unsigned char *ea_value, size_t buf_size,
5291 const struct nls_table *nls_codepage, int remap)
5293 TRANSACTION2_QPI_REQ *pSMB = NULL;
5294 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5295 int rc = 0;
5296 int bytes_returned;
5297 int name_len;
5298 struct fea *temp_fea;
5299 char *temp_ptr;
5300 __u16 params, byte_count;
5302 cFYI(1, ("In Query EA path %s", searchName));
5303 QEARetry:
5304 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5305 (void **) &pSMBr);
5306 if (rc)
5307 return rc;
5309 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5310 name_len =
5311 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5312 PATH_MAX, nls_codepage, remap);
5313 name_len++; /* trailing null */
5314 name_len *= 2;
5315 } else { /* BB improve the check for buffer overruns BB */
5316 name_len = strnlen(searchName, PATH_MAX);
5317 name_len++; /* trailing null */
5318 strncpy(pSMB->FileName, searchName, name_len);
5321 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5322 pSMB->TotalDataCount = 0;
5323 pSMB->MaxParameterCount = cpu_to_le16(2);
5324 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5325 pSMB->MaxSetupCount = 0;
5326 pSMB->Reserved = 0;
5327 pSMB->Flags = 0;
5328 pSMB->Timeout = 0;
5329 pSMB->Reserved2 = 0;
5330 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5331 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5332 pSMB->DataCount = 0;
5333 pSMB->DataOffset = 0;
5334 pSMB->SetupCount = 1;
5335 pSMB->Reserved3 = 0;
5336 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5337 byte_count = params + 1 /* pad */ ;
5338 pSMB->TotalParameterCount = cpu_to_le16(params);
5339 pSMB->ParameterCount = pSMB->TotalParameterCount;
5340 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5341 pSMB->Reserved4 = 0;
5342 pSMB->hdr.smb_buf_length += byte_count;
5343 pSMB->ByteCount = cpu_to_le16(byte_count);
5345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5347 if (rc) {
5348 cFYI(1, ("Send error in Query EA = %d", rc));
5349 } else { /* decode response */
5350 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5352 /* BB also check enough total bytes returned */
5353 /* BB we need to improve the validity checking
5354 of these trans2 responses */
5355 if (rc || (pSMBr->ByteCount < 4))
5356 rc = -EIO; /* bad smb */
5357 /* else if (pFindData){
5358 memcpy((char *) pFindData,
5359 (char *) &pSMBr->hdr.Protocol +
5360 data_offset, kl);
5361 }*/ else {
5362 /* check that length of list is not more than bcc */
5363 /* check that each entry does not go beyond length
5364 of list */
5365 /* check that each element of each entry does not
5366 go beyond end of list */
5367 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5368 struct fealist *ea_response_data;
5369 rc = -ENODATA;
5370 /* validate_trans2_offsets() */
5371 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5372 ea_response_data = (struct fealist *)
5373 (((char *) &pSMBr->hdr.Protocol) +
5374 data_offset);
5375 name_len = le32_to_cpu(ea_response_data->list_len);
5376 cFYI(1, ("ea length %d", name_len));
5377 if (name_len <= 8) {
5378 /* returned EA size zeroed at top of function */
5379 cFYI(1, ("empty EA list returned from server"));
5380 } else {
5381 /* account for ea list len */
5382 name_len -= 4;
5383 temp_fea = ea_response_data->list;
5384 temp_ptr = (char *)temp_fea;
5385 /* loop through checking if we have a matching
5386 name and then return the associated value */
5387 while (name_len > 0) {
5388 __u16 value_len;
5389 name_len -= 4;
5390 temp_ptr += 4;
5391 value_len =
5392 le16_to_cpu(temp_fea->value_len);
5393 /* BB validate that value_len falls within SMB,
5394 even though maximum for name_len is 255 */
5395 if (memcmp(temp_fea->name, ea_name,
5396 temp_fea->name_len) == 0) {
5397 /* found a match */
5398 rc = value_len;
5399 /* account for prefix user. and trailing null */
5400 if (rc <= (int)buf_size) {
5401 memcpy(ea_value,
5402 temp_fea->name+temp_fea->name_len+1,
5403 rc);
5404 /* ea values, unlike ea
5405 names, are not null
5406 terminated */
5407 } else if (buf_size == 0) {
5408 /* skip copy - calc size only */
5409 } else {
5410 /* stop before overrun buffer */
5411 rc = -ERANGE;
5413 break;
5415 name_len -= temp_fea->name_len;
5416 temp_ptr += temp_fea->name_len;
5417 /* account for trailing null */
5418 name_len--;
5419 temp_ptr++;
5420 name_len -= value_len;
5421 temp_ptr += value_len;
5422 /* No trailing null to account for in
5423 value_len. Go on to next EA */
5424 temp_fea = (struct fea *)temp_ptr;
5429 if (pSMB)
5430 cifs_buf_release(pSMB);
5431 if (rc == -EAGAIN)
5432 goto QEARetry;
5434 return (ssize_t)rc;
5438 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5439 const char *ea_name, const void *ea_value,
5440 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5441 int remap)
5443 struct smb_com_transaction2_spi_req *pSMB = NULL;
5444 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5445 struct fealist *parm_data;
5446 int name_len;
5447 int rc = 0;
5448 int bytes_returned = 0;
5449 __u16 params, param_offset, byte_count, offset, count;
5451 cFYI(1, ("In SetEA"));
5452 SetEARetry:
5453 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5454 (void **) &pSMBr);
5455 if (rc)
5456 return rc;
5458 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5459 name_len =
5460 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5461 PATH_MAX, nls_codepage, remap);
5462 name_len++; /* trailing null */
5463 name_len *= 2;
5464 } else { /* BB improve the check for buffer overruns BB */
5465 name_len = strnlen(fileName, PATH_MAX);
5466 name_len++; /* trailing null */
5467 strncpy(pSMB->FileName, fileName, name_len);
5470 params = 6 + name_len;
5472 /* done calculating parms using name_len of file name,
5473 now use name_len to calculate length of ea name
5474 we are going to create in the inode xattrs */
5475 if (ea_name == NULL)
5476 name_len = 0;
5477 else
5478 name_len = strnlen(ea_name, 255);
5480 count = sizeof(*parm_data) + ea_value_len + name_len;
5481 pSMB->MaxParameterCount = cpu_to_le16(2);
5482 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5483 pSMB->MaxSetupCount = 0;
5484 pSMB->Reserved = 0;
5485 pSMB->Flags = 0;
5486 pSMB->Timeout = 0;
5487 pSMB->Reserved2 = 0;
5488 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5489 InformationLevel) - 4;
5490 offset = param_offset + params;
5491 pSMB->InformationLevel =
5492 cpu_to_le16(SMB_SET_FILE_EA);
5494 parm_data =
5495 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5496 offset);
5497 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5498 pSMB->DataOffset = cpu_to_le16(offset);
5499 pSMB->SetupCount = 1;
5500 pSMB->Reserved3 = 0;
5501 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5502 byte_count = 3 /* pad */ + params + count;
5503 pSMB->DataCount = cpu_to_le16(count);
5504 parm_data->list_len = cpu_to_le32(count);
5505 parm_data->list[0].EA_flags = 0;
5506 /* we checked above that name len is less than 255 */
5507 parm_data->list[0].name_len = (__u8)name_len;
5508 /* EA names are always ASCII */
5509 if (ea_name)
5510 strncpy(parm_data->list[0].name, ea_name, name_len);
5511 parm_data->list[0].name[name_len] = 0;
5512 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5513 /* caller ensures that ea_value_len is less than 64K but
5514 we need to ensure that it fits within the smb */
5516 /*BB add length check to see if it would fit in
5517 negotiated SMB buffer size BB */
5518 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5519 if (ea_value_len)
5520 memcpy(parm_data->list[0].name+name_len+1,
5521 ea_value, ea_value_len);
5523 pSMB->TotalDataCount = pSMB->DataCount;
5524 pSMB->ParameterCount = cpu_to_le16(params);
5525 pSMB->TotalParameterCount = pSMB->ParameterCount;
5526 pSMB->Reserved4 = 0;
5527 pSMB->hdr.smb_buf_length += byte_count;
5528 pSMB->ByteCount = cpu_to_le16(byte_count);
5529 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5530 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5531 if (rc)
5532 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5534 cifs_buf_release(pSMB);
5536 if (rc == -EAGAIN)
5537 goto SetEARetry;
5539 return rc;
5542 #endif