[DCCP] ackvec: Introduce dccp_ackvec_slab
[linux-2.6/verdex.git] / fs / cifs / cifssmb.c
blobb41e8b379652b228377f01d1d20bfaa47c3883e8
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2005
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 {CIFS_PROT, "\2NT LM 0.12"},
48 {CIFS_PROT, "\2POSIX 2"},
49 {BAD_PROT, "\2"}
51 #else
52 static struct {
53 int index;
54 char *name;
55 } protocols[] = {
56 {CIFS_PROT, "\2NT LM 0.12"},
57 {BAD_PROT, "\2"}
59 #endif
62 /* Mark as invalid, all open files on tree connections since they
63 were closed when session to server was lost */
64 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
66 struct cifsFileInfo *open_file = NULL;
67 struct list_head * tmp;
68 struct list_head * tmp1;
70 /* list all files open on tree connection and mark them invalid */
71 write_lock(&GlobalSMBSeslock);
72 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
73 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
74 if(open_file) {
75 open_file->invalidHandle = TRUE;
78 write_unlock(&GlobalSMBSeslock);
79 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
80 to this tcon */
83 /* If the return code is zero, this function must fill in request_buf pointer */
84 static int
85 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
86 void **request_buf /* returned */)
88 int rc = 0;
90 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
91 check for tcp and smb session status done differently
92 for those three - in the calling routine */
93 if(tcon) {
94 if(tcon->tidStatus == CifsExiting) {
95 /* only tree disconnect, open, and write,
96 (and ulogoff which does not have tcon)
97 are allowed as we start force umount */
98 if((smb_command != SMB_COM_WRITE_ANDX) &&
99 (smb_command != SMB_COM_OPEN_ANDX) &&
100 (smb_command != SMB_COM_TREE_DISCONNECT)) {
101 cFYI(1,("can not send cmd %d while umounting",
102 smb_command));
103 return -ENODEV;
106 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
107 (tcon->ses->server)){
108 struct nls_table *nls_codepage;
109 /* Give Demultiplex thread up to 10 seconds to
110 reconnect, should be greater than cifs socket
111 timeout which is 7 seconds */
112 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
113 wait_event_interruptible_timeout(tcon->ses->server->response_q,
114 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
115 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
116 /* on "soft" mounts we wait once */
117 if((tcon->retry == FALSE) ||
118 (tcon->ses->status == CifsExiting)) {
119 cFYI(1,("gave up waiting on reconnect in smb_init"));
120 return -EHOSTDOWN;
121 } /* else "hard" mount - keep retrying
122 until process is killed or server
123 comes back on-line */
124 } else /* TCP session is reestablished now */
125 break;
129 nls_codepage = load_nls_default();
130 /* need to prevent multiple threads trying to
131 simultaneously reconnect the same SMB session */
132 down(&tcon->ses->sesSem);
133 if(tcon->ses->status == CifsNeedReconnect)
134 rc = cifs_setup_session(0, tcon->ses,
135 nls_codepage);
136 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
137 mark_open_files_invalid(tcon);
138 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
139 , nls_codepage);
140 up(&tcon->ses->sesSem);
141 /* BB FIXME add code to check if wsize needs
142 update due to negotiated smb buffer size
143 shrinking */
144 if(rc == 0)
145 atomic_inc(&tconInfoReconnectCount);
147 cFYI(1, ("reconnect tcon rc = %d", rc));
148 /* Removed call to reopen open files here -
149 it is safer (and faster) to reopen files
150 one at a time as needed in read and write */
152 /* Check if handle based operation so we
153 know whether we can continue or not without
154 returning to caller to reset file handle */
155 switch(smb_command) {
156 case SMB_COM_READ_ANDX:
157 case SMB_COM_WRITE_ANDX:
158 case SMB_COM_CLOSE:
159 case SMB_COM_FIND_CLOSE2:
160 case SMB_COM_LOCKING_ANDX: {
161 unload_nls(nls_codepage);
162 return -EAGAIN;
165 } else {
166 up(&tcon->ses->sesSem);
168 unload_nls(nls_codepage);
170 } else {
171 return -EIO;
174 if(rc)
175 return rc;
177 *request_buf = cifs_small_buf_get();
178 if (*request_buf == NULL) {
179 /* BB should we add a retry in here if not a writepage? */
180 return -ENOMEM;
183 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
185 if(tcon != NULL)
186 cifs_stats_inc(&tcon->num_smbs_sent);
188 return rc;
191 /* If the return code is zero, this function must fill in request_buf pointer */
192 static int
193 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
194 void **request_buf /* returned */ ,
195 void **response_buf /* returned */ )
197 int rc = 0;
199 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
200 check for tcp and smb session status done differently
201 for those three - in the calling routine */
202 if(tcon) {
203 if(tcon->tidStatus == CifsExiting) {
204 /* only tree disconnect, open, and write,
205 (and ulogoff which does not have tcon)
206 are allowed as we start force umount */
207 if((smb_command != SMB_COM_WRITE_ANDX) &&
208 (smb_command != SMB_COM_OPEN_ANDX) &&
209 (smb_command != SMB_COM_TREE_DISCONNECT)) {
210 cFYI(1,("can not send cmd %d while umounting",
211 smb_command));
212 return -ENODEV;
216 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
217 (tcon->ses->server)){
218 struct nls_table *nls_codepage;
219 /* Give Demultiplex thread up to 10 seconds to
220 reconnect, should be greater than cifs socket
221 timeout which is 7 seconds */
222 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
223 wait_event_interruptible_timeout(tcon->ses->server->response_q,
224 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
225 if(tcon->ses->server->tcpStatus ==
226 CifsNeedReconnect) {
227 /* on "soft" mounts we wait once */
228 if((tcon->retry == FALSE) ||
229 (tcon->ses->status == CifsExiting)) {
230 cFYI(1,("gave up waiting on reconnect in smb_init"));
231 return -EHOSTDOWN;
232 } /* else "hard" mount - keep retrying
233 until process is killed or server
234 comes on-line */
235 } else /* TCP session is reestablished now */
236 break;
240 nls_codepage = load_nls_default();
241 /* need to prevent multiple threads trying to
242 simultaneously reconnect the same SMB session */
243 down(&tcon->ses->sesSem);
244 if(tcon->ses->status == CifsNeedReconnect)
245 rc = cifs_setup_session(0, tcon->ses,
246 nls_codepage);
247 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
248 mark_open_files_invalid(tcon);
249 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
250 tcon, nls_codepage);
251 up(&tcon->ses->sesSem);
252 /* BB FIXME add code to check if wsize needs
253 update due to negotiated smb buffer size
254 shrinking */
255 if(rc == 0)
256 atomic_inc(&tconInfoReconnectCount);
258 cFYI(1, ("reconnect tcon rc = %d", rc));
259 /* Removed call to reopen open files here -
260 it is safer (and faster) to reopen files
261 one at a time as needed in read and write */
263 /* Check if handle based operation so we
264 know whether we can continue or not without
265 returning to caller to reset file handle */
266 switch(smb_command) {
267 case SMB_COM_READ_ANDX:
268 case SMB_COM_WRITE_ANDX:
269 case SMB_COM_CLOSE:
270 case SMB_COM_FIND_CLOSE2:
271 case SMB_COM_LOCKING_ANDX: {
272 unload_nls(nls_codepage);
273 return -EAGAIN;
276 } else {
277 up(&tcon->ses->sesSem);
279 unload_nls(nls_codepage);
281 } else {
282 return -EIO;
285 if(rc)
286 return rc;
288 *request_buf = cifs_buf_get();
289 if (*request_buf == NULL) {
290 /* BB should we add a retry in here if not a writepage? */
291 return -ENOMEM;
293 /* Although the original thought was we needed the response buf for */
294 /* potential retries of smb operations it turns out we can determine */
295 /* from the mid flags when the request buffer can be resent without */
296 /* having to use a second distinct buffer for the response */
297 *response_buf = *request_buf;
299 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
300 wct /*wct */ );
302 if(tcon != NULL)
303 cifs_stats_inc(&tcon->num_smbs_sent);
305 return rc;
308 static int validate_t2(struct smb_t2_rsp * pSMB)
310 int rc = -EINVAL;
311 int total_size;
312 char * pBCC;
314 /* check for plausible wct, bcc and t2 data and parm sizes */
315 /* check for parm and data offset going beyond end of smb */
316 if(pSMB->hdr.WordCount >= 10) {
317 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
318 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
319 /* check that bcc is at least as big as parms + data */
320 /* check that bcc is less than negotiated smb buffer */
321 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
322 if(total_size < 512) {
323 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
324 /* BCC le converted in SendReceive */
325 pBCC = (pSMB->hdr.WordCount * 2) +
326 sizeof(struct smb_hdr) +
327 (char *)pSMB;
328 if((total_size <= (*(u16 *)pBCC)) &&
329 (total_size <
330 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
331 return 0;
337 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
338 sizeof(struct smb_t2_rsp) + 16);
339 return rc;
342 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
344 NEGOTIATE_REQ *pSMB;
345 NEGOTIATE_RSP *pSMBr;
346 int rc = 0;
347 int bytes_returned;
348 struct TCP_Server_Info * server;
349 u16 count;
351 if(ses->server)
352 server = ses->server;
353 else {
354 rc = -EIO;
355 return rc;
357 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
358 (void **) &pSMB, (void **) &pSMBr);
359 if (rc)
360 return rc;
361 pSMB->hdr.Mid = GetNextMid(server);
362 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
363 if (extended_security)
364 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
366 count = strlen(protocols[0].name) + 1;
367 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
368 /* null guaranteed to be at end of source and target buffers anyway */
370 pSMB->hdr.smb_buf_length += count;
371 pSMB->ByteCount = cpu_to_le16(count);
373 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
374 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
375 if (rc == 0) {
376 server->secMode = pSMBr->SecurityMode;
377 if((server->secMode & SECMODE_USER) == 0)
378 cFYI(1,("share mode security"));
379 server->secType = NTLM; /* BB override default for
380 NTLMv2 or kerberos v5 */
381 /* one byte - no need to convert this or EncryptionKeyLen
382 from little endian */
383 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
384 /* probably no need to store and check maxvcs */
385 server->maxBuf =
386 min(le32_to_cpu(pSMBr->MaxBufferSize),
387 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
388 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
389 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
390 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
391 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
392 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
393 /* BB with UTC do we ever need to be using srvr timezone? */
394 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
395 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
396 CIFS_CRYPTO_KEY_SIZE);
397 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
398 && (pSMBr->EncryptionKeyLength == 0)) {
399 /* decode security blob */
400 } else
401 rc = -EIO;
403 /* BB might be helpful to save off the domain of server here */
405 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
406 (server->capabilities & CAP_EXTENDED_SECURITY)) {
407 count = pSMBr->ByteCount;
408 if (count < 16)
409 rc = -EIO;
410 else if (count == 16) {
411 server->secType = RawNTLMSSP;
412 if (server->socketUseCount.counter > 1) {
413 if (memcmp
414 (server->server_GUID,
415 pSMBr->u.extended_response.
416 GUID, 16) != 0) {
417 cFYI(1, ("server UID changed"));
418 memcpy(server->
419 server_GUID,
420 pSMBr->u.
421 extended_response.
422 GUID, 16);
424 } else
425 memcpy(server->server_GUID,
426 pSMBr->u.extended_response.
427 GUID, 16);
428 } else {
429 rc = decode_negTokenInit(pSMBr->u.
430 extended_response.
431 SecurityBlob,
432 count - 16,
433 &server->secType);
434 if(rc == 1) {
435 /* BB Need to fill struct for sessetup here */
436 rc = -EOPNOTSUPP;
437 } else {
438 rc = -EINVAL;
441 } else
442 server->capabilities &= ~CAP_EXTENDED_SECURITY;
443 if(sign_CIFS_PDUs == FALSE) {
444 if(server->secMode & SECMODE_SIGN_REQUIRED)
445 cERROR(1,
446 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
447 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
448 } else if(sign_CIFS_PDUs == 1) {
449 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
450 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
455 cifs_buf_release(pSMB);
456 return rc;
460 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
462 struct smb_hdr *smb_buffer;
463 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
464 int rc = 0;
465 int length;
467 cFYI(1, ("In tree disconnect"));
469 * If last user of the connection and
470 * connection alive - disconnect it
471 * If this is the last connection on the server session disconnect it
472 * (and inside session disconnect we should check if tcp socket needs
473 * to be freed and kernel thread woken up).
475 if (tcon)
476 down(&tcon->tconSem);
477 else
478 return -EIO;
480 atomic_dec(&tcon->useCount);
481 if (atomic_read(&tcon->useCount) > 0) {
482 up(&tcon->tconSem);
483 return -EBUSY;
486 /* No need to return error on this operation if tid invalidated and
487 closed on server already e.g. due to tcp session crashing */
488 if(tcon->tidStatus == CifsNeedReconnect) {
489 up(&tcon->tconSem);
490 return 0;
493 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
494 up(&tcon->tconSem);
495 return -EIO;
497 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
498 (void **)&smb_buffer);
499 if (rc) {
500 up(&tcon->tconSem);
501 return rc;
502 } else {
503 smb_buffer_response = smb_buffer; /* BB removeme BB */
505 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
506 &length, 0);
507 if (rc)
508 cFYI(1, ("Tree disconnect failed %d", rc));
510 if (smb_buffer)
511 cifs_small_buf_release(smb_buffer);
512 up(&tcon->tconSem);
514 /* No need to return error on this operation if tid invalidated and
515 closed on server already e.g. due to tcp session crashing */
516 if (rc == -EAGAIN)
517 rc = 0;
519 return rc;
523 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
525 struct smb_hdr *smb_buffer_response;
526 LOGOFF_ANDX_REQ *pSMB;
527 int rc = 0;
528 int length;
530 cFYI(1, ("In SMBLogoff for session disconnect"));
531 if (ses)
532 down(&ses->sesSem);
533 else
534 return -EIO;
536 atomic_dec(&ses->inUse);
537 if (atomic_read(&ses->inUse) > 0) {
538 up(&ses->sesSem);
539 return -EBUSY;
541 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
542 if (rc) {
543 up(&ses->sesSem);
544 return rc;
547 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
549 if(ses->server) {
550 pSMB->hdr.Mid = GetNextMid(ses->server);
552 if(ses->server->secMode &
553 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
554 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
557 pSMB->hdr.Uid = ses->Suid;
559 pSMB->AndXCommand = 0xFF;
560 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
561 smb_buffer_response, &length, 0);
562 if (ses->server) {
563 atomic_dec(&ses->server->socketUseCount);
564 if (atomic_read(&ses->server->socketUseCount) == 0) {
565 spin_lock(&GlobalMid_Lock);
566 ses->server->tcpStatus = CifsExiting;
567 spin_unlock(&GlobalMid_Lock);
568 rc = -ESHUTDOWN;
571 up(&ses->sesSem);
572 cifs_small_buf_release(pSMB);
574 /* if session dead then we do not need to do ulogoff,
575 since server closed smb session, no sense reporting
576 error */
577 if (rc == -EAGAIN)
578 rc = 0;
579 return rc;
583 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
584 const struct nls_table *nls_codepage, int remap)
586 DELETE_FILE_REQ *pSMB = NULL;
587 DELETE_FILE_RSP *pSMBr = NULL;
588 int rc = 0;
589 int bytes_returned;
590 int name_len;
592 DelFileRetry:
593 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
594 (void **) &pSMBr);
595 if (rc)
596 return rc;
598 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
599 name_len =
600 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
601 PATH_MAX, nls_codepage, remap);
602 name_len++; /* trailing null */
603 name_len *= 2;
604 } else { /* BB improve check for buffer overruns BB */
605 name_len = strnlen(fileName, PATH_MAX);
606 name_len++; /* trailing null */
607 strncpy(pSMB->fileName, fileName, name_len);
609 pSMB->SearchAttributes =
610 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
611 pSMB->BufferFormat = 0x04;
612 pSMB->hdr.smb_buf_length += name_len + 1;
613 pSMB->ByteCount = cpu_to_le16(name_len + 1);
614 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
616 cifs_stats_inc(&tcon->num_deletes);
617 if (rc) {
618 cFYI(1, ("Error in RMFile = %d", rc));
621 cifs_buf_release(pSMB);
622 if (rc == -EAGAIN)
623 goto DelFileRetry;
625 return rc;
629 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
630 const struct nls_table *nls_codepage, int remap)
632 DELETE_DIRECTORY_REQ *pSMB = NULL;
633 DELETE_DIRECTORY_RSP *pSMBr = NULL;
634 int rc = 0;
635 int bytes_returned;
636 int name_len;
638 cFYI(1, ("In CIFSSMBRmDir"));
639 RmDirRetry:
640 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
641 (void **) &pSMBr);
642 if (rc)
643 return rc;
645 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
646 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
647 PATH_MAX, nls_codepage, remap);
648 name_len++; /* trailing null */
649 name_len *= 2;
650 } else { /* BB improve check for buffer overruns BB */
651 name_len = strnlen(dirName, PATH_MAX);
652 name_len++; /* trailing null */
653 strncpy(pSMB->DirName, dirName, name_len);
656 pSMB->BufferFormat = 0x04;
657 pSMB->hdr.smb_buf_length += name_len + 1;
658 pSMB->ByteCount = cpu_to_le16(name_len + 1);
659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
661 cifs_stats_inc(&tcon->num_rmdirs);
662 if (rc) {
663 cFYI(1, ("Error in RMDir = %d", rc));
666 cifs_buf_release(pSMB);
667 if (rc == -EAGAIN)
668 goto RmDirRetry;
669 return rc;
673 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
674 const char *name, const struct nls_table *nls_codepage, int remap)
676 int rc = 0;
677 CREATE_DIRECTORY_REQ *pSMB = NULL;
678 CREATE_DIRECTORY_RSP *pSMBr = NULL;
679 int bytes_returned;
680 int name_len;
682 cFYI(1, ("In CIFSSMBMkDir"));
683 MkDirRetry:
684 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
685 (void **) &pSMBr);
686 if (rc)
687 return rc;
689 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
690 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
691 PATH_MAX, nls_codepage, remap);
692 name_len++; /* trailing null */
693 name_len *= 2;
694 } else { /* BB improve check for buffer overruns BB */
695 name_len = strnlen(name, PATH_MAX);
696 name_len++; /* trailing null */
697 strncpy(pSMB->DirName, name, name_len);
700 pSMB->BufferFormat = 0x04;
701 pSMB->hdr.smb_buf_length += name_len + 1;
702 pSMB->ByteCount = cpu_to_le16(name_len + 1);
703 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
704 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
705 cifs_stats_inc(&tcon->num_mkdirs);
706 if (rc) {
707 cFYI(1, ("Error in Mkdir = %d", rc));
710 cifs_buf_release(pSMB);
711 if (rc == -EAGAIN)
712 goto MkDirRetry;
713 return rc;
716 static __u16 convert_disposition(int disposition)
718 __u16 ofun = 0;
720 switch (disposition) {
721 case FILE_SUPERSEDE:
722 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
723 break;
724 case FILE_OPEN:
725 ofun = SMBOPEN_OAPPEND;
726 break;
727 case FILE_CREATE:
728 ofun = SMBOPEN_OCREATE;
729 break;
730 case FILE_OPEN_IF:
731 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
732 break;
733 case FILE_OVERWRITE:
734 ofun = SMBOPEN_OTRUNC;
735 break;
736 case FILE_OVERWRITE_IF:
737 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
738 break;
739 default:
740 cFYI(1,("unknown disposition %d",disposition));
741 ofun = SMBOPEN_OAPPEND; /* regular open */
743 return ofun;
747 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
748 const char *fileName, const int openDisposition,
749 const int access_flags, const int create_options, __u16 * netfid,
750 int *pOplock, FILE_ALL_INFO * pfile_info,
751 const struct nls_table *nls_codepage, int remap)
753 int rc = -EACCES;
754 OPENX_REQ *pSMB = NULL;
755 OPENX_RSP *pSMBr = NULL;
756 int bytes_returned;
757 int name_len;
758 __u16 count;
760 OldOpenRetry:
761 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
762 (void **) &pSMBr);
763 if (rc)
764 return rc;
766 pSMB->AndXCommand = 0xFF; /* none */
768 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
769 count = 1; /* account for one byte pad to word boundary */
770 name_len =
771 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
772 fileName, PATH_MAX, nls_codepage, remap);
773 name_len++; /* trailing null */
774 name_len *= 2;
775 } else { /* BB improve check for buffer overruns BB */
776 count = 0; /* no pad */
777 name_len = strnlen(fileName, PATH_MAX);
778 name_len++; /* trailing null */
779 strncpy(pSMB->fileName, fileName, name_len);
781 if (*pOplock & REQ_OPLOCK)
782 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
783 else if (*pOplock & REQ_BATCHOPLOCK) {
784 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
786 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
787 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
788 /* 0 = read
789 1 = write
790 2 = rw
791 3 = execute
793 pSMB->Mode = cpu_to_le16(2);
794 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
795 /* set file as system file if special file such
796 as fifo and server expecting SFU style and
797 no Unix extensions */
799 if(create_options & CREATE_OPTION_SPECIAL)
800 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
801 else
802 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
804 /* if ((omode & S_IWUGO) == 0)
805 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
806 /* Above line causes problems due to vfs splitting create into two
807 pieces - need to set mode after file created not while it is
808 being created */
810 /* BB FIXME BB */
811 /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
812 /* BB FIXME END BB */
814 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
815 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
816 count += name_len;
817 pSMB->hdr.smb_buf_length += count;
819 pSMB->ByteCount = cpu_to_le16(count);
820 /* long_op set to 1 to allow for oplock break timeouts */
821 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
822 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
823 cifs_stats_inc(&tcon->num_opens);
824 if (rc) {
825 cFYI(1, ("Error in Open = %d", rc));
826 } else {
827 /* BB verify if wct == 15 */
829 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
831 *netfid = pSMBr->Fid; /* cifs fid stays in le */
832 /* Let caller know file was created so we can set the mode. */
833 /* Do we care about the CreateAction in any other cases? */
834 /* BB FIXME BB */
835 /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
836 *pOplock |= CIFS_CREATE_ACTION; */
837 /* BB FIXME END */
839 if(pfile_info) {
840 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
841 pfile_info->LastAccessTime = 0; /* BB fixme */
842 pfile_info->LastWriteTime = 0; /* BB fixme */
843 pfile_info->ChangeTime = 0; /* BB fixme */
844 pfile_info->Attributes =
845 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
846 /* the file_info buf is endian converted by caller */
847 pfile_info->AllocationSize =
848 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
849 pfile_info->EndOfFile = pfile_info->AllocationSize;
850 pfile_info->NumberOfLinks = cpu_to_le32(1);
854 cifs_buf_release(pSMB);
855 if (rc == -EAGAIN)
856 goto OldOpenRetry;
857 return rc;
861 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
862 const char *fileName, const int openDisposition,
863 const int access_flags, const int create_options, __u16 * netfid,
864 int *pOplock, FILE_ALL_INFO * pfile_info,
865 const struct nls_table *nls_codepage, int remap)
867 int rc = -EACCES;
868 OPEN_REQ *pSMB = NULL;
869 OPEN_RSP *pSMBr = NULL;
870 int bytes_returned;
871 int name_len;
872 __u16 count;
874 openRetry:
875 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
876 (void **) &pSMBr);
877 if (rc)
878 return rc;
880 pSMB->AndXCommand = 0xFF; /* none */
882 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
883 count = 1; /* account for one byte pad to word boundary */
884 name_len =
885 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
886 fileName, PATH_MAX, nls_codepage, remap);
887 name_len++; /* trailing null */
888 name_len *= 2;
889 pSMB->NameLength = cpu_to_le16(name_len);
890 } else { /* BB improve check for buffer overruns BB */
891 count = 0; /* no pad */
892 name_len = strnlen(fileName, PATH_MAX);
893 name_len++; /* trailing null */
894 pSMB->NameLength = cpu_to_le16(name_len);
895 strncpy(pSMB->fileName, fileName, name_len);
897 if (*pOplock & REQ_OPLOCK)
898 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
899 else if (*pOplock & REQ_BATCHOPLOCK) {
900 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
902 pSMB->DesiredAccess = cpu_to_le32(access_flags);
903 pSMB->AllocationSize = 0;
904 /* set file as system file if special file such
905 as fifo and server expecting SFU style and
906 no Unix extensions */
907 if(create_options & CREATE_OPTION_SPECIAL)
908 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
909 else
910 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
911 /* XP does not handle ATTR_POSIX_SEMANTICS */
912 /* but it helps speed up case sensitive checks for other
913 servers such as Samba */
914 if (tcon->ses->capabilities & CAP_UNIX)
915 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
917 /* if ((omode & S_IWUGO) == 0)
918 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
919 /* Above line causes problems due to vfs splitting create into two
920 pieces - need to set mode after file created not while it is
921 being created */
922 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
923 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
924 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
925 /* BB Expirement with various impersonation levels and verify */
926 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
927 pSMB->SecurityFlags =
928 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
930 count += name_len;
931 pSMB->hdr.smb_buf_length += count;
933 pSMB->ByteCount = cpu_to_le16(count);
934 /* long_op set to 1 to allow for oplock break timeouts */
935 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
936 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
937 cifs_stats_inc(&tcon->num_opens);
938 if (rc) {
939 cFYI(1, ("Error in Open = %d", rc));
940 } else {
941 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
942 *netfid = pSMBr->Fid; /* cifs fid stays in le */
943 /* Let caller know file was created so we can set the mode. */
944 /* Do we care about the CreateAction in any other cases? */
945 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
946 *pOplock |= CIFS_CREATE_ACTION;
947 if(pfile_info) {
948 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
949 36 /* CreationTime to Attributes */);
950 /* the file_info buf is endian converted by caller */
951 pfile_info->AllocationSize = pSMBr->AllocationSize;
952 pfile_info->EndOfFile = pSMBr->EndOfFile;
953 pfile_info->NumberOfLinks = cpu_to_le32(1);
957 cifs_buf_release(pSMB);
958 if (rc == -EAGAIN)
959 goto openRetry;
960 return rc;
964 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
965 const int netfid, const unsigned int count,
966 const __u64 lseek, unsigned int *nbytes, char **buf,
967 int * pbuf_type)
969 int rc = -EACCES;
970 READ_REQ *pSMB = NULL;
971 READ_RSP *pSMBr = NULL;
972 char *pReadData = NULL;
973 int wct;
974 int resp_buf_type = 0;
975 struct kvec iov[1];
977 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
978 if(tcon->ses->capabilities & CAP_LARGE_FILES)
979 wct = 12;
980 else
981 wct = 10; /* old style read */
983 *nbytes = 0;
984 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
985 if (rc)
986 return rc;
988 /* tcon and ses pointer are checked in smb_init */
989 if (tcon->ses->server == NULL)
990 return -ECONNABORTED;
992 pSMB->AndXCommand = 0xFF; /* none */
993 pSMB->Fid = netfid;
994 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
995 if(wct == 12)
996 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
997 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
998 return -EIO;
1000 pSMB->Remaining = 0;
1001 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1002 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1003 if(wct == 12)
1004 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1005 else {
1006 /* old style read */
1007 struct smb_com_readx_req * pSMBW =
1008 (struct smb_com_readx_req *)pSMB;
1009 pSMBW->ByteCount = 0;
1012 iov[0].iov_base = (char *)pSMB;
1013 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1014 rc = SendReceive2(xid, tcon->ses, iov,
1015 1 /* num iovecs */,
1016 &resp_buf_type, 0);
1017 cifs_stats_inc(&tcon->num_reads);
1018 pSMBr = (READ_RSP *)iov[0].iov_base;
1019 if (rc) {
1020 cERROR(1, ("Send error in read = %d", rc));
1021 } else {
1022 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1023 data_length = data_length << 16;
1024 data_length += le16_to_cpu(pSMBr->DataLength);
1025 *nbytes = data_length;
1027 /*check that DataLength would not go beyond end of SMB */
1028 if ((data_length > CIFSMaxBufSize)
1029 || (data_length > count)) {
1030 cFYI(1,("bad length %d for count %d",data_length,count));
1031 rc = -EIO;
1032 *nbytes = 0;
1033 } else {
1034 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1035 le16_to_cpu(pSMBr->DataOffset);
1036 /* if(rc = copy_to_user(buf, pReadData, data_length)) {
1037 cERROR(1,("Faulting on read rc = %d",rc));
1038 rc = -EFAULT;
1039 }*/ /* can not use copy_to_user when using page cache*/
1040 if(*buf)
1041 memcpy(*buf,pReadData,data_length);
1045 cifs_small_buf_release(pSMB);
1046 if(*buf) {
1047 if(resp_buf_type == CIFS_SMALL_BUFFER)
1048 cifs_small_buf_release(iov[0].iov_base);
1049 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1050 cifs_buf_release(iov[0].iov_base);
1051 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1052 /* return buffer to caller to free */
1053 *buf = iov[0].iov_base;
1054 if(resp_buf_type == CIFS_SMALL_BUFFER)
1055 *pbuf_type = CIFS_SMALL_BUFFER;
1056 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1057 *pbuf_type = CIFS_LARGE_BUFFER;
1058 } /* else no valid buffer on return - leave as null */
1060 /* Note: On -EAGAIN error only caller can retry on handle based calls
1061 since file handle passed in no longer valid */
1062 return rc;
1067 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1068 const int netfid, const unsigned int count,
1069 const __u64 offset, unsigned int *nbytes, const char *buf,
1070 const char __user * ubuf, const int long_op)
1072 int rc = -EACCES;
1073 WRITE_REQ *pSMB = NULL;
1074 WRITE_RSP *pSMBr = NULL;
1075 int bytes_returned, wct;
1076 __u32 bytes_sent;
1077 __u16 byte_count;
1079 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1080 if(tcon->ses == NULL)
1081 return -ECONNABORTED;
1083 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1084 wct = 14;
1085 else
1086 wct = 12;
1088 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1089 (void **) &pSMBr);
1090 if (rc)
1091 return rc;
1092 /* tcon and ses pointer are checked in smb_init */
1093 if (tcon->ses->server == NULL)
1094 return -ECONNABORTED;
1096 pSMB->AndXCommand = 0xFF; /* none */
1097 pSMB->Fid = netfid;
1098 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1099 if(wct == 14)
1100 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1101 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1102 return -EIO;
1104 pSMB->Reserved = 0xFFFFFFFF;
1105 pSMB->WriteMode = 0;
1106 pSMB->Remaining = 0;
1108 /* Can increase buffer size if buffer is big enough in some cases - ie we
1109 can send more if LARGE_WRITE_X capability returned by the server and if
1110 our buffer is big enough or if we convert to iovecs on socket writes
1111 and eliminate the copy to the CIFS buffer */
1112 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1113 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1114 } else {
1115 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1116 & ~0xFF;
1119 if (bytes_sent > count)
1120 bytes_sent = count;
1121 pSMB->DataOffset =
1122 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1123 if(buf)
1124 memcpy(pSMB->Data,buf,bytes_sent);
1125 else if(ubuf) {
1126 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1127 cifs_buf_release(pSMB);
1128 return -EFAULT;
1130 } else if (count != 0) {
1131 /* No buffer */
1132 cifs_buf_release(pSMB);
1133 return -EINVAL;
1134 } /* else setting file size with write of zero bytes */
1135 if(wct == 14)
1136 byte_count = bytes_sent + 1; /* pad */
1137 else /* wct == 12 */ {
1138 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1140 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1141 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1142 pSMB->hdr.smb_buf_length += byte_count;
1144 if(wct == 14)
1145 pSMB->ByteCount = cpu_to_le16(byte_count);
1146 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
1147 struct smb_com_writex_req * pSMBW =
1148 (struct smb_com_writex_req *)pSMB;
1149 pSMBW->ByteCount = cpu_to_le16(byte_count);
1152 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1153 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1154 cifs_stats_inc(&tcon->num_writes);
1155 if (rc) {
1156 cFYI(1, ("Send error in write = %d", rc));
1157 *nbytes = 0;
1158 } else {
1159 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1160 *nbytes = (*nbytes) << 16;
1161 *nbytes += le16_to_cpu(pSMBr->Count);
1164 cifs_buf_release(pSMB);
1166 /* Note: On -EAGAIN error only caller can retry on handle based calls
1167 since file handle passed in no longer valid */
1169 return rc;
1173 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1174 const int netfid, const unsigned int count,
1175 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1176 int n_vec, const int long_op)
1178 int rc = -EACCES;
1179 WRITE_REQ *pSMB = NULL;
1180 int wct;
1181 int smb_hdr_len;
1182 int resp_buf_type = 0;
1184 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1186 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1187 wct = 14;
1188 else
1189 wct = 12;
1190 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1191 if (rc)
1192 return rc;
1193 /* tcon and ses pointer are checked in smb_init */
1194 if (tcon->ses->server == NULL)
1195 return -ECONNABORTED;
1197 pSMB->AndXCommand = 0xFF; /* none */
1198 pSMB->Fid = netfid;
1199 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1200 if(wct == 14)
1201 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1202 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1203 return -EIO;
1204 pSMB->Reserved = 0xFFFFFFFF;
1205 pSMB->WriteMode = 0;
1206 pSMB->Remaining = 0;
1208 pSMB->DataOffset =
1209 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1211 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1212 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1213 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1214 if(wct == 14)
1215 pSMB->hdr.smb_buf_length += count+1;
1216 else /* wct == 12 */
1217 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1218 if(wct == 14)
1219 pSMB->ByteCount = cpu_to_le16(count + 1);
1220 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1221 struct smb_com_writex_req * pSMBW =
1222 (struct smb_com_writex_req *)pSMB;
1223 pSMBW->ByteCount = cpu_to_le16(count + 5);
1225 iov[0].iov_base = pSMB;
1226 if(wct == 14)
1227 iov[0].iov_len = smb_hdr_len + 4;
1228 else /* wct == 12 pad bigger by four bytes */
1229 iov[0].iov_len = smb_hdr_len + 8;
1232 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1233 long_op);
1234 cifs_stats_inc(&tcon->num_writes);
1235 if (rc) {
1236 cFYI(1, ("Send error Write2 = %d", rc));
1237 *nbytes = 0;
1238 } else if(resp_buf_type == 0) {
1239 /* presumably this can not happen, but best to be safe */
1240 rc = -EIO;
1241 *nbytes = 0;
1242 } else {
1243 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1244 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1245 *nbytes = (*nbytes) << 16;
1246 *nbytes += le16_to_cpu(pSMBr->Count);
1249 cifs_small_buf_release(pSMB);
1250 if(resp_buf_type == CIFS_SMALL_BUFFER)
1251 cifs_small_buf_release(iov[0].iov_base);
1252 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1253 cifs_buf_release(iov[0].iov_base);
1255 /* Note: On -EAGAIN error only caller can retry on handle based calls
1256 since file handle passed in no longer valid */
1258 return rc;
1263 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1264 const __u16 smb_file_id, const __u64 len,
1265 const __u64 offset, const __u32 numUnlock,
1266 const __u32 numLock, const __u8 lockType, const int waitFlag)
1268 int rc = 0;
1269 LOCK_REQ *pSMB = NULL;
1270 LOCK_RSP *pSMBr = NULL;
1271 int bytes_returned;
1272 int timeout = 0;
1273 __u16 count;
1275 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1276 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1278 if (rc)
1279 return rc;
1281 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1283 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1284 timeout = -1; /* no response expected */
1285 pSMB->Timeout = 0;
1286 } else if (waitFlag == TRUE) {
1287 timeout = 3; /* blocking operation, no timeout */
1288 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1289 } else {
1290 pSMB->Timeout = 0;
1293 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1294 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1295 pSMB->LockType = lockType;
1296 pSMB->AndXCommand = 0xFF; /* none */
1297 pSMB->Fid = smb_file_id; /* netfid stays le */
1299 if((numLock != 0) || (numUnlock != 0)) {
1300 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1301 /* BB where to store pid high? */
1302 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1303 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1304 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1305 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1306 count = sizeof(LOCKING_ANDX_RANGE);
1307 } else {
1308 /* oplock break */
1309 count = 0;
1311 pSMB->hdr.smb_buf_length += count;
1312 pSMB->ByteCount = cpu_to_le16(count);
1314 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1315 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1316 cifs_stats_inc(&tcon->num_locks);
1317 if (rc) {
1318 cFYI(1, ("Send error in Lock = %d", rc));
1320 cifs_small_buf_release(pSMB);
1322 /* Note: On -EAGAIN error only caller can retry on handle based calls
1323 since file handle passed in no longer valid */
1324 return rc;
1328 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1330 int rc = 0;
1331 CLOSE_REQ *pSMB = NULL;
1332 CLOSE_RSP *pSMBr = NULL;
1333 int bytes_returned;
1334 cFYI(1, ("In CIFSSMBClose"));
1336 /* do not retry on dead session on close */
1337 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1338 if(rc == -EAGAIN)
1339 return 0;
1340 if (rc)
1341 return rc;
1343 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1345 pSMB->FileID = (__u16) smb_file_id;
1346 pSMB->LastWriteTime = 0;
1347 pSMB->ByteCount = 0;
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1350 cifs_stats_inc(&tcon->num_closes);
1351 if (rc) {
1352 if(rc!=-EINTR) {
1353 /* EINTR is expected when user ctl-c to kill app */
1354 cERROR(1, ("Send error in Close = %d", rc));
1358 cifs_small_buf_release(pSMB);
1360 /* Since session is dead, file will be closed on server already */
1361 if(rc == -EAGAIN)
1362 rc = 0;
1364 return rc;
1368 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1369 const char *fromName, const char *toName,
1370 const struct nls_table *nls_codepage, int remap)
1372 int rc = 0;
1373 RENAME_REQ *pSMB = NULL;
1374 RENAME_RSP *pSMBr = NULL;
1375 int bytes_returned;
1376 int name_len, name_len2;
1377 __u16 count;
1379 cFYI(1, ("In CIFSSMBRename"));
1380 renameRetry:
1381 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1382 (void **) &pSMBr);
1383 if (rc)
1384 return rc;
1386 pSMB->BufferFormat = 0x04;
1387 pSMB->SearchAttributes =
1388 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1389 ATTR_DIRECTORY);
1391 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1392 name_len =
1393 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1394 PATH_MAX, nls_codepage, remap);
1395 name_len++; /* trailing null */
1396 name_len *= 2;
1397 pSMB->OldFileName[name_len] = 0x04; /* pad */
1398 /* protocol requires ASCII signature byte on Unicode string */
1399 pSMB->OldFileName[name_len + 1] = 0x00;
1400 name_len2 =
1401 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1402 toName, PATH_MAX, nls_codepage, remap);
1403 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1404 name_len2 *= 2; /* convert to bytes */
1405 } else { /* BB improve the check for buffer overruns BB */
1406 name_len = strnlen(fromName, PATH_MAX);
1407 name_len++; /* trailing null */
1408 strncpy(pSMB->OldFileName, fromName, name_len);
1409 name_len2 = strnlen(toName, PATH_MAX);
1410 name_len2++; /* trailing null */
1411 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1412 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1413 name_len2++; /* trailing null */
1414 name_len2++; /* signature byte */
1417 count = 1 /* 1st signature byte */ + name_len + name_len2;
1418 pSMB->hdr.smb_buf_length += count;
1419 pSMB->ByteCount = cpu_to_le16(count);
1421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1423 cifs_stats_inc(&tcon->num_renames);
1424 if (rc) {
1425 cFYI(1, ("Send error in rename = %d", rc));
1428 cifs_buf_release(pSMB);
1430 if (rc == -EAGAIN)
1431 goto renameRetry;
1433 return rc;
1436 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1437 int netfid, char * target_name,
1438 const struct nls_table * nls_codepage, int remap)
1440 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1441 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1442 struct set_file_rename * rename_info;
1443 char *data_offset;
1444 char dummy_string[30];
1445 int rc = 0;
1446 int bytes_returned = 0;
1447 int len_of_str;
1448 __u16 params, param_offset, offset, count, byte_count;
1450 cFYI(1, ("Rename to File by handle"));
1451 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1452 (void **) &pSMBr);
1453 if (rc)
1454 return rc;
1456 params = 6;
1457 pSMB->MaxSetupCount = 0;
1458 pSMB->Reserved = 0;
1459 pSMB->Flags = 0;
1460 pSMB->Timeout = 0;
1461 pSMB->Reserved2 = 0;
1462 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1463 offset = param_offset + params;
1465 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1466 rename_info = (struct set_file_rename *) data_offset;
1467 pSMB->MaxParameterCount = cpu_to_le16(2);
1468 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1469 pSMB->SetupCount = 1;
1470 pSMB->Reserved3 = 0;
1471 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1472 byte_count = 3 /* pad */ + params;
1473 pSMB->ParameterCount = cpu_to_le16(params);
1474 pSMB->TotalParameterCount = pSMB->ParameterCount;
1475 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1476 pSMB->DataOffset = cpu_to_le16(offset);
1477 /* construct random name ".cifs_tmp<inodenum><mid>" */
1478 rename_info->overwrite = cpu_to_le32(1);
1479 rename_info->root_fid = 0;
1480 /* unicode only call */
1481 if(target_name == NULL) {
1482 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1483 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1484 dummy_string, 24, nls_codepage, remap);
1485 } else {
1486 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1487 target_name, PATH_MAX, nls_codepage, remap);
1489 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1490 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1491 byte_count += count;
1492 pSMB->DataCount = cpu_to_le16(count);
1493 pSMB->TotalDataCount = pSMB->DataCount;
1494 pSMB->Fid = netfid;
1495 pSMB->InformationLevel =
1496 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1497 pSMB->Reserved4 = 0;
1498 pSMB->hdr.smb_buf_length += byte_count;
1499 pSMB->ByteCount = cpu_to_le16(byte_count);
1500 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1501 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1502 cifs_stats_inc(&pTcon->num_t2renames);
1503 if (rc) {
1504 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1507 cifs_buf_release(pSMB);
1509 /* Note: On -EAGAIN error only caller can retry on handle based calls
1510 since file handle passed in no longer valid */
1512 return rc;
1516 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1517 const __u16 target_tid, const char *toName, const int flags,
1518 const struct nls_table *nls_codepage, int remap)
1520 int rc = 0;
1521 COPY_REQ *pSMB = NULL;
1522 COPY_RSP *pSMBr = NULL;
1523 int bytes_returned;
1524 int name_len, name_len2;
1525 __u16 count;
1527 cFYI(1, ("In CIFSSMBCopy"));
1528 copyRetry:
1529 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1530 (void **) &pSMBr);
1531 if (rc)
1532 return rc;
1534 pSMB->BufferFormat = 0x04;
1535 pSMB->Tid2 = target_tid;
1537 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1539 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1540 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1541 fromName, PATH_MAX, nls_codepage,
1542 remap);
1543 name_len++; /* trailing null */
1544 name_len *= 2;
1545 pSMB->OldFileName[name_len] = 0x04; /* pad */
1546 /* protocol requires ASCII signature byte on Unicode string */
1547 pSMB->OldFileName[name_len + 1] = 0x00;
1548 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1549 toName, PATH_MAX, nls_codepage, remap);
1550 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1551 name_len2 *= 2; /* convert to bytes */
1552 } else { /* BB improve the check for buffer overruns BB */
1553 name_len = strnlen(fromName, PATH_MAX);
1554 name_len++; /* trailing null */
1555 strncpy(pSMB->OldFileName, fromName, name_len);
1556 name_len2 = strnlen(toName, PATH_MAX);
1557 name_len2++; /* trailing null */
1558 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1559 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1560 name_len2++; /* trailing null */
1561 name_len2++; /* signature byte */
1564 count = 1 /* 1st signature byte */ + name_len + name_len2;
1565 pSMB->hdr.smb_buf_length += count;
1566 pSMB->ByteCount = cpu_to_le16(count);
1568 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1569 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1570 if (rc) {
1571 cFYI(1, ("Send error in copy = %d with %d files copied",
1572 rc, le16_to_cpu(pSMBr->CopyCount)));
1574 if (pSMB)
1575 cifs_buf_release(pSMB);
1577 if (rc == -EAGAIN)
1578 goto copyRetry;
1580 return rc;
1584 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1585 const char *fromName, const char *toName,
1586 const struct nls_table *nls_codepage)
1588 TRANSACTION2_SPI_REQ *pSMB = NULL;
1589 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1590 char *data_offset;
1591 int name_len;
1592 int name_len_target;
1593 int rc = 0;
1594 int bytes_returned = 0;
1595 __u16 params, param_offset, offset, byte_count;
1597 cFYI(1, ("In Symlink Unix style"));
1598 createSymLinkRetry:
1599 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1600 (void **) &pSMBr);
1601 if (rc)
1602 return rc;
1604 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1605 name_len =
1606 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1607 /* find define for this maxpathcomponent */
1608 , nls_codepage);
1609 name_len++; /* trailing null */
1610 name_len *= 2;
1612 } else { /* BB improve the check for buffer overruns BB */
1613 name_len = strnlen(fromName, PATH_MAX);
1614 name_len++; /* trailing null */
1615 strncpy(pSMB->FileName, fromName, name_len);
1617 params = 6 + name_len;
1618 pSMB->MaxSetupCount = 0;
1619 pSMB->Reserved = 0;
1620 pSMB->Flags = 0;
1621 pSMB->Timeout = 0;
1622 pSMB->Reserved2 = 0;
1623 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1624 InformationLevel) - 4;
1625 offset = param_offset + params;
1627 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1628 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1629 name_len_target =
1630 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1631 /* find define for this maxpathcomponent */
1632 , nls_codepage);
1633 name_len_target++; /* trailing null */
1634 name_len_target *= 2;
1635 } else { /* BB improve the check for buffer overruns BB */
1636 name_len_target = strnlen(toName, PATH_MAX);
1637 name_len_target++; /* trailing null */
1638 strncpy(data_offset, toName, name_len_target);
1641 pSMB->MaxParameterCount = cpu_to_le16(2);
1642 /* BB find exact max on data count below from sess */
1643 pSMB->MaxDataCount = cpu_to_le16(1000);
1644 pSMB->SetupCount = 1;
1645 pSMB->Reserved3 = 0;
1646 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1647 byte_count = 3 /* pad */ + params + name_len_target;
1648 pSMB->DataCount = cpu_to_le16(name_len_target);
1649 pSMB->ParameterCount = cpu_to_le16(params);
1650 pSMB->TotalDataCount = pSMB->DataCount;
1651 pSMB->TotalParameterCount = pSMB->ParameterCount;
1652 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1653 pSMB->DataOffset = cpu_to_le16(offset);
1654 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1655 pSMB->Reserved4 = 0;
1656 pSMB->hdr.smb_buf_length += byte_count;
1657 pSMB->ByteCount = cpu_to_le16(byte_count);
1658 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1659 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1660 cifs_stats_inc(&tcon->num_symlinks);
1661 if (rc) {
1662 cFYI(1,
1663 ("Send error in SetPathInfo (create symlink) = %d",
1664 rc));
1667 if (pSMB)
1668 cifs_buf_release(pSMB);
1670 if (rc == -EAGAIN)
1671 goto createSymLinkRetry;
1673 return rc;
1677 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1678 const char *fromName, const char *toName,
1679 const struct nls_table *nls_codepage, int remap)
1681 TRANSACTION2_SPI_REQ *pSMB = NULL;
1682 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1683 char *data_offset;
1684 int name_len;
1685 int name_len_target;
1686 int rc = 0;
1687 int bytes_returned = 0;
1688 __u16 params, param_offset, offset, byte_count;
1690 cFYI(1, ("In Create Hard link Unix style"));
1691 createHardLinkRetry:
1692 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1693 (void **) &pSMBr);
1694 if (rc)
1695 return rc;
1697 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1698 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1699 PATH_MAX, nls_codepage, remap);
1700 name_len++; /* trailing null */
1701 name_len *= 2;
1703 } else { /* BB improve the check for buffer overruns BB */
1704 name_len = strnlen(toName, PATH_MAX);
1705 name_len++; /* trailing null */
1706 strncpy(pSMB->FileName, toName, name_len);
1708 params = 6 + name_len;
1709 pSMB->MaxSetupCount = 0;
1710 pSMB->Reserved = 0;
1711 pSMB->Flags = 0;
1712 pSMB->Timeout = 0;
1713 pSMB->Reserved2 = 0;
1714 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1715 InformationLevel) - 4;
1716 offset = param_offset + params;
1718 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1719 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1720 name_len_target =
1721 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1722 nls_codepage, remap);
1723 name_len_target++; /* trailing null */
1724 name_len_target *= 2;
1725 } else { /* BB improve the check for buffer overruns BB */
1726 name_len_target = strnlen(fromName, PATH_MAX);
1727 name_len_target++; /* trailing null */
1728 strncpy(data_offset, fromName, name_len_target);
1731 pSMB->MaxParameterCount = cpu_to_le16(2);
1732 /* BB find exact max on data count below from sess*/
1733 pSMB->MaxDataCount = cpu_to_le16(1000);
1734 pSMB->SetupCount = 1;
1735 pSMB->Reserved3 = 0;
1736 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1737 byte_count = 3 /* pad */ + params + name_len_target;
1738 pSMB->ParameterCount = cpu_to_le16(params);
1739 pSMB->TotalParameterCount = pSMB->ParameterCount;
1740 pSMB->DataCount = cpu_to_le16(name_len_target);
1741 pSMB->TotalDataCount = pSMB->DataCount;
1742 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1743 pSMB->DataOffset = cpu_to_le16(offset);
1744 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1745 pSMB->Reserved4 = 0;
1746 pSMB->hdr.smb_buf_length += byte_count;
1747 pSMB->ByteCount = cpu_to_le16(byte_count);
1748 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1749 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1750 cifs_stats_inc(&tcon->num_hardlinks);
1751 if (rc) {
1752 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1755 cifs_buf_release(pSMB);
1756 if (rc == -EAGAIN)
1757 goto createHardLinkRetry;
1759 return rc;
1763 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1764 const char *fromName, const char *toName,
1765 const struct nls_table *nls_codepage, int remap)
1767 int rc = 0;
1768 NT_RENAME_REQ *pSMB = NULL;
1769 RENAME_RSP *pSMBr = NULL;
1770 int bytes_returned;
1771 int name_len, name_len2;
1772 __u16 count;
1774 cFYI(1, ("In CIFSCreateHardLink"));
1775 winCreateHardLinkRetry:
1777 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1778 (void **) &pSMBr);
1779 if (rc)
1780 return rc;
1782 pSMB->SearchAttributes =
1783 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1784 ATTR_DIRECTORY);
1785 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1786 pSMB->ClusterCount = 0;
1788 pSMB->BufferFormat = 0x04;
1790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1791 name_len =
1792 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1793 PATH_MAX, nls_codepage, remap);
1794 name_len++; /* trailing null */
1795 name_len *= 2;
1796 pSMB->OldFileName[name_len] = 0; /* pad */
1797 pSMB->OldFileName[name_len + 1] = 0x04;
1798 name_len2 =
1799 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1800 toName, PATH_MAX, nls_codepage, remap);
1801 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1802 name_len2 *= 2; /* convert to bytes */
1803 } else { /* BB improve the check for buffer overruns BB */
1804 name_len = strnlen(fromName, PATH_MAX);
1805 name_len++; /* trailing null */
1806 strncpy(pSMB->OldFileName, fromName, name_len);
1807 name_len2 = strnlen(toName, PATH_MAX);
1808 name_len2++; /* trailing null */
1809 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1810 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1811 name_len2++; /* trailing null */
1812 name_len2++; /* signature byte */
1815 count = 1 /* string type byte */ + name_len + name_len2;
1816 pSMB->hdr.smb_buf_length += count;
1817 pSMB->ByteCount = cpu_to_le16(count);
1819 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1820 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1821 cifs_stats_inc(&tcon->num_hardlinks);
1822 if (rc) {
1823 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1825 cifs_buf_release(pSMB);
1826 if (rc == -EAGAIN)
1827 goto winCreateHardLinkRetry;
1829 return rc;
1833 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1834 const unsigned char *searchName,
1835 char *symlinkinfo, const int buflen,
1836 const struct nls_table *nls_codepage)
1838 /* SMB_QUERY_FILE_UNIX_LINK */
1839 TRANSACTION2_QPI_REQ *pSMB = NULL;
1840 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1841 int rc = 0;
1842 int bytes_returned;
1843 int name_len;
1844 __u16 params, byte_count;
1846 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1848 querySymLinkRetry:
1849 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1850 (void **) &pSMBr);
1851 if (rc)
1852 return rc;
1854 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1855 name_len =
1856 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1857 /* find define for this maxpathcomponent */
1858 , nls_codepage);
1859 name_len++; /* trailing null */
1860 name_len *= 2;
1861 } else { /* BB improve the check for buffer overruns BB */
1862 name_len = strnlen(searchName, PATH_MAX);
1863 name_len++; /* trailing null */
1864 strncpy(pSMB->FileName, searchName, name_len);
1867 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1868 pSMB->TotalDataCount = 0;
1869 pSMB->MaxParameterCount = cpu_to_le16(2);
1870 /* BB find exact max data count below from sess structure BB */
1871 pSMB->MaxDataCount = cpu_to_le16(4000);
1872 pSMB->MaxSetupCount = 0;
1873 pSMB->Reserved = 0;
1874 pSMB->Flags = 0;
1875 pSMB->Timeout = 0;
1876 pSMB->Reserved2 = 0;
1877 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1878 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1879 pSMB->DataCount = 0;
1880 pSMB->DataOffset = 0;
1881 pSMB->SetupCount = 1;
1882 pSMB->Reserved3 = 0;
1883 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1884 byte_count = params + 1 /* pad */ ;
1885 pSMB->TotalParameterCount = cpu_to_le16(params);
1886 pSMB->ParameterCount = pSMB->TotalParameterCount;
1887 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1888 pSMB->Reserved4 = 0;
1889 pSMB->hdr.smb_buf_length += byte_count;
1890 pSMB->ByteCount = cpu_to_le16(byte_count);
1892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1894 if (rc) {
1895 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1896 } else {
1897 /* decode response */
1899 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1900 if (rc || (pSMBr->ByteCount < 2))
1901 /* BB also check enough total bytes returned */
1902 rc = -EIO; /* bad smb */
1903 else {
1904 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1905 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1907 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1908 name_len = UniStrnlen((wchar_t *) ((char *)
1909 &pSMBr->hdr.Protocol +data_offset),
1910 min_t(const int, buflen,count) / 2);
1911 /* BB FIXME investigate remapping reserved chars here */
1912 cifs_strfromUCS_le(symlinkinfo,
1913 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
1914 data_offset),
1915 name_len, nls_codepage);
1916 } else {
1917 strncpy(symlinkinfo,
1918 (char *) &pSMBr->hdr.Protocol +
1919 data_offset,
1920 min_t(const int, buflen, count));
1922 symlinkinfo[buflen] = 0;
1923 /* just in case so calling code does not go off the end of buffer */
1926 cifs_buf_release(pSMB);
1927 if (rc == -EAGAIN)
1928 goto querySymLinkRetry;
1929 return rc;
1932 /* Initialize NT TRANSACT SMB into small smb request buffer.
1933 This assumes that all NT TRANSACTS that we init here have
1934 total parm and data under about 400 bytes (to fit in small cifs
1935 buffer size), which is the case so far, it easily fits. NB:
1936 Setup words themselves and ByteCount
1937 MaxSetupCount (size of returned setup area) and
1938 MaxParameterCount (returned parms size) must be set by caller */
1939 static int
1940 smb_init_ntransact(const __u16 sub_command, const int setup_count,
1941 const int parm_len, struct cifsTconInfo *tcon,
1942 void ** ret_buf)
1944 int rc;
1945 __u32 temp_offset;
1946 struct smb_com_ntransact_req * pSMB;
1948 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1949 (void **)&pSMB);
1950 if (rc)
1951 return rc;
1952 *ret_buf = (void *)pSMB;
1953 pSMB->Reserved = 0;
1954 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1955 pSMB->TotalDataCount = 0;
1956 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1957 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1958 pSMB->ParameterCount = pSMB->TotalParameterCount;
1959 pSMB->DataCount = pSMB->TotalDataCount;
1960 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1961 (setup_count * 2) - 4 /* for rfc1001 length itself */;
1962 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1963 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1964 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1965 pSMB->SubCommand = cpu_to_le16(sub_command);
1966 return 0;
1969 static int
1970 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1971 int * pdatalen, int * pparmlen)
1973 char * end_of_smb;
1974 __u32 data_count, data_offset, parm_count, parm_offset;
1975 struct smb_com_ntransact_rsp * pSMBr;
1977 if(buf == NULL)
1978 return -EINVAL;
1980 pSMBr = (struct smb_com_ntransact_rsp *)buf;
1982 /* ByteCount was converted from little endian in SendReceive */
1983 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
1984 (char *)&pSMBr->ByteCount;
1987 data_offset = le32_to_cpu(pSMBr->DataOffset);
1988 data_count = le32_to_cpu(pSMBr->DataCount);
1989 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
1990 parm_count = le32_to_cpu(pSMBr->ParameterCount);
1992 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
1993 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
1995 /* should we also check that parm and data areas do not overlap? */
1996 if(*ppparm > end_of_smb) {
1997 cFYI(1,("parms start after end of smb"));
1998 return -EINVAL;
1999 } else if(parm_count + *ppparm > end_of_smb) {
2000 cFYI(1,("parm end after end of smb"));
2001 return -EINVAL;
2002 } else if(*ppdata > end_of_smb) {
2003 cFYI(1,("data starts after end of smb"));
2004 return -EINVAL;
2005 } else if(data_count + *ppdata > end_of_smb) {
2006 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2007 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2008 return -EINVAL;
2009 } else if(parm_count + data_count > pSMBr->ByteCount) {
2010 cFYI(1,("parm count and data count larger than SMB"));
2011 return -EINVAL;
2013 return 0;
2017 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2018 const unsigned char *searchName,
2019 char *symlinkinfo, const int buflen,__u16 fid,
2020 const struct nls_table *nls_codepage)
2022 int rc = 0;
2023 int bytes_returned;
2024 int name_len;
2025 struct smb_com_transaction_ioctl_req * pSMB;
2026 struct smb_com_transaction_ioctl_rsp * pSMBr;
2028 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2029 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2030 (void **) &pSMBr);
2031 if (rc)
2032 return rc;
2034 pSMB->TotalParameterCount = 0 ;
2035 pSMB->TotalDataCount = 0;
2036 pSMB->MaxParameterCount = cpu_to_le32(2);
2037 /* BB find exact data count max from sess structure BB */
2038 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2039 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2040 pSMB->MaxSetupCount = 4;
2041 pSMB->Reserved = 0;
2042 pSMB->ParameterOffset = 0;
2043 pSMB->DataCount = 0;
2044 pSMB->DataOffset = 0;
2045 pSMB->SetupCount = 4;
2046 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2047 pSMB->ParameterCount = pSMB->TotalParameterCount;
2048 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2049 pSMB->IsFsctl = 1; /* FSCTL */
2050 pSMB->IsRootFlag = 0;
2051 pSMB->Fid = fid; /* file handle always le */
2052 pSMB->ByteCount = 0;
2054 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2056 if (rc) {
2057 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2058 } else { /* decode response */
2059 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2060 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2061 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2062 /* BB also check enough total bytes returned */
2063 rc = -EIO; /* bad smb */
2064 else {
2065 if(data_count && (data_count < 2048)) {
2066 char * end_of_smb = 2 /* sizeof byte count */ +
2067 pSMBr->ByteCount +
2068 (char *)&pSMBr->ByteCount;
2070 struct reparse_data * reparse_buf = (struct reparse_data *)
2071 ((char *)&pSMBr->hdr.Protocol + data_offset);
2072 if((char*)reparse_buf >= end_of_smb) {
2073 rc = -EIO;
2074 goto qreparse_out;
2076 if((reparse_buf->LinkNamesBuf +
2077 reparse_buf->TargetNameOffset +
2078 reparse_buf->TargetNameLen) >
2079 end_of_smb) {
2080 cFYI(1,("reparse buf extended beyond SMB"));
2081 rc = -EIO;
2082 goto qreparse_out;
2085 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2086 name_len = UniStrnlen((wchar_t *)
2087 (reparse_buf->LinkNamesBuf +
2088 reparse_buf->TargetNameOffset),
2089 min(buflen/2, reparse_buf->TargetNameLen / 2));
2090 cifs_strfromUCS_le(symlinkinfo,
2091 (__le16 *) (reparse_buf->LinkNamesBuf +
2092 reparse_buf->TargetNameOffset),
2093 name_len, nls_codepage);
2094 } else { /* ASCII names */
2095 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2096 reparse_buf->TargetNameOffset,
2097 min_t(const int, buflen, reparse_buf->TargetNameLen));
2099 } else {
2100 rc = -EIO;
2101 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2103 symlinkinfo[buflen] = 0; /* just in case so the caller
2104 does not go off the end of the buffer */
2105 cFYI(1,("readlink result - %s ",symlinkinfo));
2108 qreparse_out:
2109 cifs_buf_release(pSMB);
2111 /* Note: On -EAGAIN error only caller can retry on handle based calls
2112 since file handle passed in no longer valid */
2114 return rc;
2117 #ifdef CONFIG_CIFS_POSIX
2119 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2120 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2122 /* u8 cifs fields do not need le conversion */
2123 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2124 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2125 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2126 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2128 return;
2131 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2132 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2133 const int acl_type,const int size_of_data_area)
2135 int size = 0;
2136 int i;
2137 __u16 count;
2138 struct cifs_posix_ace * pACE;
2139 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2140 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2142 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2143 return -EOPNOTSUPP;
2145 if(acl_type & ACL_TYPE_ACCESS) {
2146 count = le16_to_cpu(cifs_acl->access_entry_count);
2147 pACE = &cifs_acl->ace_array[0];
2148 size = sizeof(struct cifs_posix_acl);
2149 size += sizeof(struct cifs_posix_ace) * count;
2150 /* check if we would go beyond end of SMB */
2151 if(size_of_data_area < size) {
2152 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2153 return -EINVAL;
2155 } else if(acl_type & ACL_TYPE_DEFAULT) {
2156 count = le16_to_cpu(cifs_acl->access_entry_count);
2157 size = sizeof(struct cifs_posix_acl);
2158 size += sizeof(struct cifs_posix_ace) * count;
2159 /* skip past access ACEs to get to default ACEs */
2160 pACE = &cifs_acl->ace_array[count];
2161 count = le16_to_cpu(cifs_acl->default_entry_count);
2162 size += sizeof(struct cifs_posix_ace) * count;
2163 /* check if we would go beyond end of SMB */
2164 if(size_of_data_area < size)
2165 return -EINVAL;
2166 } else {
2167 /* illegal type */
2168 return -EINVAL;
2171 size = posix_acl_xattr_size(count);
2172 if((buflen == 0) || (local_acl == NULL)) {
2173 /* used to query ACL EA size */
2174 } else if(size > buflen) {
2175 return -ERANGE;
2176 } else /* buffer big enough */ {
2177 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2178 for(i = 0;i < count ;i++) {
2179 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2180 pACE ++;
2183 return size;
2186 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2187 const posix_acl_xattr_entry * local_ace)
2189 __u16 rc = 0; /* 0 = ACL converted ok */
2191 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2192 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2193 /* BB is there a better way to handle the large uid? */
2194 if(local_ace->e_id == cpu_to_le32(-1)) {
2195 /* Probably no need to le convert -1 on any arch but can not hurt */
2196 cifs_ace->cifs_uid = cpu_to_le64(-1);
2197 } else
2198 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2199 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2200 return rc;
2203 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2204 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2205 const int acl_type)
2207 __u16 rc = 0;
2208 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2209 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2210 int count;
2211 int i;
2213 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2214 return 0;
2216 count = posix_acl_xattr_count((size_t)buflen);
2217 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2218 count, buflen, le32_to_cpu(local_acl->a_version)));
2219 if(le32_to_cpu(local_acl->a_version) != 2) {
2220 cFYI(1,("unknown POSIX ACL version %d",
2221 le32_to_cpu(local_acl->a_version)));
2222 return 0;
2224 cifs_acl->version = cpu_to_le16(1);
2225 if(acl_type == ACL_TYPE_ACCESS)
2226 cifs_acl->access_entry_count = cpu_to_le16(count);
2227 else if(acl_type == ACL_TYPE_DEFAULT)
2228 cifs_acl->default_entry_count = cpu_to_le16(count);
2229 else {
2230 cFYI(1,("unknown ACL type %d",acl_type));
2231 return 0;
2233 for(i=0;i<count;i++) {
2234 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2235 &local_acl->a_entries[i]);
2236 if(rc != 0) {
2237 /* ACE not converted */
2238 break;
2241 if(rc == 0) {
2242 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2243 rc += sizeof(struct cifs_posix_acl);
2244 /* BB add check to make sure ACL does not overflow SMB */
2246 return rc;
2250 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2251 const unsigned char *searchName,
2252 char *acl_inf, const int buflen, const int acl_type,
2253 const struct nls_table *nls_codepage, int remap)
2255 /* SMB_QUERY_POSIX_ACL */
2256 TRANSACTION2_QPI_REQ *pSMB = NULL;
2257 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2258 int rc = 0;
2259 int bytes_returned;
2260 int name_len;
2261 __u16 params, byte_count;
2263 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2265 queryAclRetry:
2266 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2267 (void **) &pSMBr);
2268 if (rc)
2269 return rc;
2271 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2272 name_len =
2273 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2274 PATH_MAX, nls_codepage, remap);
2275 name_len++; /* trailing null */
2276 name_len *= 2;
2277 pSMB->FileName[name_len] = 0;
2278 pSMB->FileName[name_len+1] = 0;
2279 } else { /* BB improve the check for buffer overruns BB */
2280 name_len = strnlen(searchName, PATH_MAX);
2281 name_len++; /* trailing null */
2282 strncpy(pSMB->FileName, searchName, name_len);
2285 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2286 pSMB->TotalDataCount = 0;
2287 pSMB->MaxParameterCount = cpu_to_le16(2);
2288 /* BB find exact max data count below from sess structure BB */
2289 pSMB->MaxDataCount = cpu_to_le16(4000);
2290 pSMB->MaxSetupCount = 0;
2291 pSMB->Reserved = 0;
2292 pSMB->Flags = 0;
2293 pSMB->Timeout = 0;
2294 pSMB->Reserved2 = 0;
2295 pSMB->ParameterOffset = cpu_to_le16(
2296 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2297 pSMB->DataCount = 0;
2298 pSMB->DataOffset = 0;
2299 pSMB->SetupCount = 1;
2300 pSMB->Reserved3 = 0;
2301 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2302 byte_count = params + 1 /* pad */ ;
2303 pSMB->TotalParameterCount = cpu_to_le16(params);
2304 pSMB->ParameterCount = pSMB->TotalParameterCount;
2305 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2306 pSMB->Reserved4 = 0;
2307 pSMB->hdr.smb_buf_length += byte_count;
2308 pSMB->ByteCount = cpu_to_le16(byte_count);
2310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2312 cifs_stats_inc(&tcon->num_acl_get);
2313 if (rc) {
2314 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2315 } else {
2316 /* decode response */
2318 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2319 if (rc || (pSMBr->ByteCount < 2))
2320 /* BB also check enough total bytes returned */
2321 rc = -EIO; /* bad smb */
2322 else {
2323 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2324 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2325 rc = cifs_copy_posix_acl(acl_inf,
2326 (char *)&pSMBr->hdr.Protocol+data_offset,
2327 buflen,acl_type,count);
2330 cifs_buf_release(pSMB);
2331 if (rc == -EAGAIN)
2332 goto queryAclRetry;
2333 return rc;
2337 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2338 const unsigned char *fileName,
2339 const char *local_acl, const int buflen,
2340 const int acl_type,
2341 const struct nls_table *nls_codepage, int remap)
2343 struct smb_com_transaction2_spi_req *pSMB = NULL;
2344 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2345 char *parm_data;
2346 int name_len;
2347 int rc = 0;
2348 int bytes_returned = 0;
2349 __u16 params, byte_count, data_count, param_offset, offset;
2351 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2352 setAclRetry:
2353 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2354 (void **) &pSMBr);
2355 if (rc)
2356 return rc;
2357 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2358 name_len =
2359 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2360 PATH_MAX, nls_codepage, remap);
2361 name_len++; /* trailing null */
2362 name_len *= 2;
2363 } else { /* BB improve the check for buffer overruns BB */
2364 name_len = strnlen(fileName, PATH_MAX);
2365 name_len++; /* trailing null */
2366 strncpy(pSMB->FileName, fileName, name_len);
2368 params = 6 + name_len;
2369 pSMB->MaxParameterCount = cpu_to_le16(2);
2370 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2371 pSMB->MaxSetupCount = 0;
2372 pSMB->Reserved = 0;
2373 pSMB->Flags = 0;
2374 pSMB->Timeout = 0;
2375 pSMB->Reserved2 = 0;
2376 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2377 InformationLevel) - 4;
2378 offset = param_offset + params;
2379 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2380 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2382 /* convert to on the wire format for POSIX ACL */
2383 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2385 if(data_count == 0) {
2386 rc = -EOPNOTSUPP;
2387 goto setACLerrorExit;
2389 pSMB->DataOffset = cpu_to_le16(offset);
2390 pSMB->SetupCount = 1;
2391 pSMB->Reserved3 = 0;
2392 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2393 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2394 byte_count = 3 /* pad */ + params + data_count;
2395 pSMB->DataCount = cpu_to_le16(data_count);
2396 pSMB->TotalDataCount = pSMB->DataCount;
2397 pSMB->ParameterCount = cpu_to_le16(params);
2398 pSMB->TotalParameterCount = pSMB->ParameterCount;
2399 pSMB->Reserved4 = 0;
2400 pSMB->hdr.smb_buf_length += byte_count;
2401 pSMB->ByteCount = cpu_to_le16(byte_count);
2402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2404 if (rc) {
2405 cFYI(1, ("Set POSIX ACL returned %d", rc));
2408 setACLerrorExit:
2409 cifs_buf_release(pSMB);
2410 if (rc == -EAGAIN)
2411 goto setAclRetry;
2412 return rc;
2415 /* BB fix tabs in this function FIXME BB */
2417 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2418 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2420 int rc = 0;
2421 struct smb_t2_qfi_req *pSMB = NULL;
2422 struct smb_t2_qfi_rsp *pSMBr = NULL;
2423 int bytes_returned;
2424 __u16 params, byte_count;
2426 cFYI(1,("In GetExtAttr"));
2427 if(tcon == NULL)
2428 return -ENODEV;
2430 GetExtAttrRetry:
2431 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2432 (void **) &pSMBr);
2433 if (rc)
2434 return rc;
2436 params = 2 /* level */ +2 /* fid */;
2437 pSMB->t2.TotalDataCount = 0;
2438 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2439 /* BB find exact max data count below from sess structure BB */
2440 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2441 pSMB->t2.MaxSetupCount = 0;
2442 pSMB->t2.Reserved = 0;
2443 pSMB->t2.Flags = 0;
2444 pSMB->t2.Timeout = 0;
2445 pSMB->t2.Reserved2 = 0;
2446 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2447 Fid) - 4);
2448 pSMB->t2.DataCount = 0;
2449 pSMB->t2.DataOffset = 0;
2450 pSMB->t2.SetupCount = 1;
2451 pSMB->t2.Reserved3 = 0;
2452 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2453 byte_count = params + 1 /* pad */ ;
2454 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2455 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2456 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2457 pSMB->Pad = 0;
2458 pSMB->Fid = netfid;
2459 pSMB->hdr.smb_buf_length += byte_count;
2460 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2464 if (rc) {
2465 cFYI(1, ("error %d in GetExtAttr", rc));
2466 } else {
2467 /* decode response */
2468 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2469 if (rc || (pSMBr->ByteCount < 2))
2470 /* BB also check enough total bytes returned */
2471 /* If rc should we check for EOPNOSUPP and
2472 disable the srvino flag? or in caller? */
2473 rc = -EIO; /* bad smb */
2474 else {
2475 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2476 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2477 struct file_chattr_info * pfinfo;
2478 /* BB Do we need a cast or hash here ? */
2479 if(count != 16) {
2480 cFYI(1, ("Illegal size ret in GetExtAttr"));
2481 rc = -EIO;
2482 goto GetExtAttrOut;
2484 pfinfo = (struct file_chattr_info *)
2485 (data_offset + (char *) &pSMBr->hdr.Protocol);
2486 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2487 *pMask = le64_to_cpu(pfinfo->mask);
2490 GetExtAttrOut:
2491 cifs_buf_release(pSMB);
2492 if (rc == -EAGAIN)
2493 goto GetExtAttrRetry;
2494 return rc;
2498 #endif /* CONFIG_POSIX */
2501 /* security id for everyone */
2502 const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2503 /* group users */
2504 const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2506 /* Convert CIFS ACL to POSIX form */
2507 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2509 return 0;
2512 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2514 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2515 /* BB fix up return info */ char *acl_inf, const int buflen,
2516 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2518 int rc = 0;
2519 int buf_type = 0;
2520 QUERY_SEC_DESC_REQ * pSMB;
2521 struct kvec iov[1];
2523 cFYI(1, ("GetCifsACL"));
2525 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2526 8 /* parm len */, tcon, (void **) &pSMB);
2527 if (rc)
2528 return rc;
2530 pSMB->MaxParameterCount = cpu_to_le32(4);
2531 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2532 pSMB->MaxSetupCount = 0;
2533 pSMB->Fid = fid; /* file handle always le */
2534 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2535 CIFS_ACL_DACL);
2536 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2537 pSMB->hdr.smb_buf_length += 11;
2538 iov[0].iov_base = (char *)pSMB;
2539 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2541 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2542 cifs_stats_inc(&tcon->num_acl_get);
2543 if (rc) {
2544 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2545 } else { /* decode response */
2546 struct cifs_sid * psec_desc;
2547 __le32 * parm;
2548 int parm_len;
2549 int data_len;
2550 int acl_len;
2551 struct smb_com_ntransact_rsp * pSMBr;
2553 /* validate_nttransact */
2554 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2555 (char **)&psec_desc,
2556 &parm_len, &data_len);
2558 if(rc)
2559 goto qsec_out;
2560 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2562 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2564 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2565 rc = -EIO; /* bad smb */
2566 goto qsec_out;
2569 /* BB check that data area is minimum length and as big as acl_len */
2571 acl_len = le32_to_cpu(*(__le32 *)parm);
2572 /* BB check if(acl_len > bufsize) */
2574 parse_sec_desc(psec_desc, acl_len);
2576 qsec_out:
2577 if(buf_type == CIFS_SMALL_BUFFER)
2578 cifs_small_buf_release(iov[0].iov_base);
2579 else if(buf_type == CIFS_LARGE_BUFFER)
2580 cifs_buf_release(iov[0].iov_base);
2581 cifs_small_buf_release(pSMB);
2582 return rc;
2586 /* Legacy Query Path Information call for lookup to old servers such
2587 as Win9x/WinME */
2588 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2589 const unsigned char *searchName,
2590 FILE_ALL_INFO * pFinfo,
2591 const struct nls_table *nls_codepage, int remap)
2593 QUERY_INFORMATION_REQ * pSMB;
2594 QUERY_INFORMATION_RSP * pSMBr;
2595 int rc = 0;
2596 int bytes_returned;
2597 int name_len;
2599 cFYI(1, ("In SMBQPath path %s", searchName));
2600 QInfRetry:
2601 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2602 (void **) &pSMBr);
2603 if (rc)
2604 return rc;
2606 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2607 name_len =
2608 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2609 PATH_MAX, nls_codepage, remap);
2610 name_len++; /* trailing null */
2611 name_len *= 2;
2612 } else {
2613 name_len = strnlen(searchName, PATH_MAX);
2614 name_len++; /* trailing null */
2615 strncpy(pSMB->FileName, searchName, name_len);
2617 pSMB->BufferFormat = 0x04;
2618 name_len++; /* account for buffer type byte */
2619 pSMB->hdr.smb_buf_length += (__u16) name_len;
2620 pSMB->ByteCount = cpu_to_le16(name_len);
2622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2623 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2624 if (rc) {
2625 cFYI(1, ("Send error in QueryInfo = %d", rc));
2626 } else if (pFinfo) { /* decode response */
2627 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2628 pFinfo->AllocationSize =
2629 cpu_to_le64(le32_to_cpu(pSMBr->size));
2630 pFinfo->EndOfFile = pFinfo->AllocationSize;
2631 pFinfo->Attributes =
2632 cpu_to_le32(le16_to_cpu(pSMBr->attr));
2633 } else
2634 rc = -EIO; /* bad buffer passed in */
2636 cifs_buf_release(pSMB);
2638 if (rc == -EAGAIN)
2639 goto QInfRetry;
2641 return rc;
2648 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2649 const unsigned char *searchName,
2650 FILE_ALL_INFO * pFindData,
2651 const struct nls_table *nls_codepage, int remap)
2653 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2654 TRANSACTION2_QPI_REQ *pSMB = NULL;
2655 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2656 int rc = 0;
2657 int bytes_returned;
2658 int name_len;
2659 __u16 params, byte_count;
2661 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2662 QPathInfoRetry:
2663 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2664 (void **) &pSMBr);
2665 if (rc)
2666 return rc;
2668 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2669 name_len =
2670 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2671 PATH_MAX, nls_codepage, remap);
2672 name_len++; /* trailing null */
2673 name_len *= 2;
2674 } else { /* BB improve the check for buffer overruns BB */
2675 name_len = strnlen(searchName, PATH_MAX);
2676 name_len++; /* trailing null */
2677 strncpy(pSMB->FileName, searchName, name_len);
2680 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2681 pSMB->TotalDataCount = 0;
2682 pSMB->MaxParameterCount = cpu_to_le16(2);
2683 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2684 pSMB->MaxSetupCount = 0;
2685 pSMB->Reserved = 0;
2686 pSMB->Flags = 0;
2687 pSMB->Timeout = 0;
2688 pSMB->Reserved2 = 0;
2689 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2690 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2691 pSMB->DataCount = 0;
2692 pSMB->DataOffset = 0;
2693 pSMB->SetupCount = 1;
2694 pSMB->Reserved3 = 0;
2695 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2696 byte_count = params + 1 /* pad */ ;
2697 pSMB->TotalParameterCount = cpu_to_le16(params);
2698 pSMB->ParameterCount = pSMB->TotalParameterCount;
2699 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2700 pSMB->Reserved4 = 0;
2701 pSMB->hdr.smb_buf_length += byte_count;
2702 pSMB->ByteCount = cpu_to_le16(byte_count);
2704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2706 if (rc) {
2707 cFYI(1, ("Send error in QPathInfo = %d", rc));
2708 } else { /* decode response */
2709 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2711 if (rc || (pSMBr->ByteCount < 40))
2712 rc = -EIO; /* bad smb */
2713 else if (pFindData){
2714 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2715 memcpy((char *) pFindData,
2716 (char *) &pSMBr->hdr.Protocol +
2717 data_offset, sizeof (FILE_ALL_INFO));
2718 } else
2719 rc = -ENOMEM;
2721 cifs_buf_release(pSMB);
2722 if (rc == -EAGAIN)
2723 goto QPathInfoRetry;
2725 return rc;
2729 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2730 const unsigned char *searchName,
2731 FILE_UNIX_BASIC_INFO * pFindData,
2732 const struct nls_table *nls_codepage, int remap)
2734 /* SMB_QUERY_FILE_UNIX_BASIC */
2735 TRANSACTION2_QPI_REQ *pSMB = NULL;
2736 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2737 int rc = 0;
2738 int bytes_returned = 0;
2739 int name_len;
2740 __u16 params, byte_count;
2742 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2743 UnixQPathInfoRetry:
2744 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2745 (void **) &pSMBr);
2746 if (rc)
2747 return rc;
2749 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2750 name_len =
2751 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2752 PATH_MAX, nls_codepage, remap);
2753 name_len++; /* trailing null */
2754 name_len *= 2;
2755 } else { /* BB improve the check for buffer overruns BB */
2756 name_len = strnlen(searchName, PATH_MAX);
2757 name_len++; /* trailing null */
2758 strncpy(pSMB->FileName, searchName, name_len);
2761 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2762 pSMB->TotalDataCount = 0;
2763 pSMB->MaxParameterCount = cpu_to_le16(2);
2764 /* BB find exact max SMB PDU from sess structure BB */
2765 pSMB->MaxDataCount = cpu_to_le16(4000);
2766 pSMB->MaxSetupCount = 0;
2767 pSMB->Reserved = 0;
2768 pSMB->Flags = 0;
2769 pSMB->Timeout = 0;
2770 pSMB->Reserved2 = 0;
2771 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2772 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2773 pSMB->DataCount = 0;
2774 pSMB->DataOffset = 0;
2775 pSMB->SetupCount = 1;
2776 pSMB->Reserved3 = 0;
2777 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2778 byte_count = params + 1 /* pad */ ;
2779 pSMB->TotalParameterCount = cpu_to_le16(params);
2780 pSMB->ParameterCount = pSMB->TotalParameterCount;
2781 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2782 pSMB->Reserved4 = 0;
2783 pSMB->hdr.smb_buf_length += byte_count;
2784 pSMB->ByteCount = cpu_to_le16(byte_count);
2786 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2787 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2788 if (rc) {
2789 cFYI(1, ("Send error in QPathInfo = %d", rc));
2790 } else { /* decode response */
2791 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2793 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2794 rc = -EIO; /* bad smb */
2795 } else {
2796 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2797 memcpy((char *) pFindData,
2798 (char *) &pSMBr->hdr.Protocol +
2799 data_offset,
2800 sizeof (FILE_UNIX_BASIC_INFO));
2803 cifs_buf_release(pSMB);
2804 if (rc == -EAGAIN)
2805 goto UnixQPathInfoRetry;
2807 return rc;
2810 #if 0 /* function unused at present */
2811 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2812 const char *searchName, FILE_ALL_INFO * findData,
2813 const struct nls_table *nls_codepage)
2815 /* level 257 SMB_ */
2816 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2817 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2818 int rc = 0;
2819 int bytes_returned;
2820 int name_len;
2821 __u16 params, byte_count;
2823 cFYI(1, ("In FindUnique"));
2824 findUniqueRetry:
2825 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2826 (void **) &pSMBr);
2827 if (rc)
2828 return rc;
2830 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2831 name_len =
2832 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2833 /* find define for this maxpathcomponent */
2834 , nls_codepage);
2835 name_len++; /* trailing null */
2836 name_len *= 2;
2837 } else { /* BB improve the check for buffer overruns BB */
2838 name_len = strnlen(searchName, PATH_MAX);
2839 name_len++; /* trailing null */
2840 strncpy(pSMB->FileName, searchName, name_len);
2843 params = 12 + name_len /* includes null */ ;
2844 pSMB->TotalDataCount = 0; /* no EAs */
2845 pSMB->MaxParameterCount = cpu_to_le16(2);
2846 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2847 pSMB->MaxSetupCount = 0;
2848 pSMB->Reserved = 0;
2849 pSMB->Flags = 0;
2850 pSMB->Timeout = 0;
2851 pSMB->Reserved2 = 0;
2852 pSMB->ParameterOffset = cpu_to_le16(
2853 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2854 pSMB->DataCount = 0;
2855 pSMB->DataOffset = 0;
2856 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2857 pSMB->Reserved3 = 0;
2858 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2859 byte_count = params + 1 /* pad */ ;
2860 pSMB->TotalParameterCount = cpu_to_le16(params);
2861 pSMB->ParameterCount = pSMB->TotalParameterCount;
2862 pSMB->SearchAttributes =
2863 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2864 ATTR_DIRECTORY);
2865 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2866 pSMB->SearchFlags = cpu_to_le16(1);
2867 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2868 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2869 pSMB->hdr.smb_buf_length += byte_count;
2870 pSMB->ByteCount = cpu_to_le16(byte_count);
2872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2875 if (rc) {
2876 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2877 } else { /* decode response */
2878 cifs_stats_inc(&tcon->num_ffirst);
2879 /* BB fill in */
2882 cifs_buf_release(pSMB);
2883 if (rc == -EAGAIN)
2884 goto findUniqueRetry;
2886 return rc;
2888 #endif /* end unused (temporarily) function */
2890 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2892 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2893 const char *searchName,
2894 const struct nls_table *nls_codepage,
2895 __u16 * pnetfid,
2896 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2898 /* level 257 SMB_ */
2899 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2900 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2901 T2_FFIRST_RSP_PARMS * parms;
2902 int rc = 0;
2903 int bytes_returned = 0;
2904 int name_len;
2905 __u16 params, byte_count;
2907 cFYI(1, ("In FindFirst for %s",searchName));
2909 findFirstRetry:
2910 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2911 (void **) &pSMBr);
2912 if (rc)
2913 return rc;
2915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2916 name_len =
2917 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2918 PATH_MAX, nls_codepage, remap);
2919 /* We can not add the asterik earlier in case
2920 it got remapped to 0xF03A as if it were part of the
2921 directory name instead of a wildcard */
2922 name_len *= 2;
2923 pSMB->FileName[name_len] = dirsep;
2924 pSMB->FileName[name_len+1] = 0;
2925 pSMB->FileName[name_len+2] = '*';
2926 pSMB->FileName[name_len+3] = 0;
2927 name_len += 4; /* now the trailing null */
2928 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2929 pSMB->FileName[name_len+1] = 0;
2930 name_len += 2;
2931 } else { /* BB add check for overrun of SMB buf BB */
2932 name_len = strnlen(searchName, PATH_MAX);
2933 /* BB fix here and in unicode clause above ie
2934 if(name_len > buffersize-header)
2935 free buffer exit; BB */
2936 strncpy(pSMB->FileName, searchName, name_len);
2937 pSMB->FileName[name_len] = dirsep;
2938 pSMB->FileName[name_len+1] = '*';
2939 pSMB->FileName[name_len+2] = 0;
2940 name_len += 3;
2943 params = 12 + name_len /* includes null */ ;
2944 pSMB->TotalDataCount = 0; /* no EAs */
2945 pSMB->MaxParameterCount = cpu_to_le16(10);
2946 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2947 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2948 pSMB->MaxSetupCount = 0;
2949 pSMB->Reserved = 0;
2950 pSMB->Flags = 0;
2951 pSMB->Timeout = 0;
2952 pSMB->Reserved2 = 0;
2953 byte_count = params + 1 /* pad */ ;
2954 pSMB->TotalParameterCount = cpu_to_le16(params);
2955 pSMB->ParameterCount = pSMB->TotalParameterCount;
2956 pSMB->ParameterOffset = cpu_to_le16(
2957 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2958 pSMB->DataCount = 0;
2959 pSMB->DataOffset = 0;
2960 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2961 pSMB->Reserved3 = 0;
2962 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2963 pSMB->SearchAttributes =
2964 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2965 ATTR_DIRECTORY);
2966 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2967 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2968 CIFS_SEARCH_RETURN_RESUME);
2969 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2971 /* BB what should we set StorageType to? Does it matter? BB */
2972 pSMB->SearchStorageType = 0;
2973 pSMB->hdr.smb_buf_length += byte_count;
2974 pSMB->ByteCount = cpu_to_le16(byte_count);
2976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2978 cifs_stats_inc(&tcon->num_ffirst);
2980 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2981 /* BB Add code to handle unsupported level rc */
2982 cFYI(1, ("Error in FindFirst = %d", rc));
2984 if (pSMB)
2985 cifs_buf_release(pSMB);
2987 /* BB eventually could optimize out free and realloc of buf */
2988 /* for this case */
2989 if (rc == -EAGAIN)
2990 goto findFirstRetry;
2991 } else { /* decode response */
2992 /* BB remember to free buffer if error BB */
2993 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2994 if(rc == 0) {
2995 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2996 psrch_inf->unicode = TRUE;
2997 else
2998 psrch_inf->unicode = FALSE;
3000 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3001 psrch_inf->srch_entries_start =
3002 (char *) &pSMBr->hdr.Protocol +
3003 le16_to_cpu(pSMBr->t2.DataOffset);
3004 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3005 le16_to_cpu(pSMBr->t2.ParameterOffset));
3007 if(parms->EndofSearch)
3008 psrch_inf->endOfSearch = TRUE;
3009 else
3010 psrch_inf->endOfSearch = FALSE;
3012 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3013 psrch_inf->index_of_last_entry =
3014 psrch_inf->entries_in_buffer;
3015 *pnetfid = parms->SearchHandle;
3016 } else {
3017 cifs_buf_release(pSMB);
3021 return rc;
3024 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3025 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3027 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3028 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3029 T2_FNEXT_RSP_PARMS * parms;
3030 char *response_data;
3031 int rc = 0;
3032 int bytes_returned, name_len;
3033 __u16 params, byte_count;
3035 cFYI(1, ("In FindNext"));
3037 if(psrch_inf->endOfSearch == TRUE)
3038 return -ENOENT;
3040 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3041 (void **) &pSMBr);
3042 if (rc)
3043 return rc;
3045 params = 14; /* includes 2 bytes of null string, converted to LE below */
3046 byte_count = 0;
3047 pSMB->TotalDataCount = 0; /* no EAs */
3048 pSMB->MaxParameterCount = cpu_to_le16(8);
3049 pSMB->MaxDataCount =
3050 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3051 pSMB->MaxSetupCount = 0;
3052 pSMB->Reserved = 0;
3053 pSMB->Flags = 0;
3054 pSMB->Timeout = 0;
3055 pSMB->Reserved2 = 0;
3056 pSMB->ParameterOffset = cpu_to_le16(
3057 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3058 pSMB->DataCount = 0;
3059 pSMB->DataOffset = 0;
3060 pSMB->SetupCount = 1;
3061 pSMB->Reserved3 = 0;
3062 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3063 pSMB->SearchHandle = searchHandle; /* always kept as le */
3064 pSMB->SearchCount =
3065 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3066 /* test for Unix extensions */
3067 /* if (tcon->ses->capabilities & CAP_UNIX) {
3068 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3069 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3070 } else {
3071 pSMB->InformationLevel =
3072 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3073 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3074 } */
3075 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3076 pSMB->ResumeKey = psrch_inf->resume_key;
3077 pSMB->SearchFlags =
3078 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3080 name_len = psrch_inf->resume_name_len;
3081 params += name_len;
3082 if(name_len < PATH_MAX) {
3083 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3084 byte_count += name_len;
3085 /* 14 byte parm len above enough for 2 byte null terminator */
3086 pSMB->ResumeFileName[name_len] = 0;
3087 pSMB->ResumeFileName[name_len+1] = 0;
3088 } else {
3089 rc = -EINVAL;
3090 goto FNext2_err_exit;
3092 byte_count = params + 1 /* pad */ ;
3093 pSMB->TotalParameterCount = cpu_to_le16(params);
3094 pSMB->ParameterCount = pSMB->TotalParameterCount;
3095 pSMB->hdr.smb_buf_length += byte_count;
3096 pSMB->ByteCount = cpu_to_le16(byte_count);
3098 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3100 cifs_stats_inc(&tcon->num_fnext);
3101 if (rc) {
3102 if (rc == -EBADF) {
3103 psrch_inf->endOfSearch = TRUE;
3104 rc = 0; /* search probably was closed at end of search above */
3105 } else
3106 cFYI(1, ("FindNext returned = %d", rc));
3107 } else { /* decode response */
3108 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3110 if(rc == 0) {
3111 /* BB fixme add lock for file (srch_info) struct here */
3112 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3113 psrch_inf->unicode = TRUE;
3114 else
3115 psrch_inf->unicode = FALSE;
3116 response_data = (char *) &pSMBr->hdr.Protocol +
3117 le16_to_cpu(pSMBr->t2.ParameterOffset);
3118 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3119 response_data = (char *)&pSMBr->hdr.Protocol +
3120 le16_to_cpu(pSMBr->t2.DataOffset);
3121 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3122 psrch_inf->srch_entries_start = response_data;
3123 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3124 if(parms->EndofSearch)
3125 psrch_inf->endOfSearch = TRUE;
3126 else
3127 psrch_inf->endOfSearch = FALSE;
3129 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3130 psrch_inf->index_of_last_entry +=
3131 psrch_inf->entries_in_buffer;
3132 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3134 /* BB fixme add unlock here */
3139 /* BB On error, should we leave previous search buf (and count and
3140 last entry fields) intact or free the previous one? */
3142 /* Note: On -EAGAIN error only caller can retry on handle based calls
3143 since file handle passed in no longer valid */
3144 FNext2_err_exit:
3145 if (rc != 0)
3146 cifs_buf_release(pSMB);
3148 return rc;
3152 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3154 int rc = 0;
3155 FINDCLOSE_REQ *pSMB = NULL;
3156 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3157 int bytes_returned;
3159 cFYI(1, ("In CIFSSMBFindClose"));
3160 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3162 /* no sense returning error if session restarted
3163 as file handle has been closed */
3164 if(rc == -EAGAIN)
3165 return 0;
3166 if (rc)
3167 return rc;
3169 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3170 pSMB->FileID = searchHandle;
3171 pSMB->ByteCount = 0;
3172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3174 if (rc) {
3175 cERROR(1, ("Send error in FindClose = %d", rc));
3177 cifs_stats_inc(&tcon->num_fclose);
3178 cifs_small_buf_release(pSMB);
3180 /* Since session is dead, search handle closed on server already */
3181 if (rc == -EAGAIN)
3182 rc = 0;
3184 return rc;
3188 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3189 const unsigned char *searchName,
3190 __u64 * inode_number,
3191 const struct nls_table *nls_codepage, int remap)
3193 int rc = 0;
3194 TRANSACTION2_QPI_REQ *pSMB = NULL;
3195 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3196 int name_len, bytes_returned;
3197 __u16 params, byte_count;
3199 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3200 if(tcon == NULL)
3201 return -ENODEV;
3203 GetInodeNumberRetry:
3204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3205 (void **) &pSMBr);
3206 if (rc)
3207 return rc;
3210 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3211 name_len =
3212 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3213 PATH_MAX,nls_codepage, remap);
3214 name_len++; /* trailing null */
3215 name_len *= 2;
3216 } else { /* BB improve the check for buffer overruns BB */
3217 name_len = strnlen(searchName, PATH_MAX);
3218 name_len++; /* trailing null */
3219 strncpy(pSMB->FileName, searchName, name_len);
3222 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3223 pSMB->TotalDataCount = 0;
3224 pSMB->MaxParameterCount = cpu_to_le16(2);
3225 /* BB find exact max data count below from sess structure BB */
3226 pSMB->MaxDataCount = cpu_to_le16(4000);
3227 pSMB->MaxSetupCount = 0;
3228 pSMB->Reserved = 0;
3229 pSMB->Flags = 0;
3230 pSMB->Timeout = 0;
3231 pSMB->Reserved2 = 0;
3232 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3233 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3234 pSMB->DataCount = 0;
3235 pSMB->DataOffset = 0;
3236 pSMB->SetupCount = 1;
3237 pSMB->Reserved3 = 0;
3238 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3239 byte_count = params + 1 /* pad */ ;
3240 pSMB->TotalParameterCount = cpu_to_le16(params);
3241 pSMB->ParameterCount = pSMB->TotalParameterCount;
3242 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3243 pSMB->Reserved4 = 0;
3244 pSMB->hdr.smb_buf_length += byte_count;
3245 pSMB->ByteCount = cpu_to_le16(byte_count);
3247 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3248 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3249 if (rc) {
3250 cFYI(1, ("error %d in QueryInternalInfo", rc));
3251 } else {
3252 /* decode response */
3253 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3254 if (rc || (pSMBr->ByteCount < 2))
3255 /* BB also check enough total bytes returned */
3256 /* If rc should we check for EOPNOSUPP and
3257 disable the srvino flag? or in caller? */
3258 rc = -EIO; /* bad smb */
3259 else {
3260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3261 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3262 struct file_internal_info * pfinfo;
3263 /* BB Do we need a cast or hash here ? */
3264 if(count < 8) {
3265 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3266 rc = -EIO;
3267 goto GetInodeNumOut;
3269 pfinfo = (struct file_internal_info *)
3270 (data_offset + (char *) &pSMBr->hdr.Protocol);
3271 *inode_number = pfinfo->UniqueId;
3274 GetInodeNumOut:
3275 cifs_buf_release(pSMB);
3276 if (rc == -EAGAIN)
3277 goto GetInodeNumberRetry;
3278 return rc;
3282 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3283 const unsigned char *searchName,
3284 unsigned char **targetUNCs,
3285 unsigned int *number_of_UNC_in_array,
3286 const struct nls_table *nls_codepage, int remap)
3288 /* TRANS2_GET_DFS_REFERRAL */
3289 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3290 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3291 struct dfs_referral_level_3 * referrals = NULL;
3292 int rc = 0;
3293 int bytes_returned;
3294 int name_len;
3295 unsigned int i;
3296 char * temp;
3297 __u16 params, byte_count;
3298 *number_of_UNC_in_array = 0;
3299 *targetUNCs = NULL;
3301 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3302 if (ses == NULL)
3303 return -ENODEV;
3304 getDFSRetry:
3305 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3306 (void **) &pSMBr);
3307 if (rc)
3308 return rc;
3310 /* server pointer checked in called function,
3311 but should never be null here anyway */
3312 pSMB->hdr.Mid = GetNextMid(ses->server);
3313 pSMB->hdr.Tid = ses->ipc_tid;
3314 pSMB->hdr.Uid = ses->Suid;
3315 if (ses->capabilities & CAP_STATUS32) {
3316 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3318 if (ses->capabilities & CAP_DFS) {
3319 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3322 if (ses->capabilities & CAP_UNICODE) {
3323 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3324 name_len =
3325 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3326 searchName, PATH_MAX, nls_codepage, remap);
3327 name_len++; /* trailing null */
3328 name_len *= 2;
3329 } else { /* BB improve the check for buffer overruns BB */
3330 name_len = strnlen(searchName, PATH_MAX);
3331 name_len++; /* trailing null */
3332 strncpy(pSMB->RequestFileName, searchName, name_len);
3335 params = 2 /* level */ + name_len /*includes null */ ;
3336 pSMB->TotalDataCount = 0;
3337 pSMB->DataCount = 0;
3338 pSMB->DataOffset = 0;
3339 pSMB->MaxParameterCount = 0;
3340 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3341 pSMB->MaxSetupCount = 0;
3342 pSMB->Reserved = 0;
3343 pSMB->Flags = 0;
3344 pSMB->Timeout = 0;
3345 pSMB->Reserved2 = 0;
3346 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3347 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3348 pSMB->SetupCount = 1;
3349 pSMB->Reserved3 = 0;
3350 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3351 byte_count = params + 3 /* pad */ ;
3352 pSMB->ParameterCount = cpu_to_le16(params);
3353 pSMB->TotalParameterCount = pSMB->ParameterCount;
3354 pSMB->MaxReferralLevel = cpu_to_le16(3);
3355 pSMB->hdr.smb_buf_length += byte_count;
3356 pSMB->ByteCount = cpu_to_le16(byte_count);
3358 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3360 if (rc) {
3361 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3362 } else { /* decode response */
3363 /* BB Add logic to parse referrals here */
3364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3366 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3367 rc = -EIO; /* bad smb */
3368 else {
3369 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3370 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3372 cFYI(1,
3373 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3374 pSMBr->ByteCount, data_offset));
3375 referrals =
3376 (struct dfs_referral_level_3 *)
3377 (8 /* sizeof start of data block */ +
3378 data_offset +
3379 (char *) &pSMBr->hdr.Protocol);
3380 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",
3381 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)));
3382 /* BB This field is actually two bytes in from start of
3383 data block so we could do safety check that DataBlock
3384 begins at address of pSMBr->NumberOfReferrals */
3385 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3387 /* BB Fix below so can return more than one referral */
3388 if(*number_of_UNC_in_array > 1)
3389 *number_of_UNC_in_array = 1;
3391 /* get the length of the strings describing refs */
3392 name_len = 0;
3393 for(i=0;i<*number_of_UNC_in_array;i++) {
3394 /* make sure that DfsPathOffset not past end */
3395 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3396 if (offset > data_count) {
3397 /* if invalid referral, stop here and do
3398 not try to copy any more */
3399 *number_of_UNC_in_array = i;
3400 break;
3402 temp = ((char *)referrals) + offset;
3404 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3405 name_len += UniStrnlen((wchar_t *)temp,data_count);
3406 } else {
3407 name_len += strnlen(temp,data_count);
3409 referrals++;
3410 /* BB add check that referral pointer does not fall off end PDU */
3413 /* BB add check for name_len bigger than bcc */
3414 *targetUNCs =
3415 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3416 if(*targetUNCs == NULL) {
3417 rc = -ENOMEM;
3418 goto GetDFSRefExit;
3420 /* copy the ref strings */
3421 referrals =
3422 (struct dfs_referral_level_3 *)
3423 (8 /* sizeof data hdr */ +
3424 data_offset +
3425 (char *) &pSMBr->hdr.Protocol);
3427 for(i=0;i<*number_of_UNC_in_array;i++) {
3428 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3429 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3430 cifs_strfromUCS_le(*targetUNCs,
3431 (__le16 *) temp, name_len, nls_codepage);
3432 } else {
3433 strncpy(*targetUNCs,temp,name_len);
3435 /* BB update target_uncs pointers */
3436 referrals++;
3438 temp = *targetUNCs;
3439 temp[name_len] = 0;
3443 GetDFSRefExit:
3444 if (pSMB)
3445 cifs_buf_release(pSMB);
3447 if (rc == -EAGAIN)
3448 goto getDFSRetry;
3450 return rc;
3453 /* Query File System Info such as free space to old servers such as Win 9x */
3455 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3457 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3458 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3459 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3460 FILE_SYSTEM_ALLOC_INFO *response_data;
3461 int rc = 0;
3462 int bytes_returned = 0;
3463 __u16 params, byte_count;
3465 cFYI(1, ("OldQFSInfo"));
3466 oldQFSInfoRetry:
3467 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3468 (void **) &pSMBr);
3469 if (rc)
3470 return rc;
3471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3472 (void **) &pSMBr);
3473 if (rc)
3474 return rc;
3476 params = 2; /* level */
3477 pSMB->TotalDataCount = 0;
3478 pSMB->MaxParameterCount = cpu_to_le16(2);
3479 pSMB->MaxDataCount = cpu_to_le16(1000);
3480 pSMB->MaxSetupCount = 0;
3481 pSMB->Reserved = 0;
3482 pSMB->Flags = 0;
3483 pSMB->Timeout = 0;
3484 pSMB->Reserved2 = 0;
3485 byte_count = params + 1 /* pad */ ;
3486 pSMB->TotalParameterCount = cpu_to_le16(params);
3487 pSMB->ParameterCount = pSMB->TotalParameterCount;
3488 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3489 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3490 pSMB->DataCount = 0;
3491 pSMB->DataOffset = 0;
3492 pSMB->SetupCount = 1;
3493 pSMB->Reserved3 = 0;
3494 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3495 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3496 pSMB->hdr.smb_buf_length += byte_count;
3497 pSMB->ByteCount = cpu_to_le16(byte_count);
3499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3501 if (rc) {
3502 cFYI(1, ("Send error in QFSInfo = %d", rc));
3503 } else { /* decode response */
3504 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3506 if (rc || (pSMBr->ByteCount < 18))
3507 rc = -EIO; /* bad smb */
3508 else {
3509 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3510 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3511 pSMBr->ByteCount, data_offset));
3513 response_data =
3514 (FILE_SYSTEM_ALLOC_INFO *)
3515 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3516 FSData->f_bsize =
3517 le16_to_cpu(response_data->BytesPerSector) *
3518 le32_to_cpu(response_data->
3519 SectorsPerAllocationUnit);
3520 FSData->f_blocks =
3521 le32_to_cpu(response_data->TotalAllocationUnits);
3522 FSData->f_bfree = FSData->f_bavail =
3523 le32_to_cpu(response_data->FreeAllocationUnits);
3524 cFYI(1,
3525 ("Blocks: %lld Free: %lld Block size %ld",
3526 (unsigned long long)FSData->f_blocks,
3527 (unsigned long long)FSData->f_bfree,
3528 FSData->f_bsize));
3531 cifs_buf_release(pSMB);
3533 if (rc == -EAGAIN)
3534 goto oldQFSInfoRetry;
3536 return rc;
3540 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3542 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3543 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3544 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3545 FILE_SYSTEM_INFO *response_data;
3546 int rc = 0;
3547 int bytes_returned = 0;
3548 __u16 params, byte_count;
3550 cFYI(1, ("In QFSInfo"));
3551 QFSInfoRetry:
3552 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3553 (void **) &pSMBr);
3554 if (rc)
3555 return rc;
3557 params = 2; /* level */
3558 pSMB->TotalDataCount = 0;
3559 pSMB->MaxParameterCount = cpu_to_le16(2);
3560 pSMB->MaxDataCount = cpu_to_le16(1000);
3561 pSMB->MaxSetupCount = 0;
3562 pSMB->Reserved = 0;
3563 pSMB->Flags = 0;
3564 pSMB->Timeout = 0;
3565 pSMB->Reserved2 = 0;
3566 byte_count = params + 1 /* pad */ ;
3567 pSMB->TotalParameterCount = cpu_to_le16(params);
3568 pSMB->ParameterCount = pSMB->TotalParameterCount;
3569 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3570 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3571 pSMB->DataCount = 0;
3572 pSMB->DataOffset = 0;
3573 pSMB->SetupCount = 1;
3574 pSMB->Reserved3 = 0;
3575 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3576 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3577 pSMB->hdr.smb_buf_length += byte_count;
3578 pSMB->ByteCount = cpu_to_le16(byte_count);
3580 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3581 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3582 if (rc) {
3583 cFYI(1, ("Send error in QFSInfo = %d", rc));
3584 } else { /* decode response */
3585 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3587 if (rc || (pSMBr->ByteCount < 24))
3588 rc = -EIO; /* bad smb */
3589 else {
3590 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3592 response_data =
3593 (FILE_SYSTEM_INFO
3594 *) (((char *) &pSMBr->hdr.Protocol) +
3595 data_offset);
3596 FSData->f_bsize =
3597 le32_to_cpu(response_data->BytesPerSector) *
3598 le32_to_cpu(response_data->
3599 SectorsPerAllocationUnit);
3600 FSData->f_blocks =
3601 le64_to_cpu(response_data->TotalAllocationUnits);
3602 FSData->f_bfree = FSData->f_bavail =
3603 le64_to_cpu(response_data->FreeAllocationUnits);
3604 cFYI(1,
3605 ("Blocks: %lld Free: %lld Block size %ld",
3606 (unsigned long long)FSData->f_blocks,
3607 (unsigned long long)FSData->f_bfree,
3608 FSData->f_bsize));
3611 cifs_buf_release(pSMB);
3613 if (rc == -EAGAIN)
3614 goto QFSInfoRetry;
3616 return rc;
3620 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3622 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3623 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3624 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3625 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3626 int rc = 0;
3627 int bytes_returned = 0;
3628 __u16 params, byte_count;
3630 cFYI(1, ("In QFSAttributeInfo"));
3631 QFSAttributeRetry:
3632 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3633 (void **) &pSMBr);
3634 if (rc)
3635 return rc;
3637 params = 2; /* level */
3638 pSMB->TotalDataCount = 0;
3639 pSMB->MaxParameterCount = cpu_to_le16(2);
3640 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3641 pSMB->MaxSetupCount = 0;
3642 pSMB->Reserved = 0;
3643 pSMB->Flags = 0;
3644 pSMB->Timeout = 0;
3645 pSMB->Reserved2 = 0;
3646 byte_count = params + 1 /* pad */ ;
3647 pSMB->TotalParameterCount = cpu_to_le16(params);
3648 pSMB->ParameterCount = pSMB->TotalParameterCount;
3649 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3650 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3651 pSMB->DataCount = 0;
3652 pSMB->DataOffset = 0;
3653 pSMB->SetupCount = 1;
3654 pSMB->Reserved3 = 0;
3655 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3656 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3657 pSMB->hdr.smb_buf_length += byte_count;
3658 pSMB->ByteCount = cpu_to_le16(byte_count);
3660 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3661 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3662 if (rc) {
3663 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3664 } else { /* decode response */
3665 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3667 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3668 rc = -EIO; /* bad smb */
3669 } else {
3670 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3671 response_data =
3672 (FILE_SYSTEM_ATTRIBUTE_INFO
3673 *) (((char *) &pSMBr->hdr.Protocol) +
3674 data_offset);
3675 memcpy(&tcon->fsAttrInfo, response_data,
3676 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3679 cifs_buf_release(pSMB);
3681 if (rc == -EAGAIN)
3682 goto QFSAttributeRetry;
3684 return rc;
3688 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3690 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3691 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3692 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3693 FILE_SYSTEM_DEVICE_INFO *response_data;
3694 int rc = 0;
3695 int bytes_returned = 0;
3696 __u16 params, byte_count;
3698 cFYI(1, ("In QFSDeviceInfo"));
3699 QFSDeviceRetry:
3700 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3701 (void **) &pSMBr);
3702 if (rc)
3703 return rc;
3705 params = 2; /* level */
3706 pSMB->TotalDataCount = 0;
3707 pSMB->MaxParameterCount = cpu_to_le16(2);
3708 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3709 pSMB->MaxSetupCount = 0;
3710 pSMB->Reserved = 0;
3711 pSMB->Flags = 0;
3712 pSMB->Timeout = 0;
3713 pSMB->Reserved2 = 0;
3714 byte_count = params + 1 /* pad */ ;
3715 pSMB->TotalParameterCount = cpu_to_le16(params);
3716 pSMB->ParameterCount = pSMB->TotalParameterCount;
3717 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3718 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3720 pSMB->DataCount = 0;
3721 pSMB->DataOffset = 0;
3722 pSMB->SetupCount = 1;
3723 pSMB->Reserved3 = 0;
3724 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3725 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3726 pSMB->hdr.smb_buf_length += byte_count;
3727 pSMB->ByteCount = cpu_to_le16(byte_count);
3729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3731 if (rc) {
3732 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3733 } else { /* decode response */
3734 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3736 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3737 rc = -EIO; /* bad smb */
3738 else {
3739 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3740 response_data =
3741 (FILE_SYSTEM_DEVICE_INFO *)
3742 (((char *) &pSMBr->hdr.Protocol) +
3743 data_offset);
3744 memcpy(&tcon->fsDevInfo, response_data,
3745 sizeof (FILE_SYSTEM_DEVICE_INFO));
3748 cifs_buf_release(pSMB);
3750 if (rc == -EAGAIN)
3751 goto QFSDeviceRetry;
3753 return rc;
3757 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3759 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3760 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3761 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3762 FILE_SYSTEM_UNIX_INFO *response_data;
3763 int rc = 0;
3764 int bytes_returned = 0;
3765 __u16 params, byte_count;
3767 cFYI(1, ("In QFSUnixInfo"));
3768 QFSUnixRetry:
3769 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3770 (void **) &pSMBr);
3771 if (rc)
3772 return rc;
3774 params = 2; /* level */
3775 pSMB->TotalDataCount = 0;
3776 pSMB->DataCount = 0;
3777 pSMB->DataOffset = 0;
3778 pSMB->MaxParameterCount = cpu_to_le16(2);
3779 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3780 pSMB->MaxSetupCount = 0;
3781 pSMB->Reserved = 0;
3782 pSMB->Flags = 0;
3783 pSMB->Timeout = 0;
3784 pSMB->Reserved2 = 0;
3785 byte_count = params + 1 /* pad */ ;
3786 pSMB->ParameterCount = cpu_to_le16(params);
3787 pSMB->TotalParameterCount = pSMB->ParameterCount;
3788 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3789 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3790 pSMB->SetupCount = 1;
3791 pSMB->Reserved3 = 0;
3792 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3793 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3794 pSMB->hdr.smb_buf_length += byte_count;
3795 pSMB->ByteCount = cpu_to_le16(byte_count);
3797 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3798 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3799 if (rc) {
3800 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3801 } else { /* decode response */
3802 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3804 if (rc || (pSMBr->ByteCount < 13)) {
3805 rc = -EIO; /* bad smb */
3806 } else {
3807 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3808 response_data =
3809 (FILE_SYSTEM_UNIX_INFO
3810 *) (((char *) &pSMBr->hdr.Protocol) +
3811 data_offset);
3812 memcpy(&tcon->fsUnixInfo, response_data,
3813 sizeof (FILE_SYSTEM_UNIX_INFO));
3816 cifs_buf_release(pSMB);
3818 if (rc == -EAGAIN)
3819 goto QFSUnixRetry;
3822 return rc;
3826 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3828 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3829 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3830 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3831 int rc = 0;
3832 int bytes_returned = 0;
3833 __u16 params, param_offset, offset, byte_count;
3835 cFYI(1, ("In SETFSUnixInfo"));
3836 SETFSUnixRetry:
3837 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3838 (void **) &pSMBr);
3839 if (rc)
3840 return rc;
3842 params = 4; /* 2 bytes zero followed by info level. */
3843 pSMB->MaxSetupCount = 0;
3844 pSMB->Reserved = 0;
3845 pSMB->Flags = 0;
3846 pSMB->Timeout = 0;
3847 pSMB->Reserved2 = 0;
3848 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3849 offset = param_offset + params;
3851 pSMB->MaxParameterCount = cpu_to_le16(4);
3852 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3853 pSMB->SetupCount = 1;
3854 pSMB->Reserved3 = 0;
3855 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3856 byte_count = 1 /* pad */ + params + 12;
3858 pSMB->DataCount = cpu_to_le16(12);
3859 pSMB->ParameterCount = cpu_to_le16(params);
3860 pSMB->TotalDataCount = pSMB->DataCount;
3861 pSMB->TotalParameterCount = pSMB->ParameterCount;
3862 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3863 pSMB->DataOffset = cpu_to_le16(offset);
3865 /* Params. */
3866 pSMB->FileNum = 0;
3867 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3869 /* Data. */
3870 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3871 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3872 pSMB->ClientUnixCap = cpu_to_le64(cap);
3874 pSMB->hdr.smb_buf_length += byte_count;
3875 pSMB->ByteCount = cpu_to_le16(byte_count);
3877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3879 if (rc) {
3880 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3881 } else { /* decode response */
3882 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3883 if (rc) {
3884 rc = -EIO; /* bad smb */
3887 cifs_buf_release(pSMB);
3889 if (rc == -EAGAIN)
3890 goto SETFSUnixRetry;
3892 return rc;
3898 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3899 struct kstatfs *FSData)
3901 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3902 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3903 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3904 FILE_SYSTEM_POSIX_INFO *response_data;
3905 int rc = 0;
3906 int bytes_returned = 0;
3907 __u16 params, byte_count;
3909 cFYI(1, ("In QFSPosixInfo"));
3910 QFSPosixRetry:
3911 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3912 (void **) &pSMBr);
3913 if (rc)
3914 return rc;
3916 params = 2; /* level */
3917 pSMB->TotalDataCount = 0;
3918 pSMB->DataCount = 0;
3919 pSMB->DataOffset = 0;
3920 pSMB->MaxParameterCount = cpu_to_le16(2);
3921 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3922 pSMB->MaxSetupCount = 0;
3923 pSMB->Reserved = 0;
3924 pSMB->Flags = 0;
3925 pSMB->Timeout = 0;
3926 pSMB->Reserved2 = 0;
3927 byte_count = params + 1 /* pad */ ;
3928 pSMB->ParameterCount = cpu_to_le16(params);
3929 pSMB->TotalParameterCount = pSMB->ParameterCount;
3930 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3931 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3932 pSMB->SetupCount = 1;
3933 pSMB->Reserved3 = 0;
3934 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3935 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3936 pSMB->hdr.smb_buf_length += byte_count;
3937 pSMB->ByteCount = cpu_to_le16(byte_count);
3939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3941 if (rc) {
3942 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3943 } else { /* decode response */
3944 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3946 if (rc || (pSMBr->ByteCount < 13)) {
3947 rc = -EIO; /* bad smb */
3948 } else {
3949 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3950 response_data =
3951 (FILE_SYSTEM_POSIX_INFO
3952 *) (((char *) &pSMBr->hdr.Protocol) +
3953 data_offset);
3954 FSData->f_bsize =
3955 le32_to_cpu(response_data->BlockSize);
3956 FSData->f_blocks =
3957 le64_to_cpu(response_data->TotalBlocks);
3958 FSData->f_bfree =
3959 le64_to_cpu(response_data->BlocksAvail);
3960 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
3961 FSData->f_bavail = FSData->f_bfree;
3962 } else {
3963 FSData->f_bavail =
3964 le64_to_cpu(response_data->UserBlocksAvail);
3966 if(response_data->TotalFileNodes != cpu_to_le64(-1))
3967 FSData->f_files =
3968 le64_to_cpu(response_data->TotalFileNodes);
3969 if(response_data->FreeFileNodes != cpu_to_le64(-1))
3970 FSData->f_ffree =
3971 le64_to_cpu(response_data->FreeFileNodes);
3974 cifs_buf_release(pSMB);
3976 if (rc == -EAGAIN)
3977 goto QFSPosixRetry;
3979 return rc;
3983 /* We can not use write of zero bytes trick to
3984 set file size due to need for large file support. Also note that
3985 this SetPathInfo is preferred to SetFileInfo based method in next
3986 routine which is only needed to work around a sharing violation bug
3987 in Samba which this routine can run into */
3990 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3991 __u64 size, int SetAllocation,
3992 const struct nls_table *nls_codepage, int remap)
3994 struct smb_com_transaction2_spi_req *pSMB = NULL;
3995 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3996 struct file_end_of_file_info *parm_data;
3997 int name_len;
3998 int rc = 0;
3999 int bytes_returned = 0;
4000 __u16 params, byte_count, data_count, param_offset, offset;
4002 cFYI(1, ("In SetEOF"));
4003 SetEOFRetry:
4004 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4005 (void **) &pSMBr);
4006 if (rc)
4007 return rc;
4009 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4010 name_len =
4011 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4012 PATH_MAX, nls_codepage, remap);
4013 name_len++; /* trailing null */
4014 name_len *= 2;
4015 } else { /* BB improve the check for buffer overruns BB */
4016 name_len = strnlen(fileName, PATH_MAX);
4017 name_len++; /* trailing null */
4018 strncpy(pSMB->FileName, fileName, name_len);
4020 params = 6 + name_len;
4021 data_count = sizeof (struct file_end_of_file_info);
4022 pSMB->MaxParameterCount = cpu_to_le16(2);
4023 pSMB->MaxDataCount = cpu_to_le16(4100);
4024 pSMB->MaxSetupCount = 0;
4025 pSMB->Reserved = 0;
4026 pSMB->Flags = 0;
4027 pSMB->Timeout = 0;
4028 pSMB->Reserved2 = 0;
4029 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4030 InformationLevel) - 4;
4031 offset = param_offset + params;
4032 if(SetAllocation) {
4033 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4034 pSMB->InformationLevel =
4035 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4036 else
4037 pSMB->InformationLevel =
4038 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4039 } else /* Set File Size */ {
4040 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4041 pSMB->InformationLevel =
4042 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4043 else
4044 pSMB->InformationLevel =
4045 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4048 parm_data =
4049 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4050 offset);
4051 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4052 pSMB->DataOffset = cpu_to_le16(offset);
4053 pSMB->SetupCount = 1;
4054 pSMB->Reserved3 = 0;
4055 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4056 byte_count = 3 /* pad */ + params + data_count;
4057 pSMB->DataCount = cpu_to_le16(data_count);
4058 pSMB->TotalDataCount = pSMB->DataCount;
4059 pSMB->ParameterCount = cpu_to_le16(params);
4060 pSMB->TotalParameterCount = pSMB->ParameterCount;
4061 pSMB->Reserved4 = 0;
4062 pSMB->hdr.smb_buf_length += byte_count;
4063 parm_data->FileSize = cpu_to_le64(size);
4064 pSMB->ByteCount = cpu_to_le16(byte_count);
4065 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4066 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4067 if (rc) {
4068 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4071 cifs_buf_release(pSMB);
4073 if (rc == -EAGAIN)
4074 goto SetEOFRetry;
4076 return rc;
4080 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4081 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4083 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4084 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4085 char *data_offset;
4086 struct file_end_of_file_info *parm_data;
4087 int rc = 0;
4088 int bytes_returned = 0;
4089 __u16 params, param_offset, offset, byte_count, count;
4091 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4092 (long long)size));
4093 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4095 if (rc)
4096 return rc;
4098 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4100 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4101 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4103 params = 6;
4104 pSMB->MaxSetupCount = 0;
4105 pSMB->Reserved = 0;
4106 pSMB->Flags = 0;
4107 pSMB->Timeout = 0;
4108 pSMB->Reserved2 = 0;
4109 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4110 offset = param_offset + params;
4112 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4114 count = sizeof(struct file_end_of_file_info);
4115 pSMB->MaxParameterCount = cpu_to_le16(2);
4116 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4117 pSMB->SetupCount = 1;
4118 pSMB->Reserved3 = 0;
4119 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4120 byte_count = 3 /* pad */ + params + count;
4121 pSMB->DataCount = cpu_to_le16(count);
4122 pSMB->ParameterCount = cpu_to_le16(params);
4123 pSMB->TotalDataCount = pSMB->DataCount;
4124 pSMB->TotalParameterCount = pSMB->ParameterCount;
4125 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4126 parm_data =
4127 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4128 offset);
4129 pSMB->DataOffset = cpu_to_le16(offset);
4130 parm_data->FileSize = cpu_to_le64(size);
4131 pSMB->Fid = fid;
4132 if(SetAllocation) {
4133 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4134 pSMB->InformationLevel =
4135 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4136 else
4137 pSMB->InformationLevel =
4138 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4139 } else /* Set File Size */ {
4140 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4141 pSMB->InformationLevel =
4142 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4143 else
4144 pSMB->InformationLevel =
4145 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4147 pSMB->Reserved4 = 0;
4148 pSMB->hdr.smb_buf_length += byte_count;
4149 pSMB->ByteCount = cpu_to_le16(byte_count);
4150 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4151 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4152 if (rc) {
4153 cFYI(1,
4154 ("Send error in SetFileInfo (SetFileSize) = %d",
4155 rc));
4158 if (pSMB)
4159 cifs_small_buf_release(pSMB);
4161 /* Note: On -EAGAIN error only caller can retry on handle based calls
4162 since file handle passed in no longer valid */
4164 return rc;
4167 /* Some legacy servers such as NT4 require that the file times be set on
4168 an open handle, rather than by pathname - this is awkward due to
4169 potential access conflicts on the open, but it is unavoidable for these
4170 old servers since the only other choice is to go from 100 nanosecond DCE
4171 time and resort to the original setpathinfo level which takes the ancient
4172 DOS time format with 2 second granularity */
4174 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4175 __u16 fid)
4177 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4178 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4179 char *data_offset;
4180 int rc = 0;
4181 int bytes_returned = 0;
4182 __u16 params, param_offset, offset, byte_count, count;
4184 cFYI(1, ("Set Times (via SetFileInfo)"));
4185 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4187 if (rc)
4188 return rc;
4190 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4192 /* At this point there is no need to override the current pid
4193 with the pid of the opener, but that could change if we someday
4194 use an existing handle (rather than opening one on the fly) */
4195 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4196 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4198 params = 6;
4199 pSMB->MaxSetupCount = 0;
4200 pSMB->Reserved = 0;
4201 pSMB->Flags = 0;
4202 pSMB->Timeout = 0;
4203 pSMB->Reserved2 = 0;
4204 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4205 offset = param_offset + params;
4207 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4209 count = sizeof (FILE_BASIC_INFO);
4210 pSMB->MaxParameterCount = cpu_to_le16(2);
4211 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4212 pSMB->SetupCount = 1;
4213 pSMB->Reserved3 = 0;
4214 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4215 byte_count = 3 /* pad */ + params + count;
4216 pSMB->DataCount = cpu_to_le16(count);
4217 pSMB->ParameterCount = cpu_to_le16(params);
4218 pSMB->TotalDataCount = pSMB->DataCount;
4219 pSMB->TotalParameterCount = pSMB->ParameterCount;
4220 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4221 pSMB->DataOffset = cpu_to_le16(offset);
4222 pSMB->Fid = fid;
4223 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4224 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4225 else
4226 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4227 pSMB->Reserved4 = 0;
4228 pSMB->hdr.smb_buf_length += byte_count;
4229 pSMB->ByteCount = cpu_to_le16(byte_count);
4230 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4233 if (rc) {
4234 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4237 cifs_small_buf_release(pSMB);
4239 /* Note: On -EAGAIN error only caller can retry on handle based calls
4240 since file handle passed in no longer valid */
4242 return rc;
4247 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4248 const FILE_BASIC_INFO * data,
4249 const struct nls_table *nls_codepage, int remap)
4251 TRANSACTION2_SPI_REQ *pSMB = NULL;
4252 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4253 int name_len;
4254 int rc = 0;
4255 int bytes_returned = 0;
4256 char *data_offset;
4257 __u16 params, param_offset, offset, byte_count, count;
4259 cFYI(1, ("In SetTimes"));
4261 SetTimesRetry:
4262 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4263 (void **) &pSMBr);
4264 if (rc)
4265 return rc;
4267 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4268 name_len =
4269 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4270 PATH_MAX, nls_codepage, remap);
4271 name_len++; /* trailing null */
4272 name_len *= 2;
4273 } else { /* BB improve the check for buffer overruns BB */
4274 name_len = strnlen(fileName, PATH_MAX);
4275 name_len++; /* trailing null */
4276 strncpy(pSMB->FileName, fileName, name_len);
4279 params = 6 + name_len;
4280 count = sizeof (FILE_BASIC_INFO);
4281 pSMB->MaxParameterCount = cpu_to_le16(2);
4282 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4283 pSMB->MaxSetupCount = 0;
4284 pSMB->Reserved = 0;
4285 pSMB->Flags = 0;
4286 pSMB->Timeout = 0;
4287 pSMB->Reserved2 = 0;
4288 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4289 InformationLevel) - 4;
4290 offset = param_offset + params;
4291 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4292 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4293 pSMB->DataOffset = cpu_to_le16(offset);
4294 pSMB->SetupCount = 1;
4295 pSMB->Reserved3 = 0;
4296 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4297 byte_count = 3 /* pad */ + params + count;
4299 pSMB->DataCount = cpu_to_le16(count);
4300 pSMB->ParameterCount = cpu_to_le16(params);
4301 pSMB->TotalDataCount = pSMB->DataCount;
4302 pSMB->TotalParameterCount = pSMB->ParameterCount;
4303 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4304 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4305 else
4306 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4307 pSMB->Reserved4 = 0;
4308 pSMB->hdr.smb_buf_length += byte_count;
4309 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4310 pSMB->ByteCount = cpu_to_le16(byte_count);
4311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4312 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4313 if (rc) {
4314 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4317 cifs_buf_release(pSMB);
4319 if (rc == -EAGAIN)
4320 goto SetTimesRetry;
4322 return rc;
4325 /* Can not be used to set time stamps yet (due to old DOS time format) */
4326 /* Can be used to set attributes */
4327 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4328 handling it anyway and NT4 was what we thought it would be needed for
4329 Do not delete it until we prove whether needed for Win9x though */
4331 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4332 __u16 dos_attrs, const struct nls_table *nls_codepage)
4334 SETATTR_REQ *pSMB = NULL;
4335 SETATTR_RSP *pSMBr = NULL;
4336 int rc = 0;
4337 int bytes_returned;
4338 int name_len;
4340 cFYI(1, ("In SetAttrLegacy"));
4342 SetAttrLgcyRetry:
4343 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4344 (void **) &pSMBr);
4345 if (rc)
4346 return rc;
4348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4349 name_len =
4350 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4351 PATH_MAX, nls_codepage);
4352 name_len++; /* trailing null */
4353 name_len *= 2;
4354 } else { /* BB improve the check for buffer overruns BB */
4355 name_len = strnlen(fileName, PATH_MAX);
4356 name_len++; /* trailing null */
4357 strncpy(pSMB->fileName, fileName, name_len);
4359 pSMB->attr = cpu_to_le16(dos_attrs);
4360 pSMB->BufferFormat = 0x04;
4361 pSMB->hdr.smb_buf_length += name_len + 1;
4362 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4364 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4365 if (rc) {
4366 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4369 cifs_buf_release(pSMB);
4371 if (rc == -EAGAIN)
4372 goto SetAttrLgcyRetry;
4374 return rc;
4376 #endif /* temporarily unneeded SetAttr legacy function */
4379 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4380 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4381 dev_t device, const struct nls_table *nls_codepage,
4382 int remap)
4384 TRANSACTION2_SPI_REQ *pSMB = NULL;
4385 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4386 int name_len;
4387 int rc = 0;
4388 int bytes_returned = 0;
4389 FILE_UNIX_BASIC_INFO *data_offset;
4390 __u16 params, param_offset, offset, count, byte_count;
4392 cFYI(1, ("In SetUID/GID/Mode"));
4393 setPermsRetry:
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4399 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4400 name_len =
4401 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4402 PATH_MAX, nls_codepage, remap);
4403 name_len++; /* trailing null */
4404 name_len *= 2;
4405 } else { /* BB improve the check for buffer overruns BB */
4406 name_len = strnlen(fileName, PATH_MAX);
4407 name_len++; /* trailing null */
4408 strncpy(pSMB->FileName, fileName, name_len);
4411 params = 6 + name_len;
4412 count = sizeof (FILE_UNIX_BASIC_INFO);
4413 pSMB->MaxParameterCount = cpu_to_le16(2);
4414 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4415 pSMB->MaxSetupCount = 0;
4416 pSMB->Reserved = 0;
4417 pSMB->Flags = 0;
4418 pSMB->Timeout = 0;
4419 pSMB->Reserved2 = 0;
4420 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4421 InformationLevel) - 4;
4422 offset = param_offset + params;
4423 data_offset =
4424 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4425 offset);
4426 memset(data_offset, 0, count);
4427 pSMB->DataOffset = cpu_to_le16(offset);
4428 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4429 pSMB->SetupCount = 1;
4430 pSMB->Reserved3 = 0;
4431 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4432 byte_count = 3 /* pad */ + params + count;
4433 pSMB->ParameterCount = cpu_to_le16(params);
4434 pSMB->DataCount = cpu_to_le16(count);
4435 pSMB->TotalParameterCount = pSMB->ParameterCount;
4436 pSMB->TotalDataCount = pSMB->DataCount;
4437 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4438 pSMB->Reserved4 = 0;
4439 pSMB->hdr.smb_buf_length += byte_count;
4440 data_offset->Uid = cpu_to_le64(uid);
4441 data_offset->Gid = cpu_to_le64(gid);
4442 /* better to leave device as zero when it is */
4443 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4444 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4445 data_offset->Permissions = cpu_to_le64(mode);
4447 if(S_ISREG(mode))
4448 data_offset->Type = cpu_to_le32(UNIX_FILE);
4449 else if(S_ISDIR(mode))
4450 data_offset->Type = cpu_to_le32(UNIX_DIR);
4451 else if(S_ISLNK(mode))
4452 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4453 else if(S_ISCHR(mode))
4454 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4455 else if(S_ISBLK(mode))
4456 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4457 else if(S_ISFIFO(mode))
4458 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4459 else if(S_ISSOCK(mode))
4460 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4463 pSMB->ByteCount = cpu_to_le16(byte_count);
4464 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4466 if (rc) {
4467 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4470 if (pSMB)
4471 cifs_buf_release(pSMB);
4472 if (rc == -EAGAIN)
4473 goto setPermsRetry;
4474 return rc;
4477 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4478 const int notify_subdirs, const __u16 netfid,
4479 __u32 filter, struct file * pfile, int multishot,
4480 const struct nls_table *nls_codepage)
4482 int rc = 0;
4483 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4484 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4485 struct dir_notify_req *dnotify_req;
4486 int bytes_returned;
4488 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4489 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4490 (void **) &pSMBr);
4491 if (rc)
4492 return rc;
4494 pSMB->TotalParameterCount = 0 ;
4495 pSMB->TotalDataCount = 0;
4496 pSMB->MaxParameterCount = cpu_to_le32(2);
4497 /* BB find exact data count max from sess structure BB */
4498 pSMB->MaxDataCount = 0; /* same in little endian or be */
4499 /* BB VERIFY verify which is correct for above BB */
4500 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4501 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4503 pSMB->MaxSetupCount = 4;
4504 pSMB->Reserved = 0;
4505 pSMB->ParameterOffset = 0;
4506 pSMB->DataCount = 0;
4507 pSMB->DataOffset = 0;
4508 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4509 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4510 pSMB->ParameterCount = pSMB->TotalParameterCount;
4511 if(notify_subdirs)
4512 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4513 pSMB->Reserved2 = 0;
4514 pSMB->CompletionFilter = cpu_to_le32(filter);
4515 pSMB->Fid = netfid; /* file handle always le */
4516 pSMB->ByteCount = 0;
4518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4519 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4520 if (rc) {
4521 cFYI(1, ("Error in Notify = %d", rc));
4522 } else {
4523 /* Add file to outstanding requests */
4524 /* BB change to kmem cache alloc */
4525 dnotify_req = (struct dir_notify_req *) kmalloc(
4526 sizeof(struct dir_notify_req),
4527 GFP_KERNEL);
4528 if(dnotify_req) {
4529 dnotify_req->Pid = pSMB->hdr.Pid;
4530 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4531 dnotify_req->Mid = pSMB->hdr.Mid;
4532 dnotify_req->Tid = pSMB->hdr.Tid;
4533 dnotify_req->Uid = pSMB->hdr.Uid;
4534 dnotify_req->netfid = netfid;
4535 dnotify_req->pfile = pfile;
4536 dnotify_req->filter = filter;
4537 dnotify_req->multishot = multishot;
4538 spin_lock(&GlobalMid_Lock);
4539 list_add_tail(&dnotify_req->lhead,
4540 &GlobalDnotifyReqList);
4541 spin_unlock(&GlobalMid_Lock);
4542 } else
4543 rc = -ENOMEM;
4545 cifs_buf_release(pSMB);
4546 return rc;
4548 #ifdef CONFIG_CIFS_XATTR
4549 ssize_t
4550 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4551 const unsigned char *searchName,
4552 char * EAData, size_t buf_size,
4553 const struct nls_table *nls_codepage, int remap)
4555 /* BB assumes one setup word */
4556 TRANSACTION2_QPI_REQ *pSMB = NULL;
4557 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4558 int rc = 0;
4559 int bytes_returned;
4560 int name_len;
4561 struct fea * temp_fea;
4562 char * temp_ptr;
4563 __u16 params, byte_count;
4565 cFYI(1, ("In Query All EAs path %s", searchName));
4566 QAllEAsRetry:
4567 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4568 (void **) &pSMBr);
4569 if (rc)
4570 return rc;
4572 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4573 name_len =
4574 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4575 PATH_MAX, nls_codepage, remap);
4576 name_len++; /* trailing null */
4577 name_len *= 2;
4578 } else { /* BB improve the check for buffer overruns BB */
4579 name_len = strnlen(searchName, PATH_MAX);
4580 name_len++; /* trailing null */
4581 strncpy(pSMB->FileName, searchName, name_len);
4584 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4585 pSMB->TotalDataCount = 0;
4586 pSMB->MaxParameterCount = cpu_to_le16(2);
4587 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4588 pSMB->MaxSetupCount = 0;
4589 pSMB->Reserved = 0;
4590 pSMB->Flags = 0;
4591 pSMB->Timeout = 0;
4592 pSMB->Reserved2 = 0;
4593 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4594 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4595 pSMB->DataCount = 0;
4596 pSMB->DataOffset = 0;
4597 pSMB->SetupCount = 1;
4598 pSMB->Reserved3 = 0;
4599 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4600 byte_count = params + 1 /* pad */ ;
4601 pSMB->TotalParameterCount = cpu_to_le16(params);
4602 pSMB->ParameterCount = pSMB->TotalParameterCount;
4603 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4604 pSMB->Reserved4 = 0;
4605 pSMB->hdr.smb_buf_length += byte_count;
4606 pSMB->ByteCount = cpu_to_le16(byte_count);
4608 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4609 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4610 if (rc) {
4611 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4612 } else { /* decode response */
4613 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4615 /* BB also check enough total bytes returned */
4616 /* BB we need to improve the validity checking
4617 of these trans2 responses */
4618 if (rc || (pSMBr->ByteCount < 4))
4619 rc = -EIO; /* bad smb */
4620 /* else if (pFindData){
4621 memcpy((char *) pFindData,
4622 (char *) &pSMBr->hdr.Protocol +
4623 data_offset, kl);
4624 }*/ else {
4625 /* check that length of list is not more than bcc */
4626 /* check that each entry does not go beyond length
4627 of list */
4628 /* check that each element of each entry does not
4629 go beyond end of list */
4630 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4631 struct fealist * ea_response_data;
4632 rc = 0;
4633 /* validate_trans2_offsets() */
4634 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4635 ea_response_data = (struct fealist *)
4636 (((char *) &pSMBr->hdr.Protocol) +
4637 data_offset);
4638 name_len = le32_to_cpu(ea_response_data->list_len);
4639 cFYI(1,("ea length %d", name_len));
4640 if(name_len <= 8) {
4641 /* returned EA size zeroed at top of function */
4642 cFYI(1,("empty EA list returned from server"));
4643 } else {
4644 /* account for ea list len */
4645 name_len -= 4;
4646 temp_fea = ea_response_data->list;
4647 temp_ptr = (char *)temp_fea;
4648 while(name_len > 0) {
4649 __u16 value_len;
4650 name_len -= 4;
4651 temp_ptr += 4;
4652 rc += temp_fea->name_len;
4653 /* account for prefix user. and trailing null */
4654 rc = rc + 5 + 1;
4655 if(rc<(int)buf_size) {
4656 memcpy(EAData,"user.",5);
4657 EAData+=5;
4658 memcpy(EAData,temp_ptr,temp_fea->name_len);
4659 EAData+=temp_fea->name_len;
4660 /* null terminate name */
4661 *EAData = 0;
4662 EAData = EAData + 1;
4663 } else if(buf_size == 0) {
4664 /* skip copy - calc size only */
4665 } else {
4666 /* stop before overrun buffer */
4667 rc = -ERANGE;
4668 break;
4670 name_len -= temp_fea->name_len;
4671 temp_ptr += temp_fea->name_len;
4672 /* account for trailing null */
4673 name_len--;
4674 temp_ptr++;
4675 value_len = le16_to_cpu(temp_fea->value_len);
4676 name_len -= value_len;
4677 temp_ptr += value_len;
4678 /* BB check that temp_ptr is still within smb BB*/
4679 /* no trailing null to account for in value len */
4680 /* go on to next EA */
4681 temp_fea = (struct fea *)temp_ptr;
4686 if (pSMB)
4687 cifs_buf_release(pSMB);
4688 if (rc == -EAGAIN)
4689 goto QAllEAsRetry;
4691 return (ssize_t)rc;
4694 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4695 const unsigned char * searchName,const unsigned char * ea_name,
4696 unsigned char * ea_value, size_t buf_size,
4697 const struct nls_table *nls_codepage, int remap)
4699 TRANSACTION2_QPI_REQ *pSMB = NULL;
4700 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4701 int rc = 0;
4702 int bytes_returned;
4703 int name_len;
4704 struct fea * temp_fea;
4705 char * temp_ptr;
4706 __u16 params, byte_count;
4708 cFYI(1, ("In Query EA path %s", searchName));
4709 QEARetry:
4710 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4711 (void **) &pSMBr);
4712 if (rc)
4713 return rc;
4715 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4716 name_len =
4717 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4718 PATH_MAX, nls_codepage, remap);
4719 name_len++; /* trailing null */
4720 name_len *= 2;
4721 } else { /* BB improve the check for buffer overruns BB */
4722 name_len = strnlen(searchName, PATH_MAX);
4723 name_len++; /* trailing null */
4724 strncpy(pSMB->FileName, searchName, name_len);
4727 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4728 pSMB->TotalDataCount = 0;
4729 pSMB->MaxParameterCount = cpu_to_le16(2);
4730 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4731 pSMB->MaxSetupCount = 0;
4732 pSMB->Reserved = 0;
4733 pSMB->Flags = 0;
4734 pSMB->Timeout = 0;
4735 pSMB->Reserved2 = 0;
4736 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4737 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4738 pSMB->DataCount = 0;
4739 pSMB->DataOffset = 0;
4740 pSMB->SetupCount = 1;
4741 pSMB->Reserved3 = 0;
4742 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4743 byte_count = params + 1 /* pad */ ;
4744 pSMB->TotalParameterCount = cpu_to_le16(params);
4745 pSMB->ParameterCount = pSMB->TotalParameterCount;
4746 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4747 pSMB->Reserved4 = 0;
4748 pSMB->hdr.smb_buf_length += byte_count;
4749 pSMB->ByteCount = cpu_to_le16(byte_count);
4751 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4752 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4753 if (rc) {
4754 cFYI(1, ("Send error in Query EA = %d", rc));
4755 } else { /* decode response */
4756 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4758 /* BB also check enough total bytes returned */
4759 /* BB we need to improve the validity checking
4760 of these trans2 responses */
4761 if (rc || (pSMBr->ByteCount < 4))
4762 rc = -EIO; /* bad smb */
4763 /* else if (pFindData){
4764 memcpy((char *) pFindData,
4765 (char *) &pSMBr->hdr.Protocol +
4766 data_offset, kl);
4767 }*/ else {
4768 /* check that length of list is not more than bcc */
4769 /* check that each entry does not go beyond length
4770 of list */
4771 /* check that each element of each entry does not
4772 go beyond end of list */
4773 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4774 struct fealist * ea_response_data;
4775 rc = -ENODATA;
4776 /* validate_trans2_offsets() */
4777 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4778 ea_response_data = (struct fealist *)
4779 (((char *) &pSMBr->hdr.Protocol) +
4780 data_offset);
4781 name_len = le32_to_cpu(ea_response_data->list_len);
4782 cFYI(1,("ea length %d", name_len));
4783 if(name_len <= 8) {
4784 /* returned EA size zeroed at top of function */
4785 cFYI(1,("empty EA list returned from server"));
4786 } else {
4787 /* account for ea list len */
4788 name_len -= 4;
4789 temp_fea = ea_response_data->list;
4790 temp_ptr = (char *)temp_fea;
4791 /* loop through checking if we have a matching
4792 name and then return the associated value */
4793 while(name_len > 0) {
4794 __u16 value_len;
4795 name_len -= 4;
4796 temp_ptr += 4;
4797 value_len = le16_to_cpu(temp_fea->value_len);
4798 /* BB validate that value_len falls within SMB,
4799 even though maximum for name_len is 255 */
4800 if(memcmp(temp_fea->name,ea_name,
4801 temp_fea->name_len) == 0) {
4802 /* found a match */
4803 rc = value_len;
4804 /* account for prefix user. and trailing null */
4805 if(rc<=(int)buf_size) {
4806 memcpy(ea_value,
4807 temp_fea->name+temp_fea->name_len+1,
4808 rc);
4809 /* ea values, unlike ea names,
4810 are not null terminated */
4811 } else if(buf_size == 0) {
4812 /* skip copy - calc size only */
4813 } else {
4814 /* stop before overrun buffer */
4815 rc = -ERANGE;
4817 break;
4819 name_len -= temp_fea->name_len;
4820 temp_ptr += temp_fea->name_len;
4821 /* account for trailing null */
4822 name_len--;
4823 temp_ptr++;
4824 name_len -= value_len;
4825 temp_ptr += value_len;
4826 /* no trailing null to account for in value len */
4827 /* go on to next EA */
4828 temp_fea = (struct fea *)temp_ptr;
4833 if (pSMB)
4834 cifs_buf_release(pSMB);
4835 if (rc == -EAGAIN)
4836 goto QEARetry;
4838 return (ssize_t)rc;
4842 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4843 const char * ea_name, const void * ea_value,
4844 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4845 int remap)
4847 struct smb_com_transaction2_spi_req *pSMB = NULL;
4848 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4849 struct fealist *parm_data;
4850 int name_len;
4851 int rc = 0;
4852 int bytes_returned = 0;
4853 __u16 params, param_offset, byte_count, offset, count;
4855 cFYI(1, ("In SetEA"));
4856 SetEARetry:
4857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4858 (void **) &pSMBr);
4859 if (rc)
4860 return rc;
4862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4863 name_len =
4864 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4865 PATH_MAX, nls_codepage, remap);
4866 name_len++; /* trailing null */
4867 name_len *= 2;
4868 } else { /* BB improve the check for buffer overruns BB */
4869 name_len = strnlen(fileName, PATH_MAX);
4870 name_len++; /* trailing null */
4871 strncpy(pSMB->FileName, fileName, name_len);
4874 params = 6 + name_len;
4876 /* done calculating parms using name_len of file name,
4877 now use name_len to calculate length of ea name
4878 we are going to create in the inode xattrs */
4879 if(ea_name == NULL)
4880 name_len = 0;
4881 else
4882 name_len = strnlen(ea_name,255);
4884 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4885 pSMB->MaxParameterCount = cpu_to_le16(2);
4886 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4887 pSMB->MaxSetupCount = 0;
4888 pSMB->Reserved = 0;
4889 pSMB->Flags = 0;
4890 pSMB->Timeout = 0;
4891 pSMB->Reserved2 = 0;
4892 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4893 InformationLevel) - 4;
4894 offset = param_offset + params;
4895 pSMB->InformationLevel =
4896 cpu_to_le16(SMB_SET_FILE_EA);
4898 parm_data =
4899 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4900 offset);
4901 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4902 pSMB->DataOffset = cpu_to_le16(offset);
4903 pSMB->SetupCount = 1;
4904 pSMB->Reserved3 = 0;
4905 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4906 byte_count = 3 /* pad */ + params + count;
4907 pSMB->DataCount = cpu_to_le16(count);
4908 parm_data->list_len = cpu_to_le32(count);
4909 parm_data->list[0].EA_flags = 0;
4910 /* we checked above that name len is less than 255 */
4911 parm_data->list[0].name_len = (__u8)name_len;;
4912 /* EA names are always ASCII */
4913 if(ea_name)
4914 strncpy(parm_data->list[0].name,ea_name,name_len);
4915 parm_data->list[0].name[name_len] = 0;
4916 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4917 /* caller ensures that ea_value_len is less than 64K but
4918 we need to ensure that it fits within the smb */
4920 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4921 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4922 if(ea_value_len)
4923 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4925 pSMB->TotalDataCount = pSMB->DataCount;
4926 pSMB->ParameterCount = cpu_to_le16(params);
4927 pSMB->TotalParameterCount = pSMB->ParameterCount;
4928 pSMB->Reserved4 = 0;
4929 pSMB->hdr.smb_buf_length += byte_count;
4930 pSMB->ByteCount = cpu_to_le16(byte_count);
4931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4933 if (rc) {
4934 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4937 cifs_buf_release(pSMB);
4939 if (rc == -EAGAIN)
4940 goto SetEARetry;
4942 return rc;
4945 #endif