[BNX2]: Add indirect spinlock.
[linux-2.6/x86.git] / fs / cifs / cifssmb.c
blob48fc0c2ab0e5fb022e8b714cf561a55a521b1737
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2006
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 different for reconnection purposes since we never want */
28 /* to reuse a stale file handle and the caller knows the file handle */
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 "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifsacl.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;
101 write_unlock(&GlobalSMBSeslock);
102 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103 to this tcon */
106 /* If the return code is zero, this function must fill in request_buf pointer */
107 static int
108 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
109 void **request_buf /* returned */)
111 int rc = 0;
113 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
114 check for tcp and smb session status done differently
115 for those three - in the calling routine */
116 if(tcon) {
117 if(tcon->tidStatus == CifsExiting) {
118 /* only tree disconnect, open, and write,
119 (and ulogoff which does not have tcon)
120 are allowed as we start force umount */
121 if((smb_command != SMB_COM_WRITE_ANDX) &&
122 (smb_command != SMB_COM_OPEN_ANDX) &&
123 (smb_command != SMB_COM_TREE_DISCONNECT)) {
124 cFYI(1,("can not send cmd %d while umounting",
125 smb_command));
126 return -ENODEV;
129 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
130 (tcon->ses->server)){
131 struct nls_table *nls_codepage;
132 /* Give Demultiplex thread up to 10 seconds to
133 reconnect, should be greater than cifs socket
134 timeout which is 7 seconds */
135 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
137 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
138 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
139 /* on "soft" mounts we wait once */
140 if((tcon->retry == FALSE) ||
141 (tcon->ses->status == CifsExiting)) {
142 cFYI(1,("gave up waiting on reconnect in smb_init"));
143 return -EHOSTDOWN;
144 } /* else "hard" mount - keep retrying
145 until process is killed or server
146 comes back on-line */
147 } else /* TCP session is reestablished now */
148 break;
152 nls_codepage = load_nls_default();
153 /* need to prevent multiple threads trying to
154 simultaneously reconnect the same SMB session */
155 down(&tcon->ses->sesSem);
156 if(tcon->ses->status == CifsNeedReconnect)
157 rc = cifs_setup_session(0, tcon->ses,
158 nls_codepage);
159 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
160 mark_open_files_invalid(tcon);
161 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
162 tcon, nls_codepage);
163 up(&tcon->ses->sesSem);
164 /* tell server which Unix caps we support */
165 if (tcon->ses->capabilities & CAP_UNIX)
166 reset_cifs_unix_caps(0 /* no xid */,
167 tcon,
168 NULL /* we do not know sb */,
169 NULL /* no vol info */);
170 /* BB FIXME add code to check if wsize needs
171 update due to negotiated smb buffer size
172 shrinking */
173 if(rc == 0)
174 atomic_inc(&tconInfoReconnectCount);
176 cFYI(1, ("reconnect tcon rc = %d", rc));
177 /* Removed call to reopen open files here -
178 it is safer (and faster) to reopen files
179 one at a time as needed in read and write */
181 /* Check if handle based operation so we
182 know whether we can continue or not without
183 returning to caller to reset file handle */
184 switch(smb_command) {
185 case SMB_COM_READ_ANDX:
186 case SMB_COM_WRITE_ANDX:
187 case SMB_COM_CLOSE:
188 case SMB_COM_FIND_CLOSE2:
189 case SMB_COM_LOCKING_ANDX: {
190 unload_nls(nls_codepage);
191 return -EAGAIN;
194 } else {
195 up(&tcon->ses->sesSem);
197 unload_nls(nls_codepage);
199 } else {
200 return -EIO;
203 if(rc)
204 return rc;
206 *request_buf = cifs_small_buf_get();
207 if (*request_buf == NULL) {
208 /* BB should we add a retry in here if not a writepage? */
209 return -ENOMEM;
212 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
214 if(tcon != NULL)
215 cifs_stats_inc(&tcon->num_smbs_sent);
217 return rc;
221 small_smb_init_no_tc(const int smb_command, const int wct,
222 struct cifsSesInfo *ses, void **request_buf)
224 int rc;
225 struct smb_hdr * buffer;
227 rc = small_smb_init(smb_command, wct, NULL, request_buf);
228 if(rc)
229 return rc;
231 buffer = (struct smb_hdr *)*request_buf;
232 buffer->Mid = GetNextMid(ses->server);
233 if (ses->capabilities & CAP_UNICODE)
234 buffer->Flags2 |= SMBFLG2_UNICODE;
235 if (ses->capabilities & CAP_STATUS32)
236 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
238 /* uid, tid can stay at zero as set in header assemble */
240 /* BB add support for turning on the signing when
241 this function is used after 1st of session setup requests */
243 return rc;
246 /* If the return code is zero, this function must fill in request_buf pointer */
247 static int
248 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
249 void **request_buf /* returned */ ,
250 void **response_buf /* returned */ )
252 int rc = 0;
254 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
255 check for tcp and smb session status done differently
256 for those three - in the calling routine */
257 if(tcon) {
258 if(tcon->tidStatus == CifsExiting) {
259 /* only tree disconnect, open, and write,
260 (and ulogoff which does not have tcon)
261 are allowed as we start force umount */
262 if((smb_command != SMB_COM_WRITE_ANDX) &&
263 (smb_command != SMB_COM_OPEN_ANDX) &&
264 (smb_command != SMB_COM_TREE_DISCONNECT)) {
265 cFYI(1,("can not send cmd %d while umounting",
266 smb_command));
267 return -ENODEV;
271 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
272 (tcon->ses->server)){
273 struct nls_table *nls_codepage;
274 /* Give Demultiplex thread up to 10 seconds to
275 reconnect, should be greater than cifs socket
276 timeout which is 7 seconds */
277 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
278 wait_event_interruptible_timeout(tcon->ses->server->response_q,
279 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
280 if(tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
282 /* on "soft" mounts we wait once */
283 if((tcon->retry == FALSE) ||
284 (tcon->ses->status == CifsExiting)) {
285 cFYI(1,("gave up waiting on reconnect in smb_init"));
286 return -EHOSTDOWN;
287 } /* else "hard" mount - keep retrying
288 until process is killed or server
289 comes on-line */
290 } else /* TCP session is reestablished now */
291 break;
295 nls_codepage = load_nls_default();
296 /* need to prevent multiple threads trying to
297 simultaneously reconnect the same SMB session */
298 down(&tcon->ses->sesSem);
299 if(tcon->ses->status == CifsNeedReconnect)
300 rc = cifs_setup_session(0, tcon->ses,
301 nls_codepage);
302 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
303 mark_open_files_invalid(tcon);
304 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
305 tcon, nls_codepage);
306 up(&tcon->ses->sesSem);
307 /* tell server which Unix caps we support */
308 if (tcon->ses->capabilities & CAP_UNIX)
309 reset_cifs_unix_caps(0 /* no xid */,
310 tcon,
311 NULL /* do not know sb */,
312 NULL /* no vol info */);
313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
316 if(rc == 0)
317 atomic_inc(&tconInfoReconnectCount);
319 cFYI(1, ("reconnect tcon rc = %d", rc));
320 /* Removed call to reopen open files here -
321 it is safer (and faster) to reopen files
322 one at a time as needed in read and write */
324 /* Check if handle based operation so we
325 know whether we can continue or not without
326 returning to caller to reset file handle */
327 switch(smb_command) {
328 case SMB_COM_READ_ANDX:
329 case SMB_COM_WRITE_ANDX:
330 case SMB_COM_CLOSE:
331 case SMB_COM_FIND_CLOSE2:
332 case SMB_COM_LOCKING_ANDX: {
333 unload_nls(nls_codepage);
334 return -EAGAIN;
337 } else {
338 up(&tcon->ses->sesSem);
340 unload_nls(nls_codepage);
342 } else {
343 return -EIO;
346 if(rc)
347 return rc;
349 *request_buf = cifs_buf_get();
350 if (*request_buf == NULL) {
351 /* BB should we add a retry in here if not a writepage? */
352 return -ENOMEM;
354 /* Although the original thought was we needed the response buf for */
355 /* potential retries of smb operations it turns out we can determine */
356 /* from the mid flags when the request buffer can be resent without */
357 /* having to use a second distinct buffer for the response */
358 if(response_buf)
359 *response_buf = *request_buf;
361 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
362 wct /*wct */ );
364 if(tcon != NULL)
365 cifs_stats_inc(&tcon->num_smbs_sent);
367 return rc;
370 static int validate_t2(struct smb_t2_rsp * pSMB)
372 int rc = -EINVAL;
373 int total_size;
374 char * pBCC;
376 /* check for plausible wct, bcc and t2 data and parm sizes */
377 /* check for parm and data offset going beyond end of smb */
378 if(pSMB->hdr.WordCount >= 10) {
379 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
380 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
381 /* check that bcc is at least as big as parms + data */
382 /* check that bcc is less than negotiated smb buffer */
383 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
384 if(total_size < 512) {
385 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
386 /* BCC le converted in SendReceive */
387 pBCC = (pSMB->hdr.WordCount * 2) +
388 sizeof(struct smb_hdr) +
389 (char *)pSMB;
390 if((total_size <= (*(u16 *)pBCC)) &&
391 (total_size <
392 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
393 return 0;
399 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
400 sizeof(struct smb_t2_rsp) + 16);
401 return rc;
404 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
406 NEGOTIATE_REQ *pSMB;
407 NEGOTIATE_RSP *pSMBr;
408 int rc = 0;
409 int bytes_returned;
410 int i;
411 struct TCP_Server_Info * server;
412 u16 count;
413 unsigned int secFlags;
414 u16 dialect;
416 if(ses->server)
417 server = ses->server;
418 else {
419 rc = -EIO;
420 return rc;
422 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
423 (void **) &pSMB, (void **) &pSMBr);
424 if (rc)
425 return rc;
427 /* if any of auth flags (ie not sign or seal) are overriden use them */
428 if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
429 secFlags = ses->overrideSecFlg;
430 else /* if override flags set only sign/seal OR them with global auth */
431 secFlags = extended_security | ses->overrideSecFlg;
433 cFYI(1,("secFlags 0x%x",secFlags));
435 pSMB->hdr.Mid = GetNextMid(server);
436 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
437 if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
438 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
440 count = 0;
441 for(i=0;i<CIFS_NUM_PROT;i++) {
442 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
443 count += strlen(protocols[i].name) + 1;
444 /* null at end of source and target buffers anyway */
446 pSMB->hdr.smb_buf_length += count;
447 pSMB->ByteCount = cpu_to_le16(count);
449 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
451 if (rc != 0)
452 goto neg_err_exit;
454 dialect = le16_to_cpu(pSMBr->DialectIndex);
455 cFYI(1,("Dialect: %d", dialect));
456 /* Check wct = 1 error case */
457 if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
458 /* core returns wct = 1, but we do not ask for core - otherwise
459 small wct just comes when dialect index is -1 indicating we
460 could not negotiate a common dialect */
461 rc = -EOPNOTSUPP;
462 goto neg_err_exit;
463 #ifdef CONFIG_CIFS_WEAK_PW_HASH
464 } else if((pSMBr->hdr.WordCount == 13)
465 && ((dialect == LANMAN_PROT)
466 || (dialect == LANMAN2_PROT))) {
467 __s16 tmp;
468 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
470 if((secFlags & CIFSSEC_MAY_LANMAN) ||
471 (secFlags & CIFSSEC_MAY_PLNTXT))
472 server->secType = LANMAN;
473 else {
474 cERROR(1, ("mount failed weak security disabled"
475 " in /proc/fs/cifs/SecurityFlags"));
476 rc = -EOPNOTSUPP;
477 goto neg_err_exit;
479 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
480 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
481 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
482 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
483 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
484 /* even though we do not use raw we might as well set this
485 accurately, in case we ever find a need for it */
486 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
487 server->maxRw = 0xFF00;
488 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
489 } else {
490 server->maxRw = 0;/* we do not need to use raw anyway */
491 server->capabilities = CAP_MPX_MODE;
493 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
494 if (tmp == -1) {
495 /* OS/2 often does not set timezone therefore
496 * we must use server time to calc time zone.
497 * Could deviate slightly from the right zone.
498 * Smallest defined timezone difference is 15 minutes
499 * (i.e. Nepal). Rounding up/down is done to match
500 * this requirement.
502 int val, seconds, remain, result;
503 struct timespec ts, utc;
504 utc = CURRENT_TIME;
505 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
506 le16_to_cpu(rsp->SrvTime.Time));
507 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
508 (int)ts.tv_sec, (int)utc.tv_sec,
509 (int)(utc.tv_sec - ts.tv_sec)));
510 val = (int)(utc.tv_sec - ts.tv_sec);
511 seconds = val < 0 ? -val : val;
512 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
513 remain = seconds % MIN_TZ_ADJ;
514 if(remain >= (MIN_TZ_ADJ / 2))
515 result += MIN_TZ_ADJ;
516 if(val < 0)
517 result = - result;
518 server->timeAdj = result;
519 } else {
520 server->timeAdj = (int)tmp;
521 server->timeAdj *= 60; /* also in seconds */
523 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
526 /* BB get server time for time conversions and add
527 code to use it and timezone since this is not UTC */
529 if (rsp->EncryptionKeyLength ==
530 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
531 memcpy(server->cryptKey, rsp->EncryptionKey,
532 CIFS_CRYPTO_KEY_SIZE);
533 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
534 rc = -EIO; /* need cryptkey unless plain text */
535 goto neg_err_exit;
538 cFYI(1,("LANMAN negotiated"));
539 /* we will not end up setting signing flags - as no signing
540 was in LANMAN and server did not return the flags on */
541 goto signing_check;
542 #else /* weak security disabled */
543 } else if(pSMBr->hdr.WordCount == 13) {
544 cERROR(1,("mount failed, cifs module not built "
545 "with CIFS_WEAK_PW_HASH support"));
546 rc = -EOPNOTSUPP;
547 #endif /* WEAK_PW_HASH */
548 goto neg_err_exit;
549 } else if(pSMBr->hdr.WordCount != 17) {
550 /* unknown wct */
551 rc = -EOPNOTSUPP;
552 goto neg_err_exit;
554 /* else wct == 17 NTLM */
555 server->secMode = pSMBr->SecurityMode;
556 if((server->secMode & SECMODE_USER) == 0)
557 cFYI(1,("share mode security"));
559 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
560 #ifdef CONFIG_CIFS_WEAK_PW_HASH
561 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
562 #endif /* CIFS_WEAK_PW_HASH */
563 cERROR(1,("Server requests plain text password"
564 " but client support disabled"));
566 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
567 server->secType = NTLMv2;
568 else if(secFlags & CIFSSEC_MAY_NTLM)
569 server->secType = NTLM;
570 else if(secFlags & CIFSSEC_MAY_NTLMV2)
571 server->secType = NTLMv2;
572 /* else krb5 ... any others ... */
574 /* one byte, so no need to convert this or EncryptionKeyLen from
575 little endian */
576 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
577 /* probably no need to store and check maxvcs */
578 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
579 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
580 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
581 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
582 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
583 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
584 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
585 server->timeAdj *= 60;
586 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
587 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
588 CIFS_CRYPTO_KEY_SIZE);
589 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
590 && (pSMBr->EncryptionKeyLength == 0)) {
591 /* decode security blob */
592 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
593 rc = -EIO; /* no crypt key only if plain text pwd */
594 goto neg_err_exit;
597 /* BB might be helpful to save off the domain of server here */
599 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
600 (server->capabilities & CAP_EXTENDED_SECURITY)) {
601 count = pSMBr->ByteCount;
602 if (count < 16)
603 rc = -EIO;
604 else if (count == 16) {
605 server->secType = RawNTLMSSP;
606 if (server->socketUseCount.counter > 1) {
607 if (memcmp(server->server_GUID,
608 pSMBr->u.extended_response.
609 GUID, 16) != 0) {
610 cFYI(1, ("server UID changed"));
611 memcpy(server->server_GUID,
612 pSMBr->u.extended_response.GUID,
613 16);
615 } else
616 memcpy(server->server_GUID,
617 pSMBr->u.extended_response.GUID, 16);
618 } else {
619 rc = decode_negTokenInit(pSMBr->u.extended_response.
620 SecurityBlob,
621 count - 16,
622 &server->secType);
623 if(rc == 1) {
624 /* BB Need to fill struct for sessetup here */
625 rc = -EOPNOTSUPP;
626 } else {
627 rc = -EINVAL;
630 } else
631 server->capabilities &= ~CAP_EXTENDED_SECURITY;
633 #ifdef CONFIG_CIFS_WEAK_PW_HASH
634 signing_check:
635 #endif
636 if(sign_CIFS_PDUs == FALSE) {
637 if(server->secMode & SECMODE_SIGN_REQUIRED)
638 cERROR(1,("Server requires "
639 "/proc/fs/cifs/PacketSigningEnabled to be on"));
640 server->secMode &=
641 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
642 } else if(sign_CIFS_PDUs == 1) {
643 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
644 server->secMode &=
645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
646 } else if(sign_CIFS_PDUs == 2) {
647 if((server->secMode &
648 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
649 cERROR(1,("signing required but server lacks support"));
652 neg_err_exit:
653 cifs_buf_release(pSMB);
655 cFYI(1,("negprot rc %d",rc));
656 return rc;
660 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
662 struct smb_hdr *smb_buffer;
663 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
664 int rc = 0;
665 int length;
667 cFYI(1, ("In tree disconnect"));
669 * If last user of the connection and
670 * connection alive - disconnect it
671 * If this is the last connection on the server session disconnect it
672 * (and inside session disconnect we should check if tcp socket needs
673 * to be freed and kernel thread woken up).
675 if (tcon)
676 down(&tcon->tconSem);
677 else
678 return -EIO;
680 atomic_dec(&tcon->useCount);
681 if (atomic_read(&tcon->useCount) > 0) {
682 up(&tcon->tconSem);
683 return -EBUSY;
686 /* No need to return error on this operation if tid invalidated and
687 closed on server already e.g. due to tcp session crashing */
688 if(tcon->tidStatus == CifsNeedReconnect) {
689 up(&tcon->tconSem);
690 return 0;
693 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
694 up(&tcon->tconSem);
695 return -EIO;
697 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
698 (void **)&smb_buffer);
699 if (rc) {
700 up(&tcon->tconSem);
701 return rc;
702 } else {
703 smb_buffer_response = smb_buffer; /* BB removeme BB */
705 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
706 &length, 0);
707 if (rc)
708 cFYI(1, ("Tree disconnect failed %d", rc));
710 if (smb_buffer)
711 cifs_small_buf_release(smb_buffer);
712 up(&tcon->tconSem);
714 /* No need to return error on this operation if tid invalidated and
715 closed on server already e.g. due to tcp session crashing */
716 if (rc == -EAGAIN)
717 rc = 0;
719 return rc;
723 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
725 struct smb_hdr *smb_buffer_response;
726 LOGOFF_ANDX_REQ *pSMB;
727 int rc = 0;
728 int length;
730 cFYI(1, ("In SMBLogoff for session disconnect"));
731 if (ses)
732 down(&ses->sesSem);
733 else
734 return -EIO;
736 atomic_dec(&ses->inUse);
737 if (atomic_read(&ses->inUse) > 0) {
738 up(&ses->sesSem);
739 return -EBUSY;
741 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
742 if (rc) {
743 up(&ses->sesSem);
744 return rc;
747 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
749 if(ses->server) {
750 pSMB->hdr.Mid = GetNextMid(ses->server);
752 if(ses->server->secMode &
753 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
754 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
757 pSMB->hdr.Uid = ses->Suid;
759 pSMB->AndXCommand = 0xFF;
760 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
761 smb_buffer_response, &length, 0);
762 if (ses->server) {
763 atomic_dec(&ses->server->socketUseCount);
764 if (atomic_read(&ses->server->socketUseCount) == 0) {
765 spin_lock(&GlobalMid_Lock);
766 ses->server->tcpStatus = CifsExiting;
767 spin_unlock(&GlobalMid_Lock);
768 rc = -ESHUTDOWN;
771 up(&ses->sesSem);
772 cifs_small_buf_release(pSMB);
774 /* if session dead then we do not need to do ulogoff,
775 since server closed smb session, no sense reporting
776 error */
777 if (rc == -EAGAIN)
778 rc = 0;
779 return rc;
783 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
784 const struct nls_table *nls_codepage, int remap)
786 DELETE_FILE_REQ *pSMB = NULL;
787 DELETE_FILE_RSP *pSMBr = NULL;
788 int rc = 0;
789 int bytes_returned;
790 int name_len;
792 DelFileRetry:
793 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
794 (void **) &pSMBr);
795 if (rc)
796 return rc;
798 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
799 name_len =
800 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
801 PATH_MAX, nls_codepage, remap);
802 name_len++; /* trailing null */
803 name_len *= 2;
804 } else { /* BB improve check for buffer overruns BB */
805 name_len = strnlen(fileName, PATH_MAX);
806 name_len++; /* trailing null */
807 strncpy(pSMB->fileName, fileName, name_len);
809 pSMB->SearchAttributes =
810 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
811 pSMB->BufferFormat = 0x04;
812 pSMB->hdr.smb_buf_length += name_len + 1;
813 pSMB->ByteCount = cpu_to_le16(name_len + 1);
814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
816 cifs_stats_inc(&tcon->num_deletes);
817 if (rc) {
818 cFYI(1, ("Error in RMFile = %d", rc));
821 cifs_buf_release(pSMB);
822 if (rc == -EAGAIN)
823 goto DelFileRetry;
825 return rc;
829 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
830 const struct nls_table *nls_codepage, int remap)
832 DELETE_DIRECTORY_REQ *pSMB = NULL;
833 DELETE_DIRECTORY_RSP *pSMBr = NULL;
834 int rc = 0;
835 int bytes_returned;
836 int name_len;
838 cFYI(1, ("In CIFSSMBRmDir"));
839 RmDirRetry:
840 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
841 (void **) &pSMBr);
842 if (rc)
843 return rc;
845 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
846 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
847 PATH_MAX, nls_codepage, remap);
848 name_len++; /* trailing null */
849 name_len *= 2;
850 } else { /* BB improve check for buffer overruns BB */
851 name_len = strnlen(dirName, PATH_MAX);
852 name_len++; /* trailing null */
853 strncpy(pSMB->DirName, dirName, name_len);
856 pSMB->BufferFormat = 0x04;
857 pSMB->hdr.smb_buf_length += name_len + 1;
858 pSMB->ByteCount = cpu_to_le16(name_len + 1);
859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
861 cifs_stats_inc(&tcon->num_rmdirs);
862 if (rc) {
863 cFYI(1, ("Error in RMDir = %d", rc));
866 cifs_buf_release(pSMB);
867 if (rc == -EAGAIN)
868 goto RmDirRetry;
869 return rc;
873 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
874 const char *name, const struct nls_table *nls_codepage, int remap)
876 int rc = 0;
877 CREATE_DIRECTORY_REQ *pSMB = NULL;
878 CREATE_DIRECTORY_RSP *pSMBr = NULL;
879 int bytes_returned;
880 int name_len;
882 cFYI(1, ("In CIFSSMBMkDir"));
883 MkDirRetry:
884 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
885 (void **) &pSMBr);
886 if (rc)
887 return rc;
889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
890 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
891 PATH_MAX, nls_codepage, remap);
892 name_len++; /* trailing null */
893 name_len *= 2;
894 } else { /* BB improve check for buffer overruns BB */
895 name_len = strnlen(name, PATH_MAX);
896 name_len++; /* trailing null */
897 strncpy(pSMB->DirName, name, name_len);
900 pSMB->BufferFormat = 0x04;
901 pSMB->hdr.smb_buf_length += name_len + 1;
902 pSMB->ByteCount = cpu_to_le16(name_len + 1);
903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
905 cifs_stats_inc(&tcon->num_mkdirs);
906 if (rc) {
907 cFYI(1, ("Error in Mkdir = %d", rc));
910 cifs_buf_release(pSMB);
911 if (rc == -EAGAIN)
912 goto MkDirRetry;
913 return rc;
916 static __u16 convert_disposition(int disposition)
918 __u16 ofun = 0;
920 switch (disposition) {
921 case FILE_SUPERSEDE:
922 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
923 break;
924 case FILE_OPEN:
925 ofun = SMBOPEN_OAPPEND;
926 break;
927 case FILE_CREATE:
928 ofun = SMBOPEN_OCREATE;
929 break;
930 case FILE_OPEN_IF:
931 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
932 break;
933 case FILE_OVERWRITE:
934 ofun = SMBOPEN_OTRUNC;
935 break;
936 case FILE_OVERWRITE_IF:
937 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
938 break;
939 default:
940 cFYI(1,("unknown disposition %d",disposition));
941 ofun = SMBOPEN_OAPPEND; /* regular open */
943 return ofun;
947 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
948 const char *fileName, const int openDisposition,
949 const int access_flags, const int create_options, __u16 * netfid,
950 int *pOplock, FILE_ALL_INFO * pfile_info,
951 const struct nls_table *nls_codepage, int remap)
953 int rc = -EACCES;
954 OPENX_REQ *pSMB = NULL;
955 OPENX_RSP *pSMBr = NULL;
956 int bytes_returned;
957 int name_len;
958 __u16 count;
960 OldOpenRetry:
961 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
962 (void **) &pSMBr);
963 if (rc)
964 return rc;
966 pSMB->AndXCommand = 0xFF; /* none */
968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
969 count = 1; /* account for one byte pad to word boundary */
970 name_len =
971 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
972 fileName, PATH_MAX, nls_codepage, remap);
973 name_len++; /* trailing null */
974 name_len *= 2;
975 } else { /* BB improve check for buffer overruns BB */
976 count = 0; /* no pad */
977 name_len = strnlen(fileName, PATH_MAX);
978 name_len++; /* trailing null */
979 strncpy(pSMB->fileName, fileName, name_len);
981 if (*pOplock & REQ_OPLOCK)
982 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
983 else if (*pOplock & REQ_BATCHOPLOCK) {
984 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
986 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
987 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
988 /* 0 = read
989 1 = write
990 2 = rw
991 3 = execute
993 pSMB->Mode = cpu_to_le16(2);
994 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
995 /* set file as system file if special file such
996 as fifo and server expecting SFU style and
997 no Unix extensions */
999 if(create_options & CREATE_OPTION_SPECIAL)
1000 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1001 else
1002 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
1004 /* if ((omode & S_IWUGO) == 0)
1005 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1006 /* Above line causes problems due to vfs splitting create into two
1007 pieces - need to set mode after file created not while it is
1008 being created */
1010 /* BB FIXME BB */
1011 /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
1012 /* BB FIXME END BB */
1014 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1015 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1016 count += name_len;
1017 pSMB->hdr.smb_buf_length += count;
1019 pSMB->ByteCount = cpu_to_le16(count);
1020 /* long_op set to 1 to allow for oplock break timeouts */
1021 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1022 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1023 cifs_stats_inc(&tcon->num_opens);
1024 if (rc) {
1025 cFYI(1, ("Error in Open = %d", rc));
1026 } else {
1027 /* BB verify if wct == 15 */
1029 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1031 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1032 /* Let caller know file was created so we can set the mode. */
1033 /* Do we care about the CreateAction in any other cases? */
1034 /* BB FIXME BB */
1035 /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1036 *pOplock |= CIFS_CREATE_ACTION; */
1037 /* BB FIXME END */
1039 if(pfile_info) {
1040 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1041 pfile_info->LastAccessTime = 0; /* BB fixme */
1042 pfile_info->LastWriteTime = 0; /* BB fixme */
1043 pfile_info->ChangeTime = 0; /* BB fixme */
1044 pfile_info->Attributes =
1045 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1046 /* the file_info buf is endian converted by caller */
1047 pfile_info->AllocationSize =
1048 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1049 pfile_info->EndOfFile = pfile_info->AllocationSize;
1050 pfile_info->NumberOfLinks = cpu_to_le32(1);
1054 cifs_buf_release(pSMB);
1055 if (rc == -EAGAIN)
1056 goto OldOpenRetry;
1057 return rc;
1061 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1062 const char *fileName, const int openDisposition,
1063 const int access_flags, const int create_options, __u16 * netfid,
1064 int *pOplock, FILE_ALL_INFO * pfile_info,
1065 const struct nls_table *nls_codepage, int remap)
1067 int rc = -EACCES;
1068 OPEN_REQ *pSMB = NULL;
1069 OPEN_RSP *pSMBr = NULL;
1070 int bytes_returned;
1071 int name_len;
1072 __u16 count;
1074 openRetry:
1075 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1076 (void **) &pSMBr);
1077 if (rc)
1078 return rc;
1080 pSMB->AndXCommand = 0xFF; /* none */
1082 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1083 count = 1; /* account for one byte pad to word boundary */
1084 name_len =
1085 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1086 fileName, PATH_MAX, nls_codepage, remap);
1087 name_len++; /* trailing null */
1088 name_len *= 2;
1089 pSMB->NameLength = cpu_to_le16(name_len);
1090 } else { /* BB improve check for buffer overruns BB */
1091 count = 0; /* no pad */
1092 name_len = strnlen(fileName, PATH_MAX);
1093 name_len++; /* trailing null */
1094 pSMB->NameLength = cpu_to_le16(name_len);
1095 strncpy(pSMB->fileName, fileName, name_len);
1097 if (*pOplock & REQ_OPLOCK)
1098 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1099 else if (*pOplock & REQ_BATCHOPLOCK) {
1100 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1102 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1103 pSMB->AllocationSize = 0;
1104 /* set file as system file if special file such
1105 as fifo and server expecting SFU style and
1106 no Unix extensions */
1107 if(create_options & CREATE_OPTION_SPECIAL)
1108 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1109 else
1110 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1111 /* XP does not handle ATTR_POSIX_SEMANTICS */
1112 /* but it helps speed up case sensitive checks for other
1113 servers such as Samba */
1114 if (tcon->ses->capabilities & CAP_UNIX)
1115 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1117 /* if ((omode & S_IWUGO) == 0)
1118 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1119 /* Above line causes problems due to vfs splitting create into two
1120 pieces - need to set mode after file created not while it is
1121 being created */
1122 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1123 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1124 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1125 /* BB Expirement with various impersonation levels and verify */
1126 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1127 pSMB->SecurityFlags =
1128 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1130 count += name_len;
1131 pSMB->hdr.smb_buf_length += count;
1133 pSMB->ByteCount = cpu_to_le16(count);
1134 /* long_op set to 1 to allow for oplock break timeouts */
1135 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1136 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1137 cifs_stats_inc(&tcon->num_opens);
1138 if (rc) {
1139 cFYI(1, ("Error in Open = %d", rc));
1140 } else {
1141 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1142 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1143 /* Let caller know file was created so we can set the mode. */
1144 /* Do we care about the CreateAction in any other cases? */
1145 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1146 *pOplock |= CIFS_CREATE_ACTION;
1147 if(pfile_info) {
1148 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1149 36 /* CreationTime to Attributes */);
1150 /* the file_info buf is endian converted by caller */
1151 pfile_info->AllocationSize = pSMBr->AllocationSize;
1152 pfile_info->EndOfFile = pSMBr->EndOfFile;
1153 pfile_info->NumberOfLinks = cpu_to_le32(1);
1157 cifs_buf_release(pSMB);
1158 if (rc == -EAGAIN)
1159 goto openRetry;
1160 return rc;
1164 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
1165 const int netfid, const unsigned int count,
1166 const __u64 lseek, unsigned int *nbytes, char **buf,
1167 int * pbuf_type)
1169 int rc = -EACCES;
1170 READ_REQ *pSMB = NULL;
1171 READ_RSP *pSMBr = NULL;
1172 char *pReadData = NULL;
1173 int wct;
1174 int resp_buf_type = 0;
1175 struct kvec iov[1];
1177 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
1178 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1179 wct = 12;
1180 else
1181 wct = 10; /* old style read */
1183 *nbytes = 0;
1184 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1185 if (rc)
1186 return rc;
1188 /* tcon and ses pointer are checked in smb_init */
1189 if (tcon->ses->server == NULL)
1190 return -ECONNABORTED;
1192 pSMB->AndXCommand = 0xFF; /* none */
1193 pSMB->Fid = netfid;
1194 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1195 if(wct == 12)
1196 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1197 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1198 return -EIO;
1200 pSMB->Remaining = 0;
1201 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1202 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1203 if(wct == 12)
1204 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1205 else {
1206 /* old style read */
1207 struct smb_com_readx_req * pSMBW =
1208 (struct smb_com_readx_req *)pSMB;
1209 pSMBW->ByteCount = 0;
1212 iov[0].iov_base = (char *)pSMB;
1213 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1214 rc = SendReceive2(xid, tcon->ses, iov,
1215 1 /* num iovecs */,
1216 &resp_buf_type, 0);
1217 cifs_stats_inc(&tcon->num_reads);
1218 pSMBr = (READ_RSP *)iov[0].iov_base;
1219 if (rc) {
1220 cERROR(1, ("Send error in read = %d", rc));
1221 } else {
1222 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1223 data_length = data_length << 16;
1224 data_length += le16_to_cpu(pSMBr->DataLength);
1225 *nbytes = data_length;
1227 /*check that DataLength would not go beyond end of SMB */
1228 if ((data_length > CIFSMaxBufSize)
1229 || (data_length > count)) {
1230 cFYI(1,("bad length %d for count %d",data_length,count));
1231 rc = -EIO;
1232 *nbytes = 0;
1233 } else {
1234 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1235 le16_to_cpu(pSMBr->DataOffset);
1236 /* if(rc = copy_to_user(buf, pReadData, data_length)) {
1237 cERROR(1,("Faulting on read rc = %d",rc));
1238 rc = -EFAULT;
1239 }*/ /* can not use copy_to_user when using page cache*/
1240 if(*buf)
1241 memcpy(*buf,pReadData,data_length);
1245 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1246 if(*buf) {
1247 if(resp_buf_type == CIFS_SMALL_BUFFER)
1248 cifs_small_buf_release(iov[0].iov_base);
1249 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1250 cifs_buf_release(iov[0].iov_base);
1251 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1252 /* return buffer to caller to free */
1253 *buf = iov[0].iov_base;
1254 if(resp_buf_type == CIFS_SMALL_BUFFER)
1255 *pbuf_type = CIFS_SMALL_BUFFER;
1256 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1257 *pbuf_type = CIFS_LARGE_BUFFER;
1258 } /* else no valid buffer on return - leave as null */
1260 /* Note: On -EAGAIN error only caller can retry on handle based calls
1261 since file handle passed in no longer valid */
1262 return rc;
1267 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1268 const int netfid, const unsigned int count,
1269 const __u64 offset, unsigned int *nbytes, const char *buf,
1270 const char __user * ubuf, const int long_op)
1272 int rc = -EACCES;
1273 WRITE_REQ *pSMB = NULL;
1274 WRITE_RSP *pSMBr = NULL;
1275 int bytes_returned, wct;
1276 __u32 bytes_sent;
1277 __u16 byte_count;
1279 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1280 if(tcon->ses == NULL)
1281 return -ECONNABORTED;
1283 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1284 wct = 14;
1285 else
1286 wct = 12;
1288 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1289 (void **) &pSMBr);
1290 if (rc)
1291 return rc;
1292 /* tcon and ses pointer are checked in smb_init */
1293 if (tcon->ses->server == NULL)
1294 return -ECONNABORTED;
1296 pSMB->AndXCommand = 0xFF; /* none */
1297 pSMB->Fid = netfid;
1298 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1299 if(wct == 14)
1300 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1301 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1302 return -EIO;
1304 pSMB->Reserved = 0xFFFFFFFF;
1305 pSMB->WriteMode = 0;
1306 pSMB->Remaining = 0;
1308 /* Can increase buffer size if buffer is big enough in some cases - ie we
1309 can send more if LARGE_WRITE_X capability returned by the server and if
1310 our buffer is big enough or if we convert to iovecs on socket writes
1311 and eliminate the copy to the CIFS buffer */
1312 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1313 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1314 } else {
1315 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1316 & ~0xFF;
1319 if (bytes_sent > count)
1320 bytes_sent = count;
1321 pSMB->DataOffset =
1322 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1323 if(buf)
1324 memcpy(pSMB->Data,buf,bytes_sent);
1325 else if(ubuf) {
1326 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1327 cifs_buf_release(pSMB);
1328 return -EFAULT;
1330 } else if (count != 0) {
1331 /* No buffer */
1332 cifs_buf_release(pSMB);
1333 return -EINVAL;
1334 } /* else setting file size with write of zero bytes */
1335 if(wct == 14)
1336 byte_count = bytes_sent + 1; /* pad */
1337 else /* wct == 12 */ {
1338 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1340 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1341 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1342 pSMB->hdr.smb_buf_length += byte_count;
1344 if(wct == 14)
1345 pSMB->ByteCount = cpu_to_le16(byte_count);
1346 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
1347 struct smb_com_writex_req * pSMBW =
1348 (struct smb_com_writex_req *)pSMB;
1349 pSMBW->ByteCount = cpu_to_le16(byte_count);
1352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1353 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1354 cifs_stats_inc(&tcon->num_writes);
1355 if (rc) {
1356 cFYI(1, ("Send error in write = %d", rc));
1357 *nbytes = 0;
1358 } else {
1359 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1360 *nbytes = (*nbytes) << 16;
1361 *nbytes += le16_to_cpu(pSMBr->Count);
1364 cifs_buf_release(pSMB);
1366 /* Note: On -EAGAIN error only caller can retry on handle based calls
1367 since file handle passed in no longer valid */
1369 return rc;
1373 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1374 const int netfid, const unsigned int count,
1375 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1376 int n_vec, const int long_op)
1378 int rc = -EACCES;
1379 WRITE_REQ *pSMB = NULL;
1380 int wct;
1381 int smb_hdr_len;
1382 int resp_buf_type = 0;
1384 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1386 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1387 wct = 14;
1388 else
1389 wct = 12;
1390 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1391 if (rc)
1392 return rc;
1393 /* tcon and ses pointer are checked in smb_init */
1394 if (tcon->ses->server == NULL)
1395 return -ECONNABORTED;
1397 pSMB->AndXCommand = 0xFF; /* none */
1398 pSMB->Fid = netfid;
1399 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1400 if(wct == 14)
1401 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1402 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1403 return -EIO;
1404 pSMB->Reserved = 0xFFFFFFFF;
1405 pSMB->WriteMode = 0;
1406 pSMB->Remaining = 0;
1408 pSMB->DataOffset =
1409 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1411 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1412 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1413 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1414 if(wct == 14)
1415 pSMB->hdr.smb_buf_length += count+1;
1416 else /* wct == 12 */
1417 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1418 if(wct == 14)
1419 pSMB->ByteCount = cpu_to_le16(count + 1);
1420 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1421 struct smb_com_writex_req * pSMBW =
1422 (struct smb_com_writex_req *)pSMB;
1423 pSMBW->ByteCount = cpu_to_le16(count + 5);
1425 iov[0].iov_base = pSMB;
1426 if(wct == 14)
1427 iov[0].iov_len = smb_hdr_len + 4;
1428 else /* wct == 12 pad bigger by four bytes */
1429 iov[0].iov_len = smb_hdr_len + 8;
1432 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1433 long_op);
1434 cifs_stats_inc(&tcon->num_writes);
1435 if (rc) {
1436 cFYI(1, ("Send error Write2 = %d", rc));
1437 *nbytes = 0;
1438 } else if(resp_buf_type == 0) {
1439 /* presumably this can not happen, but best to be safe */
1440 rc = -EIO;
1441 *nbytes = 0;
1442 } else {
1443 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1444 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1445 *nbytes = (*nbytes) << 16;
1446 *nbytes += le16_to_cpu(pSMBr->Count);
1449 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1450 if(resp_buf_type == CIFS_SMALL_BUFFER)
1451 cifs_small_buf_release(iov[0].iov_base);
1452 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1453 cifs_buf_release(iov[0].iov_base);
1455 /* Note: On -EAGAIN error only caller can retry on handle based calls
1456 since file handle passed in no longer valid */
1458 return rc;
1463 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1464 const __u16 smb_file_id, const __u64 len,
1465 const __u64 offset, const __u32 numUnlock,
1466 const __u32 numLock, const __u8 lockType, const int waitFlag)
1468 int rc = 0;
1469 LOCK_REQ *pSMB = NULL;
1470 LOCK_RSP *pSMBr = NULL;
1471 int bytes_returned;
1472 int timeout = 0;
1473 __u16 count;
1475 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1476 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1478 if (rc)
1479 return rc;
1481 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1483 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1484 timeout = -1; /* no response expected */
1485 pSMB->Timeout = 0;
1486 } else if (waitFlag == TRUE) {
1487 timeout = 3; /* blocking operation, no timeout */
1488 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1489 } else {
1490 pSMB->Timeout = 0;
1493 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1494 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1495 pSMB->LockType = lockType;
1496 pSMB->AndXCommand = 0xFF; /* none */
1497 pSMB->Fid = smb_file_id; /* netfid stays le */
1499 if((numLock != 0) || (numUnlock != 0)) {
1500 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1501 /* BB where to store pid high? */
1502 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1503 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1504 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1505 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1506 count = sizeof(LOCKING_ANDX_RANGE);
1507 } else {
1508 /* oplock break */
1509 count = 0;
1511 pSMB->hdr.smb_buf_length += count;
1512 pSMB->ByteCount = cpu_to_le16(count);
1514 if (waitFlag) {
1515 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1516 (struct smb_hdr *) pSMBr, &bytes_returned);
1517 } else {
1518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1519 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1521 cifs_stats_inc(&tcon->num_locks);
1522 if (rc) {
1523 cFYI(1, ("Send error in Lock = %d", rc));
1525 cifs_small_buf_release(pSMB);
1527 /* Note: On -EAGAIN error only caller can retry on handle based calls
1528 since file handle passed in no longer valid */
1529 return rc;
1533 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1534 const __u16 smb_file_id, const int get_flag, const __u64 len,
1535 struct file_lock *pLockData, const __u16 lock_type,
1536 const int waitFlag)
1538 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1539 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1540 char *data_offset;
1541 struct cifs_posix_lock *parm_data;
1542 int rc = 0;
1543 int timeout = 0;
1544 int bytes_returned = 0;
1545 __u16 params, param_offset, offset, byte_count, count;
1547 cFYI(1, ("Posix Lock"));
1549 if(pLockData == NULL)
1550 return EINVAL;
1552 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1554 if (rc)
1555 return rc;
1557 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1559 params = 6;
1560 pSMB->MaxSetupCount = 0;
1561 pSMB->Reserved = 0;
1562 pSMB->Flags = 0;
1563 pSMB->Reserved2 = 0;
1564 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1565 offset = param_offset + params;
1567 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1569 count = sizeof(struct cifs_posix_lock);
1570 pSMB->MaxParameterCount = cpu_to_le16(2);
1571 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1572 pSMB->SetupCount = 1;
1573 pSMB->Reserved3 = 0;
1574 if(get_flag)
1575 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1576 else
1577 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1578 byte_count = 3 /* pad */ + params + count;
1579 pSMB->DataCount = cpu_to_le16(count);
1580 pSMB->ParameterCount = cpu_to_le16(params);
1581 pSMB->TotalDataCount = pSMB->DataCount;
1582 pSMB->TotalParameterCount = pSMB->ParameterCount;
1583 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1584 parm_data = (struct cifs_posix_lock *)
1585 (((char *) &pSMB->hdr.Protocol) + offset);
1587 parm_data->lock_type = cpu_to_le16(lock_type);
1588 if(waitFlag) {
1589 timeout = 3; /* blocking operation, no timeout */
1590 parm_data->lock_flags = cpu_to_le16(1);
1591 pSMB->Timeout = cpu_to_le32(-1);
1592 } else
1593 pSMB->Timeout = 0;
1595 parm_data->pid = cpu_to_le32(current->tgid);
1596 parm_data->start = cpu_to_le64(pLockData->fl_start);
1597 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1599 pSMB->DataOffset = cpu_to_le16(offset);
1600 pSMB->Fid = smb_file_id;
1601 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1602 pSMB->Reserved4 = 0;
1603 pSMB->hdr.smb_buf_length += byte_count;
1604 pSMB->ByteCount = cpu_to_le16(byte_count);
1605 if (waitFlag) {
1606 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1607 (struct smb_hdr *) pSMBr, &bytes_returned);
1608 } else {
1609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1610 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1613 if (rc) {
1614 cFYI(1, ("Send error in Posix Lock = %d", rc));
1615 } else if (get_flag) {
1616 /* lock structure can be returned on get */
1617 __u16 data_offset;
1618 __u16 data_count;
1619 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1621 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1622 rc = -EIO; /* bad smb */
1623 goto plk_err_exit;
1625 if(pLockData == NULL) {
1626 rc = -EINVAL;
1627 goto plk_err_exit;
1629 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1630 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1631 if(data_count < sizeof(struct cifs_posix_lock)) {
1632 rc = -EIO;
1633 goto plk_err_exit;
1635 parm_data = (struct cifs_posix_lock *)
1636 ((char *)&pSMBr->hdr.Protocol + data_offset);
1637 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1638 pLockData->fl_type = F_UNLCK;
1641 plk_err_exit:
1642 if (pSMB)
1643 cifs_small_buf_release(pSMB);
1645 /* Note: On -EAGAIN error only caller can retry on handle based calls
1646 since file handle passed in no longer valid */
1648 return rc;
1653 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1655 int rc = 0;
1656 CLOSE_REQ *pSMB = NULL;
1657 CLOSE_RSP *pSMBr = NULL;
1658 int bytes_returned;
1659 cFYI(1, ("In CIFSSMBClose"));
1661 /* do not retry on dead session on close */
1662 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1663 if(rc == -EAGAIN)
1664 return 0;
1665 if (rc)
1666 return rc;
1668 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1670 pSMB->FileID = (__u16) smb_file_id;
1671 pSMB->LastWriteTime = 0xFFFFFFFF;
1672 pSMB->ByteCount = 0;
1673 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1674 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1675 cifs_stats_inc(&tcon->num_closes);
1676 if (rc) {
1677 if(rc!=-EINTR) {
1678 /* EINTR is expected when user ctl-c to kill app */
1679 cERROR(1, ("Send error in Close = %d", rc));
1683 cifs_small_buf_release(pSMB);
1685 /* Since session is dead, file will be closed on server already */
1686 if(rc == -EAGAIN)
1687 rc = 0;
1689 return rc;
1693 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1694 const char *fromName, const char *toName,
1695 const struct nls_table *nls_codepage, int remap)
1697 int rc = 0;
1698 RENAME_REQ *pSMB = NULL;
1699 RENAME_RSP *pSMBr = NULL;
1700 int bytes_returned;
1701 int name_len, name_len2;
1702 __u16 count;
1704 cFYI(1, ("In CIFSSMBRename"));
1705 renameRetry:
1706 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1707 (void **) &pSMBr);
1708 if (rc)
1709 return rc;
1711 pSMB->BufferFormat = 0x04;
1712 pSMB->SearchAttributes =
1713 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1714 ATTR_DIRECTORY);
1716 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1717 name_len =
1718 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1719 PATH_MAX, nls_codepage, remap);
1720 name_len++; /* trailing null */
1721 name_len *= 2;
1722 pSMB->OldFileName[name_len] = 0x04; /* pad */
1723 /* protocol requires ASCII signature byte on Unicode string */
1724 pSMB->OldFileName[name_len + 1] = 0x00;
1725 name_len2 =
1726 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1727 toName, PATH_MAX, nls_codepage, remap);
1728 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1729 name_len2 *= 2; /* convert to bytes */
1730 } else { /* BB improve the check for buffer overruns BB */
1731 name_len = strnlen(fromName, PATH_MAX);
1732 name_len++; /* trailing null */
1733 strncpy(pSMB->OldFileName, fromName, name_len);
1734 name_len2 = strnlen(toName, PATH_MAX);
1735 name_len2++; /* trailing null */
1736 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1737 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1738 name_len2++; /* trailing null */
1739 name_len2++; /* signature byte */
1742 count = 1 /* 1st signature byte */ + name_len + name_len2;
1743 pSMB->hdr.smb_buf_length += count;
1744 pSMB->ByteCount = cpu_to_le16(count);
1746 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1747 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1748 cifs_stats_inc(&tcon->num_renames);
1749 if (rc) {
1750 cFYI(1, ("Send error in rename = %d", rc));
1753 cifs_buf_release(pSMB);
1755 if (rc == -EAGAIN)
1756 goto renameRetry;
1758 return rc;
1761 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1762 int netfid, char * target_name,
1763 const struct nls_table * nls_codepage, int remap)
1765 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1766 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1767 struct set_file_rename * rename_info;
1768 char *data_offset;
1769 char dummy_string[30];
1770 int rc = 0;
1771 int bytes_returned = 0;
1772 int len_of_str;
1773 __u16 params, param_offset, offset, count, byte_count;
1775 cFYI(1, ("Rename to File by handle"));
1776 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1777 (void **) &pSMBr);
1778 if (rc)
1779 return rc;
1781 params = 6;
1782 pSMB->MaxSetupCount = 0;
1783 pSMB->Reserved = 0;
1784 pSMB->Flags = 0;
1785 pSMB->Timeout = 0;
1786 pSMB->Reserved2 = 0;
1787 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1788 offset = param_offset + params;
1790 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1791 rename_info = (struct set_file_rename *) data_offset;
1792 pSMB->MaxParameterCount = cpu_to_le16(2);
1793 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1794 pSMB->SetupCount = 1;
1795 pSMB->Reserved3 = 0;
1796 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1797 byte_count = 3 /* pad */ + params;
1798 pSMB->ParameterCount = cpu_to_le16(params);
1799 pSMB->TotalParameterCount = pSMB->ParameterCount;
1800 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1801 pSMB->DataOffset = cpu_to_le16(offset);
1802 /* construct random name ".cifs_tmp<inodenum><mid>" */
1803 rename_info->overwrite = cpu_to_le32(1);
1804 rename_info->root_fid = 0;
1805 /* unicode only call */
1806 if(target_name == NULL) {
1807 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1808 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1809 dummy_string, 24, nls_codepage, remap);
1810 } else {
1811 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1812 target_name, PATH_MAX, nls_codepage, remap);
1814 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1815 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1816 byte_count += count;
1817 pSMB->DataCount = cpu_to_le16(count);
1818 pSMB->TotalDataCount = pSMB->DataCount;
1819 pSMB->Fid = netfid;
1820 pSMB->InformationLevel =
1821 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1822 pSMB->Reserved4 = 0;
1823 pSMB->hdr.smb_buf_length += byte_count;
1824 pSMB->ByteCount = cpu_to_le16(byte_count);
1825 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1826 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1827 cifs_stats_inc(&pTcon->num_t2renames);
1828 if (rc) {
1829 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1832 cifs_buf_release(pSMB);
1834 /* Note: On -EAGAIN error only caller can retry on handle based calls
1835 since file handle passed in no longer valid */
1837 return rc;
1841 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1842 const __u16 target_tid, const char *toName, const int flags,
1843 const struct nls_table *nls_codepage, int remap)
1845 int rc = 0;
1846 COPY_REQ *pSMB = NULL;
1847 COPY_RSP *pSMBr = NULL;
1848 int bytes_returned;
1849 int name_len, name_len2;
1850 __u16 count;
1852 cFYI(1, ("In CIFSSMBCopy"));
1853 copyRetry:
1854 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1855 (void **) &pSMBr);
1856 if (rc)
1857 return rc;
1859 pSMB->BufferFormat = 0x04;
1860 pSMB->Tid2 = target_tid;
1862 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1864 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1865 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1866 fromName, PATH_MAX, nls_codepage,
1867 remap);
1868 name_len++; /* trailing null */
1869 name_len *= 2;
1870 pSMB->OldFileName[name_len] = 0x04; /* pad */
1871 /* protocol requires ASCII signature byte on Unicode string */
1872 pSMB->OldFileName[name_len + 1] = 0x00;
1873 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1874 toName, PATH_MAX, nls_codepage, remap);
1875 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1876 name_len2 *= 2; /* convert to bytes */
1877 } else { /* BB improve the check for buffer overruns BB */
1878 name_len = strnlen(fromName, PATH_MAX);
1879 name_len++; /* trailing null */
1880 strncpy(pSMB->OldFileName, fromName, name_len);
1881 name_len2 = strnlen(toName, PATH_MAX);
1882 name_len2++; /* trailing null */
1883 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1884 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1885 name_len2++; /* trailing null */
1886 name_len2++; /* signature byte */
1889 count = 1 /* 1st signature byte */ + name_len + name_len2;
1890 pSMB->hdr.smb_buf_length += count;
1891 pSMB->ByteCount = cpu_to_le16(count);
1893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1895 if (rc) {
1896 cFYI(1, ("Send error in copy = %d with %d files copied",
1897 rc, le16_to_cpu(pSMBr->CopyCount)));
1899 if (pSMB)
1900 cifs_buf_release(pSMB);
1902 if (rc == -EAGAIN)
1903 goto copyRetry;
1905 return rc;
1909 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1910 const char *fromName, const char *toName,
1911 const struct nls_table *nls_codepage)
1913 TRANSACTION2_SPI_REQ *pSMB = NULL;
1914 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1915 char *data_offset;
1916 int name_len;
1917 int name_len_target;
1918 int rc = 0;
1919 int bytes_returned = 0;
1920 __u16 params, param_offset, offset, byte_count;
1922 cFYI(1, ("In Symlink Unix style"));
1923 createSymLinkRetry:
1924 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1925 (void **) &pSMBr);
1926 if (rc)
1927 return rc;
1929 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1930 name_len =
1931 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1932 /* find define for this maxpathcomponent */
1933 , nls_codepage);
1934 name_len++; /* trailing null */
1935 name_len *= 2;
1937 } else { /* BB improve the check for buffer overruns BB */
1938 name_len = strnlen(fromName, PATH_MAX);
1939 name_len++; /* trailing null */
1940 strncpy(pSMB->FileName, fromName, name_len);
1942 params = 6 + name_len;
1943 pSMB->MaxSetupCount = 0;
1944 pSMB->Reserved = 0;
1945 pSMB->Flags = 0;
1946 pSMB->Timeout = 0;
1947 pSMB->Reserved2 = 0;
1948 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1949 InformationLevel) - 4;
1950 offset = param_offset + params;
1952 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1954 name_len_target =
1955 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1956 /* find define for this maxpathcomponent */
1957 , nls_codepage);
1958 name_len_target++; /* trailing null */
1959 name_len_target *= 2;
1960 } else { /* BB improve the check for buffer overruns BB */
1961 name_len_target = strnlen(toName, PATH_MAX);
1962 name_len_target++; /* trailing null */
1963 strncpy(data_offset, toName, name_len_target);
1966 pSMB->MaxParameterCount = cpu_to_le16(2);
1967 /* BB find exact max on data count below from sess */
1968 pSMB->MaxDataCount = cpu_to_le16(1000);
1969 pSMB->SetupCount = 1;
1970 pSMB->Reserved3 = 0;
1971 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1972 byte_count = 3 /* pad */ + params + name_len_target;
1973 pSMB->DataCount = cpu_to_le16(name_len_target);
1974 pSMB->ParameterCount = cpu_to_le16(params);
1975 pSMB->TotalDataCount = pSMB->DataCount;
1976 pSMB->TotalParameterCount = pSMB->ParameterCount;
1977 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1978 pSMB->DataOffset = cpu_to_le16(offset);
1979 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1980 pSMB->Reserved4 = 0;
1981 pSMB->hdr.smb_buf_length += byte_count;
1982 pSMB->ByteCount = cpu_to_le16(byte_count);
1983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1985 cifs_stats_inc(&tcon->num_symlinks);
1986 if (rc) {
1987 cFYI(1,
1988 ("Send error in SetPathInfo (create symlink) = %d",
1989 rc));
1992 if (pSMB)
1993 cifs_buf_release(pSMB);
1995 if (rc == -EAGAIN)
1996 goto createSymLinkRetry;
1998 return rc;
2002 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2003 const char *fromName, const char *toName,
2004 const struct nls_table *nls_codepage, int remap)
2006 TRANSACTION2_SPI_REQ *pSMB = NULL;
2007 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2008 char *data_offset;
2009 int name_len;
2010 int name_len_target;
2011 int rc = 0;
2012 int bytes_returned = 0;
2013 __u16 params, param_offset, offset, byte_count;
2015 cFYI(1, ("In Create Hard link Unix style"));
2016 createHardLinkRetry:
2017 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2018 (void **) &pSMBr);
2019 if (rc)
2020 return rc;
2022 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2023 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2024 PATH_MAX, nls_codepage, remap);
2025 name_len++; /* trailing null */
2026 name_len *= 2;
2028 } else { /* BB improve the check for buffer overruns BB */
2029 name_len = strnlen(toName, PATH_MAX);
2030 name_len++; /* trailing null */
2031 strncpy(pSMB->FileName, toName, name_len);
2033 params = 6 + name_len;
2034 pSMB->MaxSetupCount = 0;
2035 pSMB->Reserved = 0;
2036 pSMB->Flags = 0;
2037 pSMB->Timeout = 0;
2038 pSMB->Reserved2 = 0;
2039 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2040 InformationLevel) - 4;
2041 offset = param_offset + params;
2043 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2045 name_len_target =
2046 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2047 nls_codepage, remap);
2048 name_len_target++; /* trailing null */
2049 name_len_target *= 2;
2050 } else { /* BB improve the check for buffer overruns BB */
2051 name_len_target = strnlen(fromName, PATH_MAX);
2052 name_len_target++; /* trailing null */
2053 strncpy(data_offset, fromName, name_len_target);
2056 pSMB->MaxParameterCount = cpu_to_le16(2);
2057 /* BB find exact max on data count below from sess*/
2058 pSMB->MaxDataCount = cpu_to_le16(1000);
2059 pSMB->SetupCount = 1;
2060 pSMB->Reserved3 = 0;
2061 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2062 byte_count = 3 /* pad */ + params + name_len_target;
2063 pSMB->ParameterCount = cpu_to_le16(params);
2064 pSMB->TotalParameterCount = pSMB->ParameterCount;
2065 pSMB->DataCount = cpu_to_le16(name_len_target);
2066 pSMB->TotalDataCount = pSMB->DataCount;
2067 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2068 pSMB->DataOffset = cpu_to_le16(offset);
2069 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2070 pSMB->Reserved4 = 0;
2071 pSMB->hdr.smb_buf_length += byte_count;
2072 pSMB->ByteCount = cpu_to_le16(byte_count);
2073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2075 cifs_stats_inc(&tcon->num_hardlinks);
2076 if (rc) {
2077 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2080 cifs_buf_release(pSMB);
2081 if (rc == -EAGAIN)
2082 goto createHardLinkRetry;
2084 return rc;
2088 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2089 const char *fromName, const char *toName,
2090 const struct nls_table *nls_codepage, int remap)
2092 int rc = 0;
2093 NT_RENAME_REQ *pSMB = NULL;
2094 RENAME_RSP *pSMBr = NULL;
2095 int bytes_returned;
2096 int name_len, name_len2;
2097 __u16 count;
2099 cFYI(1, ("In CIFSCreateHardLink"));
2100 winCreateHardLinkRetry:
2102 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2103 (void **) &pSMBr);
2104 if (rc)
2105 return rc;
2107 pSMB->SearchAttributes =
2108 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2109 ATTR_DIRECTORY);
2110 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2111 pSMB->ClusterCount = 0;
2113 pSMB->BufferFormat = 0x04;
2115 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2116 name_len =
2117 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2118 PATH_MAX, nls_codepage, remap);
2119 name_len++; /* trailing null */
2120 name_len *= 2;
2121 pSMB->OldFileName[name_len] = 0; /* pad */
2122 pSMB->OldFileName[name_len + 1] = 0x04;
2123 name_len2 =
2124 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2125 toName, PATH_MAX, nls_codepage, remap);
2126 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2127 name_len2 *= 2; /* convert to bytes */
2128 } else { /* BB improve the check for buffer overruns BB */
2129 name_len = strnlen(fromName, PATH_MAX);
2130 name_len++; /* trailing null */
2131 strncpy(pSMB->OldFileName, fromName, name_len);
2132 name_len2 = strnlen(toName, PATH_MAX);
2133 name_len2++; /* trailing null */
2134 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2135 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2136 name_len2++; /* trailing null */
2137 name_len2++; /* signature byte */
2140 count = 1 /* string type byte */ + name_len + name_len2;
2141 pSMB->hdr.smb_buf_length += count;
2142 pSMB->ByteCount = cpu_to_le16(count);
2144 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2145 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2146 cifs_stats_inc(&tcon->num_hardlinks);
2147 if (rc) {
2148 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2150 cifs_buf_release(pSMB);
2151 if (rc == -EAGAIN)
2152 goto winCreateHardLinkRetry;
2154 return rc;
2158 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2159 const unsigned char *searchName,
2160 char *symlinkinfo, const int buflen,
2161 const struct nls_table *nls_codepage)
2163 /* SMB_QUERY_FILE_UNIX_LINK */
2164 TRANSACTION2_QPI_REQ *pSMB = NULL;
2165 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2166 int rc = 0;
2167 int bytes_returned;
2168 int name_len;
2169 __u16 params, byte_count;
2171 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2173 querySymLinkRetry:
2174 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2175 (void **) &pSMBr);
2176 if (rc)
2177 return rc;
2179 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2180 name_len =
2181 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2182 /* find define for this maxpathcomponent */
2183 , nls_codepage);
2184 name_len++; /* trailing null */
2185 name_len *= 2;
2186 } else { /* BB improve the check for buffer overruns BB */
2187 name_len = strnlen(searchName, PATH_MAX);
2188 name_len++; /* trailing null */
2189 strncpy(pSMB->FileName, searchName, name_len);
2192 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2193 pSMB->TotalDataCount = 0;
2194 pSMB->MaxParameterCount = cpu_to_le16(2);
2195 /* BB find exact max data count below from sess structure BB */
2196 pSMB->MaxDataCount = cpu_to_le16(4000);
2197 pSMB->MaxSetupCount = 0;
2198 pSMB->Reserved = 0;
2199 pSMB->Flags = 0;
2200 pSMB->Timeout = 0;
2201 pSMB->Reserved2 = 0;
2202 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2203 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2204 pSMB->DataCount = 0;
2205 pSMB->DataOffset = 0;
2206 pSMB->SetupCount = 1;
2207 pSMB->Reserved3 = 0;
2208 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2209 byte_count = params + 1 /* pad */ ;
2210 pSMB->TotalParameterCount = cpu_to_le16(params);
2211 pSMB->ParameterCount = pSMB->TotalParameterCount;
2212 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2213 pSMB->Reserved4 = 0;
2214 pSMB->hdr.smb_buf_length += byte_count;
2215 pSMB->ByteCount = cpu_to_le16(byte_count);
2217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2219 if (rc) {
2220 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2221 } else {
2222 /* decode response */
2224 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2225 if (rc || (pSMBr->ByteCount < 2))
2226 /* BB also check enough total bytes returned */
2227 rc = -EIO; /* bad smb */
2228 else {
2229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2230 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2232 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2233 name_len = UniStrnlen((wchar_t *) ((char *)
2234 &pSMBr->hdr.Protocol +data_offset),
2235 min_t(const int, buflen,count) / 2);
2236 /* BB FIXME investigate remapping reserved chars here */
2237 cifs_strfromUCS_le(symlinkinfo,
2238 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
2239 data_offset),
2240 name_len, nls_codepage);
2241 } else {
2242 strncpy(symlinkinfo,
2243 (char *) &pSMBr->hdr.Protocol +
2244 data_offset,
2245 min_t(const int, buflen, count));
2247 symlinkinfo[buflen] = 0;
2248 /* just in case so calling code does not go off the end of buffer */
2251 cifs_buf_release(pSMB);
2252 if (rc == -EAGAIN)
2253 goto querySymLinkRetry;
2254 return rc;
2257 /* Initialize NT TRANSACT SMB into small smb request buffer.
2258 This assumes that all NT TRANSACTS that we init here have
2259 total parm and data under about 400 bytes (to fit in small cifs
2260 buffer size), which is the case so far, it easily fits. NB:
2261 Setup words themselves and ByteCount
2262 MaxSetupCount (size of returned setup area) and
2263 MaxParameterCount (returned parms size) must be set by caller */
2264 static int
2265 smb_init_ntransact(const __u16 sub_command, const int setup_count,
2266 const int parm_len, struct cifsTconInfo *tcon,
2267 void ** ret_buf)
2269 int rc;
2270 __u32 temp_offset;
2271 struct smb_com_ntransact_req * pSMB;
2273 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2274 (void **)&pSMB);
2275 if (rc)
2276 return rc;
2277 *ret_buf = (void *)pSMB;
2278 pSMB->Reserved = 0;
2279 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2280 pSMB->TotalDataCount = 0;
2281 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2282 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2283 pSMB->ParameterCount = pSMB->TotalParameterCount;
2284 pSMB->DataCount = pSMB->TotalDataCount;
2285 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2286 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2287 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2288 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2289 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2290 pSMB->SubCommand = cpu_to_le16(sub_command);
2291 return 0;
2294 static int
2295 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2296 int * pdatalen, int * pparmlen)
2298 char * end_of_smb;
2299 __u32 data_count, data_offset, parm_count, parm_offset;
2300 struct smb_com_ntransact_rsp * pSMBr;
2302 if(buf == NULL)
2303 return -EINVAL;
2305 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2307 /* ByteCount was converted from little endian in SendReceive */
2308 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2309 (char *)&pSMBr->ByteCount;
2312 data_offset = le32_to_cpu(pSMBr->DataOffset);
2313 data_count = le32_to_cpu(pSMBr->DataCount);
2314 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2315 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2317 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2318 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2320 /* should we also check that parm and data areas do not overlap? */
2321 if(*ppparm > end_of_smb) {
2322 cFYI(1,("parms start after end of smb"));
2323 return -EINVAL;
2324 } else if(parm_count + *ppparm > end_of_smb) {
2325 cFYI(1,("parm end after end of smb"));
2326 return -EINVAL;
2327 } else if(*ppdata > end_of_smb) {
2328 cFYI(1,("data starts after end of smb"));
2329 return -EINVAL;
2330 } else if(data_count + *ppdata > end_of_smb) {
2331 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2332 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2333 return -EINVAL;
2334 } else if(parm_count + data_count > pSMBr->ByteCount) {
2335 cFYI(1,("parm count and data count larger than SMB"));
2336 return -EINVAL;
2338 return 0;
2342 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2343 const unsigned char *searchName,
2344 char *symlinkinfo, const int buflen,__u16 fid,
2345 const struct nls_table *nls_codepage)
2347 int rc = 0;
2348 int bytes_returned;
2349 int name_len;
2350 struct smb_com_transaction_ioctl_req * pSMB;
2351 struct smb_com_transaction_ioctl_rsp * pSMBr;
2353 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2354 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2355 (void **) &pSMBr);
2356 if (rc)
2357 return rc;
2359 pSMB->TotalParameterCount = 0 ;
2360 pSMB->TotalDataCount = 0;
2361 pSMB->MaxParameterCount = cpu_to_le32(2);
2362 /* BB find exact data count max from sess structure BB */
2363 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2364 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2365 pSMB->MaxSetupCount = 4;
2366 pSMB->Reserved = 0;
2367 pSMB->ParameterOffset = 0;
2368 pSMB->DataCount = 0;
2369 pSMB->DataOffset = 0;
2370 pSMB->SetupCount = 4;
2371 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2372 pSMB->ParameterCount = pSMB->TotalParameterCount;
2373 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2374 pSMB->IsFsctl = 1; /* FSCTL */
2375 pSMB->IsRootFlag = 0;
2376 pSMB->Fid = fid; /* file handle always le */
2377 pSMB->ByteCount = 0;
2379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2380 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2381 if (rc) {
2382 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2383 } else { /* decode response */
2384 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2385 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2386 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2387 /* BB also check enough total bytes returned */
2388 rc = -EIO; /* bad smb */
2389 else {
2390 if(data_count && (data_count < 2048)) {
2391 char * end_of_smb = 2 /* sizeof byte count */ +
2392 pSMBr->ByteCount +
2393 (char *)&pSMBr->ByteCount;
2395 struct reparse_data * reparse_buf = (struct reparse_data *)
2396 ((char *)&pSMBr->hdr.Protocol + data_offset);
2397 if((char*)reparse_buf >= end_of_smb) {
2398 rc = -EIO;
2399 goto qreparse_out;
2401 if((reparse_buf->LinkNamesBuf +
2402 reparse_buf->TargetNameOffset +
2403 reparse_buf->TargetNameLen) >
2404 end_of_smb) {
2405 cFYI(1,("reparse buf extended beyond SMB"));
2406 rc = -EIO;
2407 goto qreparse_out;
2410 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2411 name_len = UniStrnlen((wchar_t *)
2412 (reparse_buf->LinkNamesBuf +
2413 reparse_buf->TargetNameOffset),
2414 min(buflen/2, reparse_buf->TargetNameLen / 2));
2415 cifs_strfromUCS_le(symlinkinfo,
2416 (__le16 *) (reparse_buf->LinkNamesBuf +
2417 reparse_buf->TargetNameOffset),
2418 name_len, nls_codepage);
2419 } else { /* ASCII names */
2420 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2421 reparse_buf->TargetNameOffset,
2422 min_t(const int, buflen, reparse_buf->TargetNameLen));
2424 } else {
2425 rc = -EIO;
2426 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2428 symlinkinfo[buflen] = 0; /* just in case so the caller
2429 does not go off the end of the buffer */
2430 cFYI(1,("readlink result - %s",symlinkinfo));
2433 qreparse_out:
2434 cifs_buf_release(pSMB);
2436 /* Note: On -EAGAIN error only caller can retry on handle based calls
2437 since file handle passed in no longer valid */
2439 return rc;
2442 #ifdef CONFIG_CIFS_POSIX
2444 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2445 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2447 /* u8 cifs fields do not need le conversion */
2448 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2449 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2450 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2451 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2453 return;
2456 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2457 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2458 const int acl_type,const int size_of_data_area)
2460 int size = 0;
2461 int i;
2462 __u16 count;
2463 struct cifs_posix_ace * pACE;
2464 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2465 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2467 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2468 return -EOPNOTSUPP;
2470 if(acl_type & ACL_TYPE_ACCESS) {
2471 count = le16_to_cpu(cifs_acl->access_entry_count);
2472 pACE = &cifs_acl->ace_array[0];
2473 size = sizeof(struct cifs_posix_acl);
2474 size += sizeof(struct cifs_posix_ace) * count;
2475 /* check if we would go beyond end of SMB */
2476 if(size_of_data_area < size) {
2477 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2478 return -EINVAL;
2480 } else if(acl_type & ACL_TYPE_DEFAULT) {
2481 count = le16_to_cpu(cifs_acl->access_entry_count);
2482 size = sizeof(struct cifs_posix_acl);
2483 size += sizeof(struct cifs_posix_ace) * count;
2484 /* skip past access ACEs to get to default ACEs */
2485 pACE = &cifs_acl->ace_array[count];
2486 count = le16_to_cpu(cifs_acl->default_entry_count);
2487 size += sizeof(struct cifs_posix_ace) * count;
2488 /* check if we would go beyond end of SMB */
2489 if(size_of_data_area < size)
2490 return -EINVAL;
2491 } else {
2492 /* illegal type */
2493 return -EINVAL;
2496 size = posix_acl_xattr_size(count);
2497 if((buflen == 0) || (local_acl == NULL)) {
2498 /* used to query ACL EA size */
2499 } else if(size > buflen) {
2500 return -ERANGE;
2501 } else /* buffer big enough */ {
2502 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2503 for(i = 0;i < count ;i++) {
2504 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2505 pACE ++;
2508 return size;
2511 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2512 const posix_acl_xattr_entry * local_ace)
2514 __u16 rc = 0; /* 0 = ACL converted ok */
2516 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2517 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2518 /* BB is there a better way to handle the large uid? */
2519 if(local_ace->e_id == cpu_to_le32(-1)) {
2520 /* Probably no need to le convert -1 on any arch but can not hurt */
2521 cifs_ace->cifs_uid = cpu_to_le64(-1);
2522 } else
2523 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2524 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2525 return rc;
2528 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2529 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2530 const int acl_type)
2532 __u16 rc = 0;
2533 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2534 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2535 int count;
2536 int i;
2538 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2539 return 0;
2541 count = posix_acl_xattr_count((size_t)buflen);
2542 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2543 count, buflen, le32_to_cpu(local_acl->a_version)));
2544 if(le32_to_cpu(local_acl->a_version) != 2) {
2545 cFYI(1,("unknown POSIX ACL version %d",
2546 le32_to_cpu(local_acl->a_version)));
2547 return 0;
2549 cifs_acl->version = cpu_to_le16(1);
2550 if(acl_type == ACL_TYPE_ACCESS)
2551 cifs_acl->access_entry_count = cpu_to_le16(count);
2552 else if(acl_type == ACL_TYPE_DEFAULT)
2553 cifs_acl->default_entry_count = cpu_to_le16(count);
2554 else {
2555 cFYI(1,("unknown ACL type %d",acl_type));
2556 return 0;
2558 for(i=0;i<count;i++) {
2559 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2560 &local_acl->a_entries[i]);
2561 if(rc != 0) {
2562 /* ACE not converted */
2563 break;
2566 if(rc == 0) {
2567 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2568 rc += sizeof(struct cifs_posix_acl);
2569 /* BB add check to make sure ACL does not overflow SMB */
2571 return rc;
2575 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2576 const unsigned char *searchName,
2577 char *acl_inf, const int buflen, const int acl_type,
2578 const struct nls_table *nls_codepage, int remap)
2580 /* SMB_QUERY_POSIX_ACL */
2581 TRANSACTION2_QPI_REQ *pSMB = NULL;
2582 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2583 int rc = 0;
2584 int bytes_returned;
2585 int name_len;
2586 __u16 params, byte_count;
2588 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2590 queryAclRetry:
2591 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2592 (void **) &pSMBr);
2593 if (rc)
2594 return rc;
2596 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2597 name_len =
2598 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2599 PATH_MAX, nls_codepage, remap);
2600 name_len++; /* trailing null */
2601 name_len *= 2;
2602 pSMB->FileName[name_len] = 0;
2603 pSMB->FileName[name_len+1] = 0;
2604 } else { /* BB improve the check for buffer overruns BB */
2605 name_len = strnlen(searchName, PATH_MAX);
2606 name_len++; /* trailing null */
2607 strncpy(pSMB->FileName, searchName, name_len);
2610 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2611 pSMB->TotalDataCount = 0;
2612 pSMB->MaxParameterCount = cpu_to_le16(2);
2613 /* BB find exact max data count below from sess structure BB */
2614 pSMB->MaxDataCount = cpu_to_le16(4000);
2615 pSMB->MaxSetupCount = 0;
2616 pSMB->Reserved = 0;
2617 pSMB->Flags = 0;
2618 pSMB->Timeout = 0;
2619 pSMB->Reserved2 = 0;
2620 pSMB->ParameterOffset = cpu_to_le16(
2621 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2622 pSMB->DataCount = 0;
2623 pSMB->DataOffset = 0;
2624 pSMB->SetupCount = 1;
2625 pSMB->Reserved3 = 0;
2626 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2627 byte_count = params + 1 /* pad */ ;
2628 pSMB->TotalParameterCount = cpu_to_le16(params);
2629 pSMB->ParameterCount = pSMB->TotalParameterCount;
2630 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2631 pSMB->Reserved4 = 0;
2632 pSMB->hdr.smb_buf_length += byte_count;
2633 pSMB->ByteCount = cpu_to_le16(byte_count);
2635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2637 cifs_stats_inc(&tcon->num_acl_get);
2638 if (rc) {
2639 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2640 } else {
2641 /* decode response */
2643 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2644 if (rc || (pSMBr->ByteCount < 2))
2645 /* BB also check enough total bytes returned */
2646 rc = -EIO; /* bad smb */
2647 else {
2648 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2649 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2650 rc = cifs_copy_posix_acl(acl_inf,
2651 (char *)&pSMBr->hdr.Protocol+data_offset,
2652 buflen,acl_type,count);
2655 cifs_buf_release(pSMB);
2656 if (rc == -EAGAIN)
2657 goto queryAclRetry;
2658 return rc;
2662 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2663 const unsigned char *fileName,
2664 const char *local_acl, const int buflen,
2665 const int acl_type,
2666 const struct nls_table *nls_codepage, int remap)
2668 struct smb_com_transaction2_spi_req *pSMB = NULL;
2669 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2670 char *parm_data;
2671 int name_len;
2672 int rc = 0;
2673 int bytes_returned = 0;
2674 __u16 params, byte_count, data_count, param_offset, offset;
2676 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2677 setAclRetry:
2678 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2679 (void **) &pSMBr);
2680 if (rc)
2681 return rc;
2682 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2683 name_len =
2684 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2685 PATH_MAX, nls_codepage, remap);
2686 name_len++; /* trailing null */
2687 name_len *= 2;
2688 } else { /* BB improve the check for buffer overruns BB */
2689 name_len = strnlen(fileName, PATH_MAX);
2690 name_len++; /* trailing null */
2691 strncpy(pSMB->FileName, fileName, name_len);
2693 params = 6 + name_len;
2694 pSMB->MaxParameterCount = cpu_to_le16(2);
2695 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2696 pSMB->MaxSetupCount = 0;
2697 pSMB->Reserved = 0;
2698 pSMB->Flags = 0;
2699 pSMB->Timeout = 0;
2700 pSMB->Reserved2 = 0;
2701 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2702 InformationLevel) - 4;
2703 offset = param_offset + params;
2704 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2705 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2707 /* convert to on the wire format for POSIX ACL */
2708 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2710 if(data_count == 0) {
2711 rc = -EOPNOTSUPP;
2712 goto setACLerrorExit;
2714 pSMB->DataOffset = cpu_to_le16(offset);
2715 pSMB->SetupCount = 1;
2716 pSMB->Reserved3 = 0;
2717 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2718 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2719 byte_count = 3 /* pad */ + params + data_count;
2720 pSMB->DataCount = cpu_to_le16(data_count);
2721 pSMB->TotalDataCount = pSMB->DataCount;
2722 pSMB->ParameterCount = cpu_to_le16(params);
2723 pSMB->TotalParameterCount = pSMB->ParameterCount;
2724 pSMB->Reserved4 = 0;
2725 pSMB->hdr.smb_buf_length += byte_count;
2726 pSMB->ByteCount = cpu_to_le16(byte_count);
2727 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2728 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2729 if (rc) {
2730 cFYI(1, ("Set POSIX ACL returned %d", rc));
2733 setACLerrorExit:
2734 cifs_buf_release(pSMB);
2735 if (rc == -EAGAIN)
2736 goto setAclRetry;
2737 return rc;
2740 /* BB fix tabs in this function FIXME BB */
2742 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2743 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2745 int rc = 0;
2746 struct smb_t2_qfi_req *pSMB = NULL;
2747 struct smb_t2_qfi_rsp *pSMBr = NULL;
2748 int bytes_returned;
2749 __u16 params, byte_count;
2751 cFYI(1,("In GetExtAttr"));
2752 if(tcon == NULL)
2753 return -ENODEV;
2755 GetExtAttrRetry:
2756 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2757 (void **) &pSMBr);
2758 if (rc)
2759 return rc;
2761 params = 2 /* level */ +2 /* fid */;
2762 pSMB->t2.TotalDataCount = 0;
2763 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2764 /* BB find exact max data count below from sess structure BB */
2765 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2766 pSMB->t2.MaxSetupCount = 0;
2767 pSMB->t2.Reserved = 0;
2768 pSMB->t2.Flags = 0;
2769 pSMB->t2.Timeout = 0;
2770 pSMB->t2.Reserved2 = 0;
2771 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2772 Fid) - 4);
2773 pSMB->t2.DataCount = 0;
2774 pSMB->t2.DataOffset = 0;
2775 pSMB->t2.SetupCount = 1;
2776 pSMB->t2.Reserved3 = 0;
2777 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2778 byte_count = params + 1 /* pad */ ;
2779 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2780 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2781 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2782 pSMB->Pad = 0;
2783 pSMB->Fid = netfid;
2784 pSMB->hdr.smb_buf_length += byte_count;
2785 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2787 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2788 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2789 if (rc) {
2790 cFYI(1, ("error %d in GetExtAttr", rc));
2791 } else {
2792 /* decode response */
2793 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2794 if (rc || (pSMBr->ByteCount < 2))
2795 /* BB also check enough total bytes returned */
2796 /* If rc should we check for EOPNOSUPP and
2797 disable the srvino flag? or in caller? */
2798 rc = -EIO; /* bad smb */
2799 else {
2800 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2801 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2802 struct file_chattr_info * pfinfo;
2803 /* BB Do we need a cast or hash here ? */
2804 if(count != 16) {
2805 cFYI(1, ("Illegal size ret in GetExtAttr"));
2806 rc = -EIO;
2807 goto GetExtAttrOut;
2809 pfinfo = (struct file_chattr_info *)
2810 (data_offset + (char *) &pSMBr->hdr.Protocol);
2811 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2812 *pMask = le64_to_cpu(pfinfo->mask);
2815 GetExtAttrOut:
2816 cifs_buf_release(pSMB);
2817 if (rc == -EAGAIN)
2818 goto GetExtAttrRetry;
2819 return rc;
2823 #endif /* CONFIG_POSIX */
2826 /* security id for everyone */
2827 static const struct cifs_sid sid_everyone =
2828 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2829 /* group users */
2830 static const struct cifs_sid sid_user =
2831 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2833 /* Convert CIFS ACL to POSIX form */
2834 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2836 return 0;
2839 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2841 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2842 /* BB fix up return info */ char *acl_inf, const int buflen,
2843 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2845 int rc = 0;
2846 int buf_type = 0;
2847 QUERY_SEC_DESC_REQ * pSMB;
2848 struct kvec iov[1];
2850 cFYI(1, ("GetCifsACL"));
2852 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2853 8 /* parm len */, tcon, (void **) &pSMB);
2854 if (rc)
2855 return rc;
2857 pSMB->MaxParameterCount = cpu_to_le32(4);
2858 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2859 pSMB->MaxSetupCount = 0;
2860 pSMB->Fid = fid; /* file handle always le */
2861 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2862 CIFS_ACL_DACL);
2863 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2864 pSMB->hdr.smb_buf_length += 11;
2865 iov[0].iov_base = (char *)pSMB;
2866 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2868 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2869 cifs_stats_inc(&tcon->num_acl_get);
2870 if (rc) {
2871 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2872 } else { /* decode response */
2873 struct cifs_sid * psec_desc;
2874 __le32 * parm;
2875 int parm_len;
2876 int data_len;
2877 int acl_len;
2878 struct smb_com_ntransact_rsp * pSMBr;
2880 /* validate_nttransact */
2881 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2882 (char **)&psec_desc,
2883 &parm_len, &data_len);
2885 if(rc)
2886 goto qsec_out;
2887 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2889 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2891 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2892 rc = -EIO; /* bad smb */
2893 goto qsec_out;
2896 /* BB check that data area is minimum length and as big as acl_len */
2898 acl_len = le32_to_cpu(*(__le32 *)parm);
2899 /* BB check if(acl_len > bufsize) */
2901 parse_sec_desc(psec_desc, acl_len);
2903 qsec_out:
2904 if(buf_type == CIFS_SMALL_BUFFER)
2905 cifs_small_buf_release(iov[0].iov_base);
2906 else if(buf_type == CIFS_LARGE_BUFFER)
2907 cifs_buf_release(iov[0].iov_base);
2908 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2909 return rc;
2912 /* Legacy Query Path Information call for lookup to old servers such
2913 as Win9x/WinME */
2914 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2915 const unsigned char *searchName,
2916 FILE_ALL_INFO * pFinfo,
2917 const struct nls_table *nls_codepage, int remap)
2919 QUERY_INFORMATION_REQ * pSMB;
2920 QUERY_INFORMATION_RSP * pSMBr;
2921 int rc = 0;
2922 int bytes_returned;
2923 int name_len;
2925 cFYI(1, ("In SMBQPath path %s", searchName));
2926 QInfRetry:
2927 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2928 (void **) &pSMBr);
2929 if (rc)
2930 return rc;
2932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2933 name_len =
2934 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2935 PATH_MAX, nls_codepage, remap);
2936 name_len++; /* trailing null */
2937 name_len *= 2;
2938 } else {
2939 name_len = strnlen(searchName, PATH_MAX);
2940 name_len++; /* trailing null */
2941 strncpy(pSMB->FileName, searchName, name_len);
2943 pSMB->BufferFormat = 0x04;
2944 name_len++; /* account for buffer type byte */
2945 pSMB->hdr.smb_buf_length += (__u16) name_len;
2946 pSMB->ByteCount = cpu_to_le16(name_len);
2948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2950 if (rc) {
2951 cFYI(1, ("Send error in QueryInfo = %d", rc));
2952 } else if (pFinfo) { /* decode response */
2953 struct timespec ts;
2954 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2955 /* BB FIXME - add time zone adjustment BB */
2956 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2957 ts.tv_nsec = 0;
2958 ts.tv_sec = time;
2959 /* decode time fields */
2960 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
2961 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2962 pFinfo->LastAccessTime = 0;
2963 pFinfo->AllocationSize =
2964 cpu_to_le64(le32_to_cpu(pSMBr->size));
2965 pFinfo->EndOfFile = pFinfo->AllocationSize;
2966 pFinfo->Attributes =
2967 cpu_to_le32(le16_to_cpu(pSMBr->attr));
2968 } else
2969 rc = -EIO; /* bad buffer passed in */
2971 cifs_buf_release(pSMB);
2973 if (rc == -EAGAIN)
2974 goto QInfRetry;
2976 return rc;
2983 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2984 const unsigned char *searchName,
2985 FILE_ALL_INFO * pFindData,
2986 int legacy /* old style infolevel */,
2987 const struct nls_table *nls_codepage, int remap)
2989 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2990 TRANSACTION2_QPI_REQ *pSMB = NULL;
2991 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2992 int rc = 0;
2993 int bytes_returned;
2994 int name_len;
2995 __u16 params, byte_count;
2997 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2998 QPathInfoRetry:
2999 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3000 (void **) &pSMBr);
3001 if (rc)
3002 return rc;
3004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3005 name_len =
3006 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3007 PATH_MAX, nls_codepage, remap);
3008 name_len++; /* trailing null */
3009 name_len *= 2;
3010 } else { /* BB improve the check for buffer overruns BB */
3011 name_len = strnlen(searchName, PATH_MAX);
3012 name_len++; /* trailing null */
3013 strncpy(pSMB->FileName, searchName, name_len);
3016 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3017 pSMB->TotalDataCount = 0;
3018 pSMB->MaxParameterCount = cpu_to_le16(2);
3019 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3020 pSMB->MaxSetupCount = 0;
3021 pSMB->Reserved = 0;
3022 pSMB->Flags = 0;
3023 pSMB->Timeout = 0;
3024 pSMB->Reserved2 = 0;
3025 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3026 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3027 pSMB->DataCount = 0;
3028 pSMB->DataOffset = 0;
3029 pSMB->SetupCount = 1;
3030 pSMB->Reserved3 = 0;
3031 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3032 byte_count = params + 1 /* pad */ ;
3033 pSMB->TotalParameterCount = cpu_to_le16(params);
3034 pSMB->ParameterCount = pSMB->TotalParameterCount;
3035 if(legacy)
3036 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3037 else
3038 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3039 pSMB->Reserved4 = 0;
3040 pSMB->hdr.smb_buf_length += byte_count;
3041 pSMB->ByteCount = cpu_to_le16(byte_count);
3043 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3045 if (rc) {
3046 cFYI(1, ("Send error in QPathInfo = %d", rc));
3047 } else { /* decode response */
3048 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3050 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3051 rc = -EIO;
3052 else if (!legacy && (pSMBr->ByteCount < 40))
3053 rc = -EIO; /* bad smb */
3054 else if(legacy && (pSMBr->ByteCount < 24))
3055 rc = -EIO; /* 24 or 26 expected but we do not read last field */
3056 else if (pFindData){
3057 int size;
3058 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3059 if(legacy) /* we do not read the last field, EAsize, fortunately
3060 since it varies by subdialect and on Set vs. Get, is
3061 two bytes or 4 bytes depending but we don't care here */
3062 size = sizeof(FILE_INFO_STANDARD);
3063 else
3064 size = sizeof(FILE_ALL_INFO);
3065 memcpy((char *) pFindData,
3066 (char *) &pSMBr->hdr.Protocol +
3067 data_offset, size);
3068 } else
3069 rc = -ENOMEM;
3071 cifs_buf_release(pSMB);
3072 if (rc == -EAGAIN)
3073 goto QPathInfoRetry;
3075 return rc;
3079 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3080 const unsigned char *searchName,
3081 FILE_UNIX_BASIC_INFO * pFindData,
3082 const struct nls_table *nls_codepage, int remap)
3084 /* SMB_QUERY_FILE_UNIX_BASIC */
3085 TRANSACTION2_QPI_REQ *pSMB = NULL;
3086 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3087 int rc = 0;
3088 int bytes_returned = 0;
3089 int name_len;
3090 __u16 params, byte_count;
3092 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3093 UnixQPathInfoRetry:
3094 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3095 (void **) &pSMBr);
3096 if (rc)
3097 return rc;
3099 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3100 name_len =
3101 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3102 PATH_MAX, nls_codepage, remap);
3103 name_len++; /* trailing null */
3104 name_len *= 2;
3105 } else { /* BB improve the check for buffer overruns BB */
3106 name_len = strnlen(searchName, PATH_MAX);
3107 name_len++; /* trailing null */
3108 strncpy(pSMB->FileName, searchName, name_len);
3111 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3112 pSMB->TotalDataCount = 0;
3113 pSMB->MaxParameterCount = cpu_to_le16(2);
3114 /* BB find exact max SMB PDU from sess structure BB */
3115 pSMB->MaxDataCount = cpu_to_le16(4000);
3116 pSMB->MaxSetupCount = 0;
3117 pSMB->Reserved = 0;
3118 pSMB->Flags = 0;
3119 pSMB->Timeout = 0;
3120 pSMB->Reserved2 = 0;
3121 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3122 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3123 pSMB->DataCount = 0;
3124 pSMB->DataOffset = 0;
3125 pSMB->SetupCount = 1;
3126 pSMB->Reserved3 = 0;
3127 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3128 byte_count = params + 1 /* pad */ ;
3129 pSMB->TotalParameterCount = cpu_to_le16(params);
3130 pSMB->ParameterCount = pSMB->TotalParameterCount;
3131 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3132 pSMB->Reserved4 = 0;
3133 pSMB->hdr.smb_buf_length += byte_count;
3134 pSMB->ByteCount = cpu_to_le16(byte_count);
3136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3138 if (rc) {
3139 cFYI(1, ("Send error in QPathInfo = %d", rc));
3140 } else { /* decode response */
3141 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3143 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3144 rc = -EIO; /* bad smb */
3145 } else {
3146 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3147 memcpy((char *) pFindData,
3148 (char *) &pSMBr->hdr.Protocol +
3149 data_offset,
3150 sizeof (FILE_UNIX_BASIC_INFO));
3153 cifs_buf_release(pSMB);
3154 if (rc == -EAGAIN)
3155 goto UnixQPathInfoRetry;
3157 return rc;
3160 #if 0 /* function unused at present */
3161 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3162 const char *searchName, FILE_ALL_INFO * findData,
3163 const struct nls_table *nls_codepage)
3165 /* level 257 SMB_ */
3166 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3167 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3168 int rc = 0;
3169 int bytes_returned;
3170 int name_len;
3171 __u16 params, byte_count;
3173 cFYI(1, ("In FindUnique"));
3174 findUniqueRetry:
3175 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3176 (void **) &pSMBr);
3177 if (rc)
3178 return rc;
3180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3181 name_len =
3182 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
3183 /* find define for this maxpathcomponent */
3184 , nls_codepage);
3185 name_len++; /* trailing null */
3186 name_len *= 2;
3187 } else { /* BB improve the check for buffer overruns BB */
3188 name_len = strnlen(searchName, PATH_MAX);
3189 name_len++; /* trailing null */
3190 strncpy(pSMB->FileName, searchName, name_len);
3193 params = 12 + name_len /* includes null */ ;
3194 pSMB->TotalDataCount = 0; /* no EAs */
3195 pSMB->MaxParameterCount = cpu_to_le16(2);
3196 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3197 pSMB->MaxSetupCount = 0;
3198 pSMB->Reserved = 0;
3199 pSMB->Flags = 0;
3200 pSMB->Timeout = 0;
3201 pSMB->Reserved2 = 0;
3202 pSMB->ParameterOffset = cpu_to_le16(
3203 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3204 pSMB->DataCount = 0;
3205 pSMB->DataOffset = 0;
3206 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3207 pSMB->Reserved3 = 0;
3208 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3209 byte_count = params + 1 /* pad */ ;
3210 pSMB->TotalParameterCount = cpu_to_le16(params);
3211 pSMB->ParameterCount = pSMB->TotalParameterCount;
3212 pSMB->SearchAttributes =
3213 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3214 ATTR_DIRECTORY);
3215 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3216 pSMB->SearchFlags = cpu_to_le16(1);
3217 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3218 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3219 pSMB->hdr.smb_buf_length += byte_count;
3220 pSMB->ByteCount = cpu_to_le16(byte_count);
3222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3225 if (rc) {
3226 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3227 } else { /* decode response */
3228 cifs_stats_inc(&tcon->num_ffirst);
3229 /* BB fill in */
3232 cifs_buf_release(pSMB);
3233 if (rc == -EAGAIN)
3234 goto findUniqueRetry;
3236 return rc;
3238 #endif /* end unused (temporarily) function */
3240 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3242 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3243 const char *searchName,
3244 const struct nls_table *nls_codepage,
3245 __u16 * pnetfid,
3246 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
3248 /* level 257 SMB_ */
3249 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3250 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3251 T2_FFIRST_RSP_PARMS * parms;
3252 int rc = 0;
3253 int bytes_returned = 0;
3254 int name_len;
3255 __u16 params, byte_count;
3257 cFYI(1, ("In FindFirst for %s",searchName));
3259 findFirstRetry:
3260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3261 (void **) &pSMBr);
3262 if (rc)
3263 return rc;
3265 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3266 name_len =
3267 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
3268 PATH_MAX, nls_codepage, remap);
3269 /* We can not add the asterik earlier in case
3270 it got remapped to 0xF03A as if it were part of the
3271 directory name instead of a wildcard */
3272 name_len *= 2;
3273 pSMB->FileName[name_len] = dirsep;
3274 pSMB->FileName[name_len+1] = 0;
3275 pSMB->FileName[name_len+2] = '*';
3276 pSMB->FileName[name_len+3] = 0;
3277 name_len += 4; /* now the trailing null */
3278 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3279 pSMB->FileName[name_len+1] = 0;
3280 name_len += 2;
3281 } else { /* BB add check for overrun of SMB buf BB */
3282 name_len = strnlen(searchName, PATH_MAX);
3283 /* BB fix here and in unicode clause above ie
3284 if(name_len > buffersize-header)
3285 free buffer exit; BB */
3286 strncpy(pSMB->FileName, searchName, name_len);
3287 pSMB->FileName[name_len] = dirsep;
3288 pSMB->FileName[name_len+1] = '*';
3289 pSMB->FileName[name_len+2] = 0;
3290 name_len += 3;
3293 params = 12 + name_len /* includes null */ ;
3294 pSMB->TotalDataCount = 0; /* no EAs */
3295 pSMB->MaxParameterCount = cpu_to_le16(10);
3296 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3297 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3298 pSMB->MaxSetupCount = 0;
3299 pSMB->Reserved = 0;
3300 pSMB->Flags = 0;
3301 pSMB->Timeout = 0;
3302 pSMB->Reserved2 = 0;
3303 byte_count = params + 1 /* pad */ ;
3304 pSMB->TotalParameterCount = cpu_to_le16(params);
3305 pSMB->ParameterCount = pSMB->TotalParameterCount;
3306 pSMB->ParameterOffset = cpu_to_le16(
3307 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3308 - 4);
3309 pSMB->DataCount = 0;
3310 pSMB->DataOffset = 0;
3311 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3312 pSMB->Reserved3 = 0;
3313 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3314 pSMB->SearchAttributes =
3315 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3316 ATTR_DIRECTORY);
3317 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3318 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3319 CIFS_SEARCH_RETURN_RESUME);
3320 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3322 /* BB what should we set StorageType to? Does it matter? BB */
3323 pSMB->SearchStorageType = 0;
3324 pSMB->hdr.smb_buf_length += byte_count;
3325 pSMB->ByteCount = cpu_to_le16(byte_count);
3327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3329 cifs_stats_inc(&tcon->num_ffirst);
3331 if (rc) {/* BB add logic to retry regular search if Unix search
3332 rejected unexpectedly by server */
3333 /* BB Add code to handle unsupported level rc */
3334 cFYI(1, ("Error in FindFirst = %d", rc));
3336 cifs_buf_release(pSMB);
3338 /* BB eventually could optimize out free and realloc of buf */
3339 /* for this case */
3340 if (rc == -EAGAIN)
3341 goto findFirstRetry;
3342 } else { /* decode response */
3343 /* BB remember to free buffer if error BB */
3344 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3345 if(rc == 0) {
3346 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3347 psrch_inf->unicode = TRUE;
3348 else
3349 psrch_inf->unicode = FALSE;
3351 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3352 psrch_inf->smallBuf = 0;
3353 psrch_inf->srch_entries_start =
3354 (char *) &pSMBr->hdr.Protocol +
3355 le16_to_cpu(pSMBr->t2.DataOffset);
3356 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3357 le16_to_cpu(pSMBr->t2.ParameterOffset));
3359 if(parms->EndofSearch)
3360 psrch_inf->endOfSearch = TRUE;
3361 else
3362 psrch_inf->endOfSearch = FALSE;
3364 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3365 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3366 psrch_inf->entries_in_buffer;
3367 *pnetfid = parms->SearchHandle;
3368 } else {
3369 cifs_buf_release(pSMB);
3373 return rc;
3376 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3377 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3379 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3380 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3381 T2_FNEXT_RSP_PARMS * parms;
3382 char *response_data;
3383 int rc = 0;
3384 int bytes_returned, name_len;
3385 __u16 params, byte_count;
3387 cFYI(1, ("In FindNext"));
3389 if(psrch_inf->endOfSearch == TRUE)
3390 return -ENOENT;
3392 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3393 (void **) &pSMBr);
3394 if (rc)
3395 return rc;
3397 params = 14; /* includes 2 bytes of null string, converted to LE below */
3398 byte_count = 0;
3399 pSMB->TotalDataCount = 0; /* no EAs */
3400 pSMB->MaxParameterCount = cpu_to_le16(8);
3401 pSMB->MaxDataCount =
3402 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3403 pSMB->MaxSetupCount = 0;
3404 pSMB->Reserved = 0;
3405 pSMB->Flags = 0;
3406 pSMB->Timeout = 0;
3407 pSMB->Reserved2 = 0;
3408 pSMB->ParameterOffset = cpu_to_le16(
3409 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3410 pSMB->DataCount = 0;
3411 pSMB->DataOffset = 0;
3412 pSMB->SetupCount = 1;
3413 pSMB->Reserved3 = 0;
3414 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3415 pSMB->SearchHandle = searchHandle; /* always kept as le */
3416 pSMB->SearchCount =
3417 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3418 /* test for Unix extensions */
3419 /* if (tcon->ses->capabilities & CAP_UNIX) {
3420 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3421 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3422 } else {
3423 pSMB->InformationLevel =
3424 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3425 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3426 } */
3427 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3428 pSMB->ResumeKey = psrch_inf->resume_key;
3429 pSMB->SearchFlags =
3430 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3432 name_len = psrch_inf->resume_name_len;
3433 params += name_len;
3434 if(name_len < PATH_MAX) {
3435 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3436 byte_count += name_len;
3437 /* 14 byte parm len above enough for 2 byte null terminator */
3438 pSMB->ResumeFileName[name_len] = 0;
3439 pSMB->ResumeFileName[name_len+1] = 0;
3440 } else {
3441 rc = -EINVAL;
3442 goto FNext2_err_exit;
3444 byte_count = params + 1 /* pad */ ;
3445 pSMB->TotalParameterCount = cpu_to_le16(params);
3446 pSMB->ParameterCount = pSMB->TotalParameterCount;
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 cifs_stats_inc(&tcon->num_fnext);
3453 if (rc) {
3454 if (rc == -EBADF) {
3455 psrch_inf->endOfSearch = TRUE;
3456 rc = 0; /* search probably was closed at end of search above */
3457 } else
3458 cFYI(1, ("FindNext returned = %d", rc));
3459 } else { /* decode response */
3460 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3462 if(rc == 0) {
3463 /* BB fixme add lock for file (srch_info) struct here */
3464 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3465 psrch_inf->unicode = TRUE;
3466 else
3467 psrch_inf->unicode = FALSE;
3468 response_data = (char *) &pSMBr->hdr.Protocol +
3469 le16_to_cpu(pSMBr->t2.ParameterOffset);
3470 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3471 response_data = (char *)&pSMBr->hdr.Protocol +
3472 le16_to_cpu(pSMBr->t2.DataOffset);
3473 if(psrch_inf->smallBuf)
3474 cifs_small_buf_release(
3475 psrch_inf->ntwrk_buf_start);
3476 else
3477 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3478 psrch_inf->srch_entries_start = response_data;
3479 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3480 psrch_inf->smallBuf = 0;
3481 if(parms->EndofSearch)
3482 psrch_inf->endOfSearch = TRUE;
3483 else
3484 psrch_inf->endOfSearch = FALSE;
3486 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3487 psrch_inf->index_of_last_entry +=
3488 psrch_inf->entries_in_buffer;
3489 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3491 /* BB fixme add unlock here */
3496 /* BB On error, should we leave previous search buf (and count and
3497 last entry fields) intact or free the previous one? */
3499 /* Note: On -EAGAIN error only caller can retry on handle based calls
3500 since file handle passed in no longer valid */
3501 FNext2_err_exit:
3502 if (rc != 0)
3503 cifs_buf_release(pSMB);
3505 return rc;
3509 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3511 int rc = 0;
3512 FINDCLOSE_REQ *pSMB = NULL;
3513 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3514 int bytes_returned;
3516 cFYI(1, ("In CIFSSMBFindClose"));
3517 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3519 /* no sense returning error if session restarted
3520 as file handle has been closed */
3521 if(rc == -EAGAIN)
3522 return 0;
3523 if (rc)
3524 return rc;
3526 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3527 pSMB->FileID = searchHandle;
3528 pSMB->ByteCount = 0;
3529 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3530 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3531 if (rc) {
3532 cERROR(1, ("Send error in FindClose = %d", rc));
3534 cifs_stats_inc(&tcon->num_fclose);
3535 cifs_small_buf_release(pSMB);
3537 /* Since session is dead, search handle closed on server already */
3538 if (rc == -EAGAIN)
3539 rc = 0;
3541 return rc;
3545 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3546 const unsigned char *searchName,
3547 __u64 * inode_number,
3548 const struct nls_table *nls_codepage, int remap)
3550 int rc = 0;
3551 TRANSACTION2_QPI_REQ *pSMB = NULL;
3552 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3553 int name_len, bytes_returned;
3554 __u16 params, byte_count;
3556 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3557 if(tcon == NULL)
3558 return -ENODEV;
3560 GetInodeNumberRetry:
3561 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3562 (void **) &pSMBr);
3563 if (rc)
3564 return rc;
3567 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3568 name_len =
3569 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3570 PATH_MAX,nls_codepage, remap);
3571 name_len++; /* trailing null */
3572 name_len *= 2;
3573 } else { /* BB improve the check for buffer overruns BB */
3574 name_len = strnlen(searchName, PATH_MAX);
3575 name_len++; /* trailing null */
3576 strncpy(pSMB->FileName, searchName, name_len);
3579 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3580 pSMB->TotalDataCount = 0;
3581 pSMB->MaxParameterCount = cpu_to_le16(2);
3582 /* BB find exact max data count below from sess structure BB */
3583 pSMB->MaxDataCount = cpu_to_le16(4000);
3584 pSMB->MaxSetupCount = 0;
3585 pSMB->Reserved = 0;
3586 pSMB->Flags = 0;
3587 pSMB->Timeout = 0;
3588 pSMB->Reserved2 = 0;
3589 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3590 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3591 pSMB->DataCount = 0;
3592 pSMB->DataOffset = 0;
3593 pSMB->SetupCount = 1;
3594 pSMB->Reserved3 = 0;
3595 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3596 byte_count = params + 1 /* pad */ ;
3597 pSMB->TotalParameterCount = cpu_to_le16(params);
3598 pSMB->ParameterCount = pSMB->TotalParameterCount;
3599 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3600 pSMB->Reserved4 = 0;
3601 pSMB->hdr.smb_buf_length += byte_count;
3602 pSMB->ByteCount = cpu_to_le16(byte_count);
3604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3606 if (rc) {
3607 cFYI(1, ("error %d in QueryInternalInfo", rc));
3608 } else {
3609 /* decode response */
3610 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3611 if (rc || (pSMBr->ByteCount < 2))
3612 /* BB also check enough total bytes returned */
3613 /* If rc should we check for EOPNOSUPP and
3614 disable the srvino flag? or in caller? */
3615 rc = -EIO; /* bad smb */
3616 else {
3617 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3618 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3619 struct file_internal_info * pfinfo;
3620 /* BB Do we need a cast or hash here ? */
3621 if(count < 8) {
3622 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3623 rc = -EIO;
3624 goto GetInodeNumOut;
3626 pfinfo = (struct file_internal_info *)
3627 (data_offset + (char *) &pSMBr->hdr.Protocol);
3628 *inode_number = pfinfo->UniqueId;
3631 GetInodeNumOut:
3632 cifs_buf_release(pSMB);
3633 if (rc == -EAGAIN)
3634 goto GetInodeNumberRetry;
3635 return rc;
3639 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3640 const unsigned char *searchName,
3641 unsigned char **targetUNCs,
3642 unsigned int *number_of_UNC_in_array,
3643 const struct nls_table *nls_codepage, int remap)
3645 /* TRANS2_GET_DFS_REFERRAL */
3646 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3647 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3648 struct dfs_referral_level_3 * referrals = NULL;
3649 int rc = 0;
3650 int bytes_returned;
3651 int name_len;
3652 unsigned int i;
3653 char * temp;
3654 __u16 params, byte_count;
3655 *number_of_UNC_in_array = 0;
3656 *targetUNCs = NULL;
3658 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3659 if (ses == NULL)
3660 return -ENODEV;
3661 getDFSRetry:
3662 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3663 (void **) &pSMBr);
3664 if (rc)
3665 return rc;
3667 /* server pointer checked in called function,
3668 but should never be null here anyway */
3669 pSMB->hdr.Mid = GetNextMid(ses->server);
3670 pSMB->hdr.Tid = ses->ipc_tid;
3671 pSMB->hdr.Uid = ses->Suid;
3672 if (ses->capabilities & CAP_STATUS32) {
3673 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3675 if (ses->capabilities & CAP_DFS) {
3676 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3679 if (ses->capabilities & CAP_UNICODE) {
3680 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3681 name_len =
3682 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3683 searchName, PATH_MAX, nls_codepage, remap);
3684 name_len++; /* trailing null */
3685 name_len *= 2;
3686 } else { /* BB improve the check for buffer overruns BB */
3687 name_len = strnlen(searchName, PATH_MAX);
3688 name_len++; /* trailing null */
3689 strncpy(pSMB->RequestFileName, searchName, name_len);
3692 if(ses->server) {
3693 if(ses->server->secMode &
3694 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3695 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3698 pSMB->hdr.Uid = ses->Suid;
3700 params = 2 /* level */ + name_len /*includes null */ ;
3701 pSMB->TotalDataCount = 0;
3702 pSMB->DataCount = 0;
3703 pSMB->DataOffset = 0;
3704 pSMB->MaxParameterCount = 0;
3705 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3706 pSMB->MaxSetupCount = 0;
3707 pSMB->Reserved = 0;
3708 pSMB->Flags = 0;
3709 pSMB->Timeout = 0;
3710 pSMB->Reserved2 = 0;
3711 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3712 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3713 pSMB->SetupCount = 1;
3714 pSMB->Reserved3 = 0;
3715 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3716 byte_count = params + 3 /* pad */ ;
3717 pSMB->ParameterCount = cpu_to_le16(params);
3718 pSMB->TotalParameterCount = pSMB->ParameterCount;
3719 pSMB->MaxReferralLevel = cpu_to_le16(3);
3720 pSMB->hdr.smb_buf_length += byte_count;
3721 pSMB->ByteCount = cpu_to_le16(byte_count);
3723 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3725 if (rc) {
3726 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3727 } else { /* decode response */
3728 /* BB Add logic to parse referrals here */
3729 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3731 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3732 rc = -EIO; /* bad smb */
3733 else {
3734 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3735 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3737 cFYI(1,
3738 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3739 pSMBr->ByteCount, data_offset));
3740 referrals =
3741 (struct dfs_referral_level_3 *)
3742 (8 /* sizeof start of data block */ +
3743 data_offset +
3744 (char *) &pSMBr->hdr.Protocol);
3745 cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
3746 le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
3747 /* BB This field is actually two bytes in from start of
3748 data block so we could do safety check that DataBlock
3749 begins at address of pSMBr->NumberOfReferrals */
3750 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3752 /* BB Fix below so can return more than one referral */
3753 if(*number_of_UNC_in_array > 1)
3754 *number_of_UNC_in_array = 1;
3756 /* get the length of the strings describing refs */
3757 name_len = 0;
3758 for(i=0;i<*number_of_UNC_in_array;i++) {
3759 /* make sure that DfsPathOffset not past end */
3760 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3761 if (offset > data_count) {
3762 /* if invalid referral, stop here and do
3763 not try to copy any more */
3764 *number_of_UNC_in_array = i;
3765 break;
3767 temp = ((char *)referrals) + offset;
3769 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3770 name_len += UniStrnlen((wchar_t *)temp,data_count);
3771 } else {
3772 name_len += strnlen(temp,data_count);
3774 referrals++;
3775 /* BB add check that referral pointer does not fall off end PDU */
3778 /* BB add check for name_len bigger than bcc */
3779 *targetUNCs =
3780 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3781 if(*targetUNCs == NULL) {
3782 rc = -ENOMEM;
3783 goto GetDFSRefExit;
3785 /* copy the ref strings */
3786 referrals =
3787 (struct dfs_referral_level_3 *)
3788 (8 /* sizeof data hdr */ +
3789 data_offset +
3790 (char *) &pSMBr->hdr.Protocol);
3792 for(i=0;i<*number_of_UNC_in_array;i++) {
3793 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3794 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3795 cifs_strfromUCS_le(*targetUNCs,
3796 (__le16 *) temp, name_len, nls_codepage);
3797 } else {
3798 strncpy(*targetUNCs,temp,name_len);
3800 /* BB update target_uncs pointers */
3801 referrals++;
3803 temp = *targetUNCs;
3804 temp[name_len] = 0;
3808 GetDFSRefExit:
3809 if (pSMB)
3810 cifs_buf_release(pSMB);
3812 if (rc == -EAGAIN)
3813 goto getDFSRetry;
3815 return rc;
3818 /* Query File System Info such as free space to old servers such as Win 9x */
3820 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3822 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3823 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3824 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3825 FILE_SYSTEM_ALLOC_INFO *response_data;
3826 int rc = 0;
3827 int bytes_returned = 0;
3828 __u16 params, byte_count;
3830 cFYI(1, ("OldQFSInfo"));
3831 oldQFSInfoRetry:
3832 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3833 (void **) &pSMBr);
3834 if (rc)
3835 return rc;
3836 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3837 (void **) &pSMBr);
3838 if (rc)
3839 return rc;
3841 params = 2; /* level */
3842 pSMB->TotalDataCount = 0;
3843 pSMB->MaxParameterCount = cpu_to_le16(2);
3844 pSMB->MaxDataCount = cpu_to_le16(1000);
3845 pSMB->MaxSetupCount = 0;
3846 pSMB->Reserved = 0;
3847 pSMB->Flags = 0;
3848 pSMB->Timeout = 0;
3849 pSMB->Reserved2 = 0;
3850 byte_count = params + 1 /* pad */ ;
3851 pSMB->TotalParameterCount = cpu_to_le16(params);
3852 pSMB->ParameterCount = pSMB->TotalParameterCount;
3853 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3854 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3855 pSMB->DataCount = 0;
3856 pSMB->DataOffset = 0;
3857 pSMB->SetupCount = 1;
3858 pSMB->Reserved3 = 0;
3859 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3860 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3861 pSMB->hdr.smb_buf_length += byte_count;
3862 pSMB->ByteCount = cpu_to_le16(byte_count);
3864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3866 if (rc) {
3867 cFYI(1, ("Send error in QFSInfo = %d", rc));
3868 } else { /* decode response */
3869 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3871 if (rc || (pSMBr->ByteCount < 18))
3872 rc = -EIO; /* bad smb */
3873 else {
3874 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3875 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3876 pSMBr->ByteCount, data_offset));
3878 response_data =
3879 (FILE_SYSTEM_ALLOC_INFO *)
3880 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3881 FSData->f_bsize =
3882 le16_to_cpu(response_data->BytesPerSector) *
3883 le32_to_cpu(response_data->
3884 SectorsPerAllocationUnit);
3885 FSData->f_blocks =
3886 le32_to_cpu(response_data->TotalAllocationUnits);
3887 FSData->f_bfree = FSData->f_bavail =
3888 le32_to_cpu(response_data->FreeAllocationUnits);
3889 cFYI(1,
3890 ("Blocks: %lld Free: %lld Block size %ld",
3891 (unsigned long long)FSData->f_blocks,
3892 (unsigned long long)FSData->f_bfree,
3893 FSData->f_bsize));
3896 cifs_buf_release(pSMB);
3898 if (rc == -EAGAIN)
3899 goto oldQFSInfoRetry;
3901 return rc;
3905 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3907 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3908 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3909 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3910 FILE_SYSTEM_INFO *response_data;
3911 int rc = 0;
3912 int bytes_returned = 0;
3913 __u16 params, byte_count;
3915 cFYI(1, ("In QFSInfo"));
3916 QFSInfoRetry:
3917 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3918 (void **) &pSMBr);
3919 if (rc)
3920 return rc;
3922 params = 2; /* level */
3923 pSMB->TotalDataCount = 0;
3924 pSMB->MaxParameterCount = cpu_to_le16(2);
3925 pSMB->MaxDataCount = cpu_to_le16(1000);
3926 pSMB->MaxSetupCount = 0;
3927 pSMB->Reserved = 0;
3928 pSMB->Flags = 0;
3929 pSMB->Timeout = 0;
3930 pSMB->Reserved2 = 0;
3931 byte_count = params + 1 /* pad */ ;
3932 pSMB->TotalParameterCount = cpu_to_le16(params);
3933 pSMB->ParameterCount = pSMB->TotalParameterCount;
3934 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3935 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3936 pSMB->DataCount = 0;
3937 pSMB->DataOffset = 0;
3938 pSMB->SetupCount = 1;
3939 pSMB->Reserved3 = 0;
3940 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3941 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3942 pSMB->hdr.smb_buf_length += byte_count;
3943 pSMB->ByteCount = cpu_to_le16(byte_count);
3945 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3946 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3947 if (rc) {
3948 cFYI(1, ("Send error in QFSInfo = %d", rc));
3949 } else { /* decode response */
3950 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3952 if (rc || (pSMBr->ByteCount < 24))
3953 rc = -EIO; /* bad smb */
3954 else {
3955 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3957 response_data =
3958 (FILE_SYSTEM_INFO
3959 *) (((char *) &pSMBr->hdr.Protocol) +
3960 data_offset);
3961 FSData->f_bsize =
3962 le32_to_cpu(response_data->BytesPerSector) *
3963 le32_to_cpu(response_data->
3964 SectorsPerAllocationUnit);
3965 FSData->f_blocks =
3966 le64_to_cpu(response_data->TotalAllocationUnits);
3967 FSData->f_bfree = FSData->f_bavail =
3968 le64_to_cpu(response_data->FreeAllocationUnits);
3969 cFYI(1,
3970 ("Blocks: %lld Free: %lld Block size %ld",
3971 (unsigned long long)FSData->f_blocks,
3972 (unsigned long long)FSData->f_bfree,
3973 FSData->f_bsize));
3976 cifs_buf_release(pSMB);
3978 if (rc == -EAGAIN)
3979 goto QFSInfoRetry;
3981 return rc;
3985 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3987 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3988 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3989 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3990 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3991 int rc = 0;
3992 int bytes_returned = 0;
3993 __u16 params, byte_count;
3995 cFYI(1, ("In QFSAttributeInfo"));
3996 QFSAttributeRetry:
3997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3998 (void **) &pSMBr);
3999 if (rc)
4000 return rc;
4002 params = 2; /* level */
4003 pSMB->TotalDataCount = 0;
4004 pSMB->MaxParameterCount = cpu_to_le16(2);
4005 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4006 pSMB->MaxSetupCount = 0;
4007 pSMB->Reserved = 0;
4008 pSMB->Flags = 0;
4009 pSMB->Timeout = 0;
4010 pSMB->Reserved2 = 0;
4011 byte_count = params + 1 /* pad */ ;
4012 pSMB->TotalParameterCount = cpu_to_le16(params);
4013 pSMB->ParameterCount = pSMB->TotalParameterCount;
4014 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4015 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4016 pSMB->DataCount = 0;
4017 pSMB->DataOffset = 0;
4018 pSMB->SetupCount = 1;
4019 pSMB->Reserved3 = 0;
4020 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4021 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4022 pSMB->hdr.smb_buf_length += byte_count;
4023 pSMB->ByteCount = cpu_to_le16(byte_count);
4025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4027 if (rc) {
4028 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4029 } else { /* decode response */
4030 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4032 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4033 rc = -EIO; /* bad smb */
4034 } else {
4035 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4036 response_data =
4037 (FILE_SYSTEM_ATTRIBUTE_INFO
4038 *) (((char *) &pSMBr->hdr.Protocol) +
4039 data_offset);
4040 memcpy(&tcon->fsAttrInfo, response_data,
4041 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4044 cifs_buf_release(pSMB);
4046 if (rc == -EAGAIN)
4047 goto QFSAttributeRetry;
4049 return rc;
4053 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4055 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4056 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4057 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4058 FILE_SYSTEM_DEVICE_INFO *response_data;
4059 int rc = 0;
4060 int bytes_returned = 0;
4061 __u16 params, byte_count;
4063 cFYI(1, ("In QFSDeviceInfo"));
4064 QFSDeviceRetry:
4065 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4066 (void **) &pSMBr);
4067 if (rc)
4068 return rc;
4070 params = 2; /* level */
4071 pSMB->TotalDataCount = 0;
4072 pSMB->MaxParameterCount = cpu_to_le16(2);
4073 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4074 pSMB->MaxSetupCount = 0;
4075 pSMB->Reserved = 0;
4076 pSMB->Flags = 0;
4077 pSMB->Timeout = 0;
4078 pSMB->Reserved2 = 0;
4079 byte_count = params + 1 /* pad */ ;
4080 pSMB->TotalParameterCount = cpu_to_le16(params);
4081 pSMB->ParameterCount = pSMB->TotalParameterCount;
4082 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4083 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4085 pSMB->DataCount = 0;
4086 pSMB->DataOffset = 0;
4087 pSMB->SetupCount = 1;
4088 pSMB->Reserved3 = 0;
4089 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4090 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4091 pSMB->hdr.smb_buf_length += byte_count;
4092 pSMB->ByteCount = cpu_to_le16(byte_count);
4094 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4095 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4096 if (rc) {
4097 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4098 } else { /* decode response */
4099 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4101 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4102 rc = -EIO; /* bad smb */
4103 else {
4104 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4105 response_data =
4106 (FILE_SYSTEM_DEVICE_INFO *)
4107 (((char *) &pSMBr->hdr.Protocol) +
4108 data_offset);
4109 memcpy(&tcon->fsDevInfo, response_data,
4110 sizeof (FILE_SYSTEM_DEVICE_INFO));
4113 cifs_buf_release(pSMB);
4115 if (rc == -EAGAIN)
4116 goto QFSDeviceRetry;
4118 return rc;
4122 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4124 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4125 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4126 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4127 FILE_SYSTEM_UNIX_INFO *response_data;
4128 int rc = 0;
4129 int bytes_returned = 0;
4130 __u16 params, byte_count;
4132 cFYI(1, ("In QFSUnixInfo"));
4133 QFSUnixRetry:
4134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4135 (void **) &pSMBr);
4136 if (rc)
4137 return rc;
4139 params = 2; /* level */
4140 pSMB->TotalDataCount = 0;
4141 pSMB->DataCount = 0;
4142 pSMB->DataOffset = 0;
4143 pSMB->MaxParameterCount = cpu_to_le16(2);
4144 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4145 pSMB->MaxSetupCount = 0;
4146 pSMB->Reserved = 0;
4147 pSMB->Flags = 0;
4148 pSMB->Timeout = 0;
4149 pSMB->Reserved2 = 0;
4150 byte_count = params + 1 /* pad */ ;
4151 pSMB->ParameterCount = cpu_to_le16(params);
4152 pSMB->TotalParameterCount = pSMB->ParameterCount;
4153 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4154 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4155 pSMB->SetupCount = 1;
4156 pSMB->Reserved3 = 0;
4157 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4158 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4159 pSMB->hdr.smb_buf_length += byte_count;
4160 pSMB->ByteCount = cpu_to_le16(byte_count);
4162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4164 if (rc) {
4165 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4166 } else { /* decode response */
4167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4169 if (rc || (pSMBr->ByteCount < 13)) {
4170 rc = -EIO; /* bad smb */
4171 } else {
4172 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4173 response_data =
4174 (FILE_SYSTEM_UNIX_INFO
4175 *) (((char *) &pSMBr->hdr.Protocol) +
4176 data_offset);
4177 memcpy(&tcon->fsUnixInfo, response_data,
4178 sizeof (FILE_SYSTEM_UNIX_INFO));
4181 cifs_buf_release(pSMB);
4183 if (rc == -EAGAIN)
4184 goto QFSUnixRetry;
4187 return rc;
4191 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4193 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4194 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4195 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4196 int rc = 0;
4197 int bytes_returned = 0;
4198 __u16 params, param_offset, offset, byte_count;
4200 cFYI(1, ("In SETFSUnixInfo"));
4201 SETFSUnixRetry:
4202 /* BB switch to small buf init to save memory */
4203 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4204 (void **) &pSMBr);
4205 if (rc)
4206 return rc;
4208 params = 4; /* 2 bytes zero followed by info level. */
4209 pSMB->MaxSetupCount = 0;
4210 pSMB->Reserved = 0;
4211 pSMB->Flags = 0;
4212 pSMB->Timeout = 0;
4213 pSMB->Reserved2 = 0;
4214 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4215 offset = param_offset + params;
4217 pSMB->MaxParameterCount = cpu_to_le16(4);
4218 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4219 pSMB->SetupCount = 1;
4220 pSMB->Reserved3 = 0;
4221 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4222 byte_count = 1 /* pad */ + params + 12;
4224 pSMB->DataCount = cpu_to_le16(12);
4225 pSMB->ParameterCount = cpu_to_le16(params);
4226 pSMB->TotalDataCount = pSMB->DataCount;
4227 pSMB->TotalParameterCount = pSMB->ParameterCount;
4228 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4229 pSMB->DataOffset = cpu_to_le16(offset);
4231 /* Params. */
4232 pSMB->FileNum = 0;
4233 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4235 /* Data. */
4236 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4237 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4238 pSMB->ClientUnixCap = cpu_to_le64(cap);
4240 pSMB->hdr.smb_buf_length += byte_count;
4241 pSMB->ByteCount = cpu_to_le16(byte_count);
4243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4245 if (rc) {
4246 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4247 } else { /* decode response */
4248 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4249 if (rc) {
4250 rc = -EIO; /* bad smb */
4253 cifs_buf_release(pSMB);
4255 if (rc == -EAGAIN)
4256 goto SETFSUnixRetry;
4258 return rc;
4264 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4265 struct kstatfs *FSData)
4267 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4268 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4269 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4270 FILE_SYSTEM_POSIX_INFO *response_data;
4271 int rc = 0;
4272 int bytes_returned = 0;
4273 __u16 params, byte_count;
4275 cFYI(1, ("In QFSPosixInfo"));
4276 QFSPosixRetry:
4277 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4278 (void **) &pSMBr);
4279 if (rc)
4280 return rc;
4282 params = 2; /* level */
4283 pSMB->TotalDataCount = 0;
4284 pSMB->DataCount = 0;
4285 pSMB->DataOffset = 0;
4286 pSMB->MaxParameterCount = cpu_to_le16(2);
4287 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4288 pSMB->MaxSetupCount = 0;
4289 pSMB->Reserved = 0;
4290 pSMB->Flags = 0;
4291 pSMB->Timeout = 0;
4292 pSMB->Reserved2 = 0;
4293 byte_count = params + 1 /* pad */ ;
4294 pSMB->ParameterCount = cpu_to_le16(params);
4295 pSMB->TotalParameterCount = pSMB->ParameterCount;
4296 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4297 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4298 pSMB->SetupCount = 1;
4299 pSMB->Reserved3 = 0;
4300 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4301 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4302 pSMB->hdr.smb_buf_length += byte_count;
4303 pSMB->ByteCount = cpu_to_le16(byte_count);
4305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4307 if (rc) {
4308 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4309 } else { /* decode response */
4310 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4312 if (rc || (pSMBr->ByteCount < 13)) {
4313 rc = -EIO; /* bad smb */
4314 } else {
4315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4316 response_data =
4317 (FILE_SYSTEM_POSIX_INFO
4318 *) (((char *) &pSMBr->hdr.Protocol) +
4319 data_offset);
4320 FSData->f_bsize =
4321 le32_to_cpu(response_data->BlockSize);
4322 FSData->f_blocks =
4323 le64_to_cpu(response_data->TotalBlocks);
4324 FSData->f_bfree =
4325 le64_to_cpu(response_data->BlocksAvail);
4326 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4327 FSData->f_bavail = FSData->f_bfree;
4328 } else {
4329 FSData->f_bavail =
4330 le64_to_cpu(response_data->UserBlocksAvail);
4332 if(response_data->TotalFileNodes != cpu_to_le64(-1))
4333 FSData->f_files =
4334 le64_to_cpu(response_data->TotalFileNodes);
4335 if(response_data->FreeFileNodes != cpu_to_le64(-1))
4336 FSData->f_ffree =
4337 le64_to_cpu(response_data->FreeFileNodes);
4340 cifs_buf_release(pSMB);
4342 if (rc == -EAGAIN)
4343 goto QFSPosixRetry;
4345 return rc;
4349 /* We can not use write of zero bytes trick to
4350 set file size due to need for large file support. Also note that
4351 this SetPathInfo is preferred to SetFileInfo based method in next
4352 routine which is only needed to work around a sharing violation bug
4353 in Samba which this routine can run into */
4356 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4357 __u64 size, int SetAllocation,
4358 const struct nls_table *nls_codepage, int remap)
4360 struct smb_com_transaction2_spi_req *pSMB = NULL;
4361 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4362 struct file_end_of_file_info *parm_data;
4363 int name_len;
4364 int rc = 0;
4365 int bytes_returned = 0;
4366 __u16 params, byte_count, data_count, param_offset, offset;
4368 cFYI(1, ("In SetEOF"));
4369 SetEOFRetry:
4370 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4371 (void **) &pSMBr);
4372 if (rc)
4373 return rc;
4375 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4376 name_len =
4377 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4378 PATH_MAX, nls_codepage, remap);
4379 name_len++; /* trailing null */
4380 name_len *= 2;
4381 } else { /* BB improve the check for buffer overruns BB */
4382 name_len = strnlen(fileName, PATH_MAX);
4383 name_len++; /* trailing null */
4384 strncpy(pSMB->FileName, fileName, name_len);
4386 params = 6 + name_len;
4387 data_count = sizeof (struct file_end_of_file_info);
4388 pSMB->MaxParameterCount = cpu_to_le16(2);
4389 pSMB->MaxDataCount = cpu_to_le16(4100);
4390 pSMB->MaxSetupCount = 0;
4391 pSMB->Reserved = 0;
4392 pSMB->Flags = 0;
4393 pSMB->Timeout = 0;
4394 pSMB->Reserved2 = 0;
4395 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4396 InformationLevel) - 4;
4397 offset = param_offset + params;
4398 if(SetAllocation) {
4399 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4400 pSMB->InformationLevel =
4401 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4402 else
4403 pSMB->InformationLevel =
4404 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4405 } else /* Set File Size */ {
4406 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4407 pSMB->InformationLevel =
4408 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4409 else
4410 pSMB->InformationLevel =
4411 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4414 parm_data =
4415 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4416 offset);
4417 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4418 pSMB->DataOffset = cpu_to_le16(offset);
4419 pSMB->SetupCount = 1;
4420 pSMB->Reserved3 = 0;
4421 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4422 byte_count = 3 /* pad */ + params + data_count;
4423 pSMB->DataCount = cpu_to_le16(data_count);
4424 pSMB->TotalDataCount = pSMB->DataCount;
4425 pSMB->ParameterCount = cpu_to_le16(params);
4426 pSMB->TotalParameterCount = pSMB->ParameterCount;
4427 pSMB->Reserved4 = 0;
4428 pSMB->hdr.smb_buf_length += byte_count;
4429 parm_data->FileSize = cpu_to_le64(size);
4430 pSMB->ByteCount = cpu_to_le16(byte_count);
4431 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4432 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4433 if (rc) {
4434 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4437 cifs_buf_release(pSMB);
4439 if (rc == -EAGAIN)
4440 goto SetEOFRetry;
4442 return rc;
4446 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4447 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4449 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4450 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4451 char *data_offset;
4452 struct file_end_of_file_info *parm_data;
4453 int rc = 0;
4454 int bytes_returned = 0;
4455 __u16 params, param_offset, offset, byte_count, count;
4457 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4458 (long long)size));
4459 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4461 if (rc)
4462 return rc;
4464 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4466 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4467 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4469 params = 6;
4470 pSMB->MaxSetupCount = 0;
4471 pSMB->Reserved = 0;
4472 pSMB->Flags = 0;
4473 pSMB->Timeout = 0;
4474 pSMB->Reserved2 = 0;
4475 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4476 offset = param_offset + params;
4478 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4480 count = sizeof(struct file_end_of_file_info);
4481 pSMB->MaxParameterCount = cpu_to_le16(2);
4482 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4483 pSMB->SetupCount = 1;
4484 pSMB->Reserved3 = 0;
4485 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4486 byte_count = 3 /* pad */ + params + count;
4487 pSMB->DataCount = cpu_to_le16(count);
4488 pSMB->ParameterCount = cpu_to_le16(params);
4489 pSMB->TotalDataCount = pSMB->DataCount;
4490 pSMB->TotalParameterCount = pSMB->ParameterCount;
4491 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4492 parm_data =
4493 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4494 offset);
4495 pSMB->DataOffset = cpu_to_le16(offset);
4496 parm_data->FileSize = cpu_to_le64(size);
4497 pSMB->Fid = fid;
4498 if(SetAllocation) {
4499 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4500 pSMB->InformationLevel =
4501 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4502 else
4503 pSMB->InformationLevel =
4504 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4505 } else /* Set File Size */ {
4506 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4507 pSMB->InformationLevel =
4508 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4509 else
4510 pSMB->InformationLevel =
4511 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4513 pSMB->Reserved4 = 0;
4514 pSMB->hdr.smb_buf_length += byte_count;
4515 pSMB->ByteCount = cpu_to_le16(byte_count);
4516 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4517 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4518 if (rc) {
4519 cFYI(1,
4520 ("Send error in SetFileInfo (SetFileSize) = %d",
4521 rc));
4524 if (pSMB)
4525 cifs_small_buf_release(pSMB);
4527 /* Note: On -EAGAIN error only caller can retry on handle based calls
4528 since file handle passed in no longer valid */
4530 return rc;
4533 /* Some legacy servers such as NT4 require that the file times be set on
4534 an open handle, rather than by pathname - this is awkward due to
4535 potential access conflicts on the open, but it is unavoidable for these
4536 old servers since the only other choice is to go from 100 nanosecond DCE
4537 time and resort to the original setpathinfo level which takes the ancient
4538 DOS time format with 2 second granularity */
4540 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4541 __u16 fid)
4543 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4544 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4545 char *data_offset;
4546 int rc = 0;
4547 int bytes_returned = 0;
4548 __u16 params, param_offset, offset, byte_count, count;
4550 cFYI(1, ("Set Times (via SetFileInfo)"));
4551 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4553 if (rc)
4554 return rc;
4556 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4558 /* At this point there is no need to override the current pid
4559 with the pid of the opener, but that could change if we someday
4560 use an existing handle (rather than opening one on the fly) */
4561 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4562 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4564 params = 6;
4565 pSMB->MaxSetupCount = 0;
4566 pSMB->Reserved = 0;
4567 pSMB->Flags = 0;
4568 pSMB->Timeout = 0;
4569 pSMB->Reserved2 = 0;
4570 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4571 offset = param_offset + params;
4573 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4575 count = sizeof (FILE_BASIC_INFO);
4576 pSMB->MaxParameterCount = cpu_to_le16(2);
4577 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4578 pSMB->SetupCount = 1;
4579 pSMB->Reserved3 = 0;
4580 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4581 byte_count = 3 /* pad */ + params + count;
4582 pSMB->DataCount = cpu_to_le16(count);
4583 pSMB->ParameterCount = cpu_to_le16(params);
4584 pSMB->TotalDataCount = pSMB->DataCount;
4585 pSMB->TotalParameterCount = pSMB->ParameterCount;
4586 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4587 pSMB->DataOffset = cpu_to_le16(offset);
4588 pSMB->Fid = fid;
4589 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4590 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4591 else
4592 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4593 pSMB->Reserved4 = 0;
4594 pSMB->hdr.smb_buf_length += byte_count;
4595 pSMB->ByteCount = cpu_to_le16(byte_count);
4596 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4597 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4598 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4599 if (rc) {
4600 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4603 cifs_small_buf_release(pSMB);
4605 /* Note: On -EAGAIN error only caller can retry on handle based calls
4606 since file handle passed in no longer valid */
4608 return rc;
4613 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4614 const FILE_BASIC_INFO * data,
4615 const struct nls_table *nls_codepage, int remap)
4617 TRANSACTION2_SPI_REQ *pSMB = NULL;
4618 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4619 int name_len;
4620 int rc = 0;
4621 int bytes_returned = 0;
4622 char *data_offset;
4623 __u16 params, param_offset, offset, byte_count, count;
4625 cFYI(1, ("In SetTimes"));
4627 SetTimesRetry:
4628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4629 (void **) &pSMBr);
4630 if (rc)
4631 return rc;
4633 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4634 name_len =
4635 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4636 PATH_MAX, nls_codepage, remap);
4637 name_len++; /* trailing null */
4638 name_len *= 2;
4639 } else { /* BB improve the check for buffer overruns BB */
4640 name_len = strnlen(fileName, PATH_MAX);
4641 name_len++; /* trailing null */
4642 strncpy(pSMB->FileName, fileName, name_len);
4645 params = 6 + name_len;
4646 count = sizeof (FILE_BASIC_INFO);
4647 pSMB->MaxParameterCount = cpu_to_le16(2);
4648 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4649 pSMB->MaxSetupCount = 0;
4650 pSMB->Reserved = 0;
4651 pSMB->Flags = 0;
4652 pSMB->Timeout = 0;
4653 pSMB->Reserved2 = 0;
4654 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4655 InformationLevel) - 4;
4656 offset = param_offset + params;
4657 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4658 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4659 pSMB->DataOffset = cpu_to_le16(offset);
4660 pSMB->SetupCount = 1;
4661 pSMB->Reserved3 = 0;
4662 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4663 byte_count = 3 /* pad */ + params + count;
4665 pSMB->DataCount = cpu_to_le16(count);
4666 pSMB->ParameterCount = cpu_to_le16(params);
4667 pSMB->TotalDataCount = pSMB->DataCount;
4668 pSMB->TotalParameterCount = pSMB->ParameterCount;
4669 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4670 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4671 else
4672 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4673 pSMB->Reserved4 = 0;
4674 pSMB->hdr.smb_buf_length += byte_count;
4675 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4676 pSMB->ByteCount = cpu_to_le16(byte_count);
4677 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4678 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4679 if (rc) {
4680 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4683 cifs_buf_release(pSMB);
4685 if (rc == -EAGAIN)
4686 goto SetTimesRetry;
4688 return rc;
4691 /* Can not be used to set time stamps yet (due to old DOS time format) */
4692 /* Can be used to set attributes */
4693 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4694 handling it anyway and NT4 was what we thought it would be needed for
4695 Do not delete it until we prove whether needed for Win9x though */
4697 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4698 __u16 dos_attrs, const struct nls_table *nls_codepage)
4700 SETATTR_REQ *pSMB = NULL;
4701 SETATTR_RSP *pSMBr = NULL;
4702 int rc = 0;
4703 int bytes_returned;
4704 int name_len;
4706 cFYI(1, ("In SetAttrLegacy"));
4708 SetAttrLgcyRetry:
4709 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4710 (void **) &pSMBr);
4711 if (rc)
4712 return rc;
4714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4715 name_len =
4716 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4717 PATH_MAX, nls_codepage);
4718 name_len++; /* trailing null */
4719 name_len *= 2;
4720 } else { /* BB improve the check for buffer overruns BB */
4721 name_len = strnlen(fileName, PATH_MAX);
4722 name_len++; /* trailing null */
4723 strncpy(pSMB->fileName, fileName, name_len);
4725 pSMB->attr = cpu_to_le16(dos_attrs);
4726 pSMB->BufferFormat = 0x04;
4727 pSMB->hdr.smb_buf_length += name_len + 1;
4728 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4731 if (rc) {
4732 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4735 cifs_buf_release(pSMB);
4737 if (rc == -EAGAIN)
4738 goto SetAttrLgcyRetry;
4740 return rc;
4742 #endif /* temporarily unneeded SetAttr legacy function */
4745 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4746 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4747 dev_t device, const struct nls_table *nls_codepage,
4748 int remap)
4750 TRANSACTION2_SPI_REQ *pSMB = NULL;
4751 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4752 int name_len;
4753 int rc = 0;
4754 int bytes_returned = 0;
4755 FILE_UNIX_BASIC_INFO *data_offset;
4756 __u16 params, param_offset, offset, count, byte_count;
4758 cFYI(1, ("In SetUID/GID/Mode"));
4759 setPermsRetry:
4760 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4761 (void **) &pSMBr);
4762 if (rc)
4763 return rc;
4765 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4766 name_len =
4767 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4768 PATH_MAX, nls_codepage, remap);
4769 name_len++; /* trailing null */
4770 name_len *= 2;
4771 } else { /* BB improve the check for buffer overruns BB */
4772 name_len = strnlen(fileName, PATH_MAX);
4773 name_len++; /* trailing null */
4774 strncpy(pSMB->FileName, fileName, name_len);
4777 params = 6 + name_len;
4778 count = sizeof (FILE_UNIX_BASIC_INFO);
4779 pSMB->MaxParameterCount = cpu_to_le16(2);
4780 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4781 pSMB->MaxSetupCount = 0;
4782 pSMB->Reserved = 0;
4783 pSMB->Flags = 0;
4784 pSMB->Timeout = 0;
4785 pSMB->Reserved2 = 0;
4786 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4787 InformationLevel) - 4;
4788 offset = param_offset + params;
4789 data_offset =
4790 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4791 offset);
4792 memset(data_offset, 0, count);
4793 pSMB->DataOffset = cpu_to_le16(offset);
4794 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4795 pSMB->SetupCount = 1;
4796 pSMB->Reserved3 = 0;
4797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4798 byte_count = 3 /* pad */ + params + count;
4799 pSMB->ParameterCount = cpu_to_le16(params);
4800 pSMB->DataCount = cpu_to_le16(count);
4801 pSMB->TotalParameterCount = pSMB->ParameterCount;
4802 pSMB->TotalDataCount = pSMB->DataCount;
4803 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4804 pSMB->Reserved4 = 0;
4805 pSMB->hdr.smb_buf_length += byte_count;
4806 /* Samba server ignores set of file size to zero due to bugs in some
4807 older clients, but we should be precise - we use SetFileSize to
4808 set file size and do not want to truncate file size to zero
4809 accidently as happened on one Samba server beta by putting
4810 zero instead of -1 here */
4811 data_offset->EndOfFile = NO_CHANGE_64;
4812 data_offset->NumOfBytes = NO_CHANGE_64;
4813 data_offset->LastStatusChange = NO_CHANGE_64;
4814 data_offset->LastAccessTime = NO_CHANGE_64;
4815 data_offset->LastModificationTime = NO_CHANGE_64;
4816 data_offset->Uid = cpu_to_le64(uid);
4817 data_offset->Gid = cpu_to_le64(gid);
4818 /* better to leave device as zero when it is */
4819 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4820 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4821 data_offset->Permissions = cpu_to_le64(mode);
4823 if(S_ISREG(mode))
4824 data_offset->Type = cpu_to_le32(UNIX_FILE);
4825 else if(S_ISDIR(mode))
4826 data_offset->Type = cpu_to_le32(UNIX_DIR);
4827 else if(S_ISLNK(mode))
4828 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4829 else if(S_ISCHR(mode))
4830 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4831 else if(S_ISBLK(mode))
4832 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4833 else if(S_ISFIFO(mode))
4834 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4835 else if(S_ISSOCK(mode))
4836 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4839 pSMB->ByteCount = cpu_to_le16(byte_count);
4840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4842 if (rc) {
4843 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4846 if (pSMB)
4847 cifs_buf_release(pSMB);
4848 if (rc == -EAGAIN)
4849 goto setPermsRetry;
4850 return rc;
4853 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4854 const int notify_subdirs, const __u16 netfid,
4855 __u32 filter, struct file * pfile, int multishot,
4856 const struct nls_table *nls_codepage)
4858 int rc = 0;
4859 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4860 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4861 struct dir_notify_req *dnotify_req;
4862 int bytes_returned;
4864 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4865 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4866 (void **) &pSMBr);
4867 if (rc)
4868 return rc;
4870 pSMB->TotalParameterCount = 0 ;
4871 pSMB->TotalDataCount = 0;
4872 pSMB->MaxParameterCount = cpu_to_le32(2);
4873 /* BB find exact data count max from sess structure BB */
4874 pSMB->MaxDataCount = 0; /* same in little endian or be */
4875 /* BB VERIFY verify which is correct for above BB */
4876 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4877 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4879 pSMB->MaxSetupCount = 4;
4880 pSMB->Reserved = 0;
4881 pSMB->ParameterOffset = 0;
4882 pSMB->DataCount = 0;
4883 pSMB->DataOffset = 0;
4884 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4885 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4886 pSMB->ParameterCount = pSMB->TotalParameterCount;
4887 if(notify_subdirs)
4888 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4889 pSMB->Reserved2 = 0;
4890 pSMB->CompletionFilter = cpu_to_le32(filter);
4891 pSMB->Fid = netfid; /* file handle always le */
4892 pSMB->ByteCount = 0;
4894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4895 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4896 if (rc) {
4897 cFYI(1, ("Error in Notify = %d", rc));
4898 } else {
4899 /* Add file to outstanding requests */
4900 /* BB change to kmem cache alloc */
4901 dnotify_req = kmalloc(
4902 sizeof(struct dir_notify_req),
4903 GFP_KERNEL);
4904 if(dnotify_req) {
4905 dnotify_req->Pid = pSMB->hdr.Pid;
4906 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4907 dnotify_req->Mid = pSMB->hdr.Mid;
4908 dnotify_req->Tid = pSMB->hdr.Tid;
4909 dnotify_req->Uid = pSMB->hdr.Uid;
4910 dnotify_req->netfid = netfid;
4911 dnotify_req->pfile = pfile;
4912 dnotify_req->filter = filter;
4913 dnotify_req->multishot = multishot;
4914 spin_lock(&GlobalMid_Lock);
4915 list_add_tail(&dnotify_req->lhead,
4916 &GlobalDnotifyReqList);
4917 spin_unlock(&GlobalMid_Lock);
4918 } else
4919 rc = -ENOMEM;
4921 cifs_buf_release(pSMB);
4922 return rc;
4924 #ifdef CONFIG_CIFS_XATTR
4925 ssize_t
4926 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4927 const unsigned char *searchName,
4928 char * EAData, size_t buf_size,
4929 const struct nls_table *nls_codepage, int remap)
4931 /* BB assumes one setup word */
4932 TRANSACTION2_QPI_REQ *pSMB = NULL;
4933 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4934 int rc = 0;
4935 int bytes_returned;
4936 int name_len;
4937 struct fea * temp_fea;
4938 char * temp_ptr;
4939 __u16 params, byte_count;
4941 cFYI(1, ("In Query All EAs path %s", searchName));
4942 QAllEAsRetry:
4943 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4944 (void **) &pSMBr);
4945 if (rc)
4946 return rc;
4948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4949 name_len =
4950 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4951 PATH_MAX, nls_codepage, remap);
4952 name_len++; /* trailing null */
4953 name_len *= 2;
4954 } else { /* BB improve the check for buffer overruns BB */
4955 name_len = strnlen(searchName, PATH_MAX);
4956 name_len++; /* trailing null */
4957 strncpy(pSMB->FileName, searchName, name_len);
4960 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4961 pSMB->TotalDataCount = 0;
4962 pSMB->MaxParameterCount = cpu_to_le16(2);
4963 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4964 pSMB->MaxSetupCount = 0;
4965 pSMB->Reserved = 0;
4966 pSMB->Flags = 0;
4967 pSMB->Timeout = 0;
4968 pSMB->Reserved2 = 0;
4969 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4970 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4971 pSMB->DataCount = 0;
4972 pSMB->DataOffset = 0;
4973 pSMB->SetupCount = 1;
4974 pSMB->Reserved3 = 0;
4975 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4976 byte_count = params + 1 /* pad */ ;
4977 pSMB->TotalParameterCount = cpu_to_le16(params);
4978 pSMB->ParameterCount = pSMB->TotalParameterCount;
4979 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4980 pSMB->Reserved4 = 0;
4981 pSMB->hdr.smb_buf_length += byte_count;
4982 pSMB->ByteCount = cpu_to_le16(byte_count);
4984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4986 if (rc) {
4987 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4988 } else { /* decode response */
4989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4991 /* BB also check enough total bytes returned */
4992 /* BB we need to improve the validity checking
4993 of these trans2 responses */
4994 if (rc || (pSMBr->ByteCount < 4))
4995 rc = -EIO; /* bad smb */
4996 /* else if (pFindData){
4997 memcpy((char *) pFindData,
4998 (char *) &pSMBr->hdr.Protocol +
4999 data_offset, kl);
5000 }*/ else {
5001 /* check that length of list is not more than bcc */
5002 /* check that each entry does not go beyond length
5003 of list */
5004 /* check that each element of each entry does not
5005 go beyond end of list */
5006 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5007 struct fealist * ea_response_data;
5008 rc = 0;
5009 /* validate_trans2_offsets() */
5010 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5011 ea_response_data = (struct fealist *)
5012 (((char *) &pSMBr->hdr.Protocol) +
5013 data_offset);
5014 name_len = le32_to_cpu(ea_response_data->list_len);
5015 cFYI(1,("ea length %d", name_len));
5016 if(name_len <= 8) {
5017 /* returned EA size zeroed at top of function */
5018 cFYI(1,("empty EA list returned from server"));
5019 } else {
5020 /* account for ea list len */
5021 name_len -= 4;
5022 temp_fea = ea_response_data->list;
5023 temp_ptr = (char *)temp_fea;
5024 while(name_len > 0) {
5025 __u16 value_len;
5026 name_len -= 4;
5027 temp_ptr += 4;
5028 rc += temp_fea->name_len;
5029 /* account for prefix user. and trailing null */
5030 rc = rc + 5 + 1;
5031 if(rc<(int)buf_size) {
5032 memcpy(EAData,"user.",5);
5033 EAData+=5;
5034 memcpy(EAData,temp_ptr,temp_fea->name_len);
5035 EAData+=temp_fea->name_len;
5036 /* null terminate name */
5037 *EAData = 0;
5038 EAData = EAData + 1;
5039 } else if(buf_size == 0) {
5040 /* skip copy - calc size only */
5041 } else {
5042 /* stop before overrun buffer */
5043 rc = -ERANGE;
5044 break;
5046 name_len -= temp_fea->name_len;
5047 temp_ptr += temp_fea->name_len;
5048 /* account for trailing null */
5049 name_len--;
5050 temp_ptr++;
5051 value_len = le16_to_cpu(temp_fea->value_len);
5052 name_len -= value_len;
5053 temp_ptr += value_len;
5054 /* BB check that temp_ptr is still within smb BB*/
5055 /* no trailing null to account for in value len */
5056 /* go on to next EA */
5057 temp_fea = (struct fea *)temp_ptr;
5062 if (pSMB)
5063 cifs_buf_release(pSMB);
5064 if (rc == -EAGAIN)
5065 goto QAllEAsRetry;
5067 return (ssize_t)rc;
5070 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5071 const unsigned char * searchName,const unsigned char * ea_name,
5072 unsigned char * ea_value, size_t buf_size,
5073 const struct nls_table *nls_codepage, int remap)
5075 TRANSACTION2_QPI_REQ *pSMB = NULL;
5076 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5077 int rc = 0;
5078 int bytes_returned;
5079 int name_len;
5080 struct fea * temp_fea;
5081 char * temp_ptr;
5082 __u16 params, byte_count;
5084 cFYI(1, ("In Query EA path %s", searchName));
5085 QEARetry:
5086 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5087 (void **) &pSMBr);
5088 if (rc)
5089 return rc;
5091 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5092 name_len =
5093 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5094 PATH_MAX, nls_codepage, remap);
5095 name_len++; /* trailing null */
5096 name_len *= 2;
5097 } else { /* BB improve the check for buffer overruns BB */
5098 name_len = strnlen(searchName, PATH_MAX);
5099 name_len++; /* trailing null */
5100 strncpy(pSMB->FileName, searchName, name_len);
5103 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5104 pSMB->TotalDataCount = 0;
5105 pSMB->MaxParameterCount = cpu_to_le16(2);
5106 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5107 pSMB->MaxSetupCount = 0;
5108 pSMB->Reserved = 0;
5109 pSMB->Flags = 0;
5110 pSMB->Timeout = 0;
5111 pSMB->Reserved2 = 0;
5112 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5113 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5114 pSMB->DataCount = 0;
5115 pSMB->DataOffset = 0;
5116 pSMB->SetupCount = 1;
5117 pSMB->Reserved3 = 0;
5118 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5119 byte_count = params + 1 /* pad */ ;
5120 pSMB->TotalParameterCount = cpu_to_le16(params);
5121 pSMB->ParameterCount = pSMB->TotalParameterCount;
5122 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5123 pSMB->Reserved4 = 0;
5124 pSMB->hdr.smb_buf_length += byte_count;
5125 pSMB->ByteCount = cpu_to_le16(byte_count);
5127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5129 if (rc) {
5130 cFYI(1, ("Send error in Query EA = %d", rc));
5131 } else { /* decode response */
5132 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5134 /* BB also check enough total bytes returned */
5135 /* BB we need to improve the validity checking
5136 of these trans2 responses */
5137 if (rc || (pSMBr->ByteCount < 4))
5138 rc = -EIO; /* bad smb */
5139 /* else if (pFindData){
5140 memcpy((char *) pFindData,
5141 (char *) &pSMBr->hdr.Protocol +
5142 data_offset, kl);
5143 }*/ else {
5144 /* check that length of list is not more than bcc */
5145 /* check that each entry does not go beyond length
5146 of list */
5147 /* check that each element of each entry does not
5148 go beyond end of list */
5149 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5150 struct fealist * ea_response_data;
5151 rc = -ENODATA;
5152 /* validate_trans2_offsets() */
5153 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5154 ea_response_data = (struct fealist *)
5155 (((char *) &pSMBr->hdr.Protocol) +
5156 data_offset);
5157 name_len = le32_to_cpu(ea_response_data->list_len);
5158 cFYI(1,("ea length %d", name_len));
5159 if(name_len <= 8) {
5160 /* returned EA size zeroed at top of function */
5161 cFYI(1,("empty EA list returned from server"));
5162 } else {
5163 /* account for ea list len */
5164 name_len -= 4;
5165 temp_fea = ea_response_data->list;
5166 temp_ptr = (char *)temp_fea;
5167 /* loop through checking if we have a matching
5168 name and then return the associated value */
5169 while(name_len > 0) {
5170 __u16 value_len;
5171 name_len -= 4;
5172 temp_ptr += 4;
5173 value_len = le16_to_cpu(temp_fea->value_len);
5174 /* BB validate that value_len falls within SMB,
5175 even though maximum for name_len is 255 */
5176 if(memcmp(temp_fea->name,ea_name,
5177 temp_fea->name_len) == 0) {
5178 /* found a match */
5179 rc = value_len;
5180 /* account for prefix user. and trailing null */
5181 if(rc<=(int)buf_size) {
5182 memcpy(ea_value,
5183 temp_fea->name+temp_fea->name_len+1,
5184 rc);
5185 /* ea values, unlike ea names,
5186 are not null terminated */
5187 } else if(buf_size == 0) {
5188 /* skip copy - calc size only */
5189 } else {
5190 /* stop before overrun buffer */
5191 rc = -ERANGE;
5193 break;
5195 name_len -= temp_fea->name_len;
5196 temp_ptr += temp_fea->name_len;
5197 /* account for trailing null */
5198 name_len--;
5199 temp_ptr++;
5200 name_len -= value_len;
5201 temp_ptr += value_len;
5202 /* no trailing null to account for in value len */
5203 /* go on to next EA */
5204 temp_fea = (struct fea *)temp_ptr;
5209 if (pSMB)
5210 cifs_buf_release(pSMB);
5211 if (rc == -EAGAIN)
5212 goto QEARetry;
5214 return (ssize_t)rc;
5218 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5219 const char * ea_name, const void * ea_value,
5220 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5221 int remap)
5223 struct smb_com_transaction2_spi_req *pSMB = NULL;
5224 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5225 struct fealist *parm_data;
5226 int name_len;
5227 int rc = 0;
5228 int bytes_returned = 0;
5229 __u16 params, param_offset, byte_count, offset, count;
5231 cFYI(1, ("In SetEA"));
5232 SetEARetry:
5233 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5234 (void **) &pSMBr);
5235 if (rc)
5236 return rc;
5238 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5239 name_len =
5240 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5241 PATH_MAX, nls_codepage, remap);
5242 name_len++; /* trailing null */
5243 name_len *= 2;
5244 } else { /* BB improve the check for buffer overruns BB */
5245 name_len = strnlen(fileName, PATH_MAX);
5246 name_len++; /* trailing null */
5247 strncpy(pSMB->FileName, fileName, name_len);
5250 params = 6 + name_len;
5252 /* done calculating parms using name_len of file name,
5253 now use name_len to calculate length of ea name
5254 we are going to create in the inode xattrs */
5255 if(ea_name == NULL)
5256 name_len = 0;
5257 else
5258 name_len = strnlen(ea_name,255);
5260 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5261 pSMB->MaxParameterCount = cpu_to_le16(2);
5262 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5263 pSMB->MaxSetupCount = 0;
5264 pSMB->Reserved = 0;
5265 pSMB->Flags = 0;
5266 pSMB->Timeout = 0;
5267 pSMB->Reserved2 = 0;
5268 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5269 InformationLevel) - 4;
5270 offset = param_offset + params;
5271 pSMB->InformationLevel =
5272 cpu_to_le16(SMB_SET_FILE_EA);
5274 parm_data =
5275 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5276 offset);
5277 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5278 pSMB->DataOffset = cpu_to_le16(offset);
5279 pSMB->SetupCount = 1;
5280 pSMB->Reserved3 = 0;
5281 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5282 byte_count = 3 /* pad */ + params + count;
5283 pSMB->DataCount = cpu_to_le16(count);
5284 parm_data->list_len = cpu_to_le32(count);
5285 parm_data->list[0].EA_flags = 0;
5286 /* we checked above that name len is less than 255 */
5287 parm_data->list[0].name_len = (__u8)name_len;
5288 /* EA names are always ASCII */
5289 if(ea_name)
5290 strncpy(parm_data->list[0].name,ea_name,name_len);
5291 parm_data->list[0].name[name_len] = 0;
5292 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5293 /* caller ensures that ea_value_len is less than 64K but
5294 we need to ensure that it fits within the smb */
5296 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5297 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5298 if(ea_value_len)
5299 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5301 pSMB->TotalDataCount = pSMB->DataCount;
5302 pSMB->ParameterCount = cpu_to_le16(params);
5303 pSMB->TotalParameterCount = pSMB->ParameterCount;
5304 pSMB->Reserved4 = 0;
5305 pSMB->hdr.smb_buf_length += byte_count;
5306 pSMB->ByteCount = cpu_to_le16(byte_count);
5307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5309 if (rc) {
5310 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5313 cifs_buf_release(pSMB);
5315 if (rc == -EAGAIN)
5316 goto SetEARetry;
5318 return rc;
5321 #endif