[PATCH] Kprobes: Fix deadlock in function-return probes
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blob217323b0c8966ae62db2683038adcda6d53dce3b
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 /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
1052 *buf = iov[0].iov_base;
1053 if(resp_buf_type == CIFS_SMALL_BUFFER)
1054 *pbuf_type = CIFS_SMALL_BUFFER;
1055 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1056 *pbuf_type = CIFS_LARGE_BUFFER;
1059 /* Note: On -EAGAIN error only caller can retry on handle based calls
1060 since file handle passed in no longer valid */
1061 return rc;
1066 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1067 const int netfid, const unsigned int count,
1068 const __u64 offset, unsigned int *nbytes, const char *buf,
1069 const char __user * ubuf, const int long_op)
1071 int rc = -EACCES;
1072 WRITE_REQ *pSMB = NULL;
1073 WRITE_RSP *pSMBr = NULL;
1074 int bytes_returned, wct;
1075 __u32 bytes_sent;
1076 __u16 byte_count;
1078 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1079 if(tcon->ses == NULL)
1080 return -ECONNABORTED;
1082 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1083 wct = 14;
1084 else
1085 wct = 12;
1087 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1088 (void **) &pSMBr);
1089 if (rc)
1090 return rc;
1091 /* tcon and ses pointer are checked in smb_init */
1092 if (tcon->ses->server == NULL)
1093 return -ECONNABORTED;
1095 pSMB->AndXCommand = 0xFF; /* none */
1096 pSMB->Fid = netfid;
1097 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1098 if(wct == 14)
1099 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1100 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1101 return -EIO;
1103 pSMB->Reserved = 0xFFFFFFFF;
1104 pSMB->WriteMode = 0;
1105 pSMB->Remaining = 0;
1107 /* Can increase buffer size if buffer is big enough in some cases - ie we
1108 can send more if LARGE_WRITE_X capability returned by the server and if
1109 our buffer is big enough or if we convert to iovecs on socket writes
1110 and eliminate the copy to the CIFS buffer */
1111 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1112 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1113 } else {
1114 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1115 & ~0xFF;
1118 if (bytes_sent > count)
1119 bytes_sent = count;
1120 pSMB->DataOffset =
1121 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1122 if(buf)
1123 memcpy(pSMB->Data,buf,bytes_sent);
1124 else if(ubuf) {
1125 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1126 cifs_buf_release(pSMB);
1127 return -EFAULT;
1129 } else if (count != 0) {
1130 /* No buffer */
1131 cifs_buf_release(pSMB);
1132 return -EINVAL;
1133 } /* else setting file size with write of zero bytes */
1134 if(wct == 14)
1135 byte_count = bytes_sent + 1; /* pad */
1136 else /* wct == 12 */ {
1137 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1139 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1140 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1141 pSMB->hdr.smb_buf_length += byte_count;
1143 if(wct == 14)
1144 pSMB->ByteCount = cpu_to_le16(byte_count);
1145 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
1146 struct smb_com_writex_req * pSMBW =
1147 (struct smb_com_writex_req *)pSMB;
1148 pSMBW->ByteCount = cpu_to_le16(byte_count);
1151 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1152 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1153 cifs_stats_inc(&tcon->num_writes);
1154 if (rc) {
1155 cFYI(1, ("Send error in write = %d", rc));
1156 *nbytes = 0;
1157 } else {
1158 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1159 *nbytes = (*nbytes) << 16;
1160 *nbytes += le16_to_cpu(pSMBr->Count);
1163 cifs_buf_release(pSMB);
1165 /* Note: On -EAGAIN error only caller can retry on handle based calls
1166 since file handle passed in no longer valid */
1168 return rc;
1172 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1173 const int netfid, const unsigned int count,
1174 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1175 int n_vec, const int long_op)
1177 int rc = -EACCES;
1178 WRITE_REQ *pSMB = NULL;
1179 int wct;
1180 int smb_hdr_len;
1181 int resp_buf_type = 0;
1183 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1185 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1186 wct = 14;
1187 else
1188 wct = 12;
1189 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1190 if (rc)
1191 return rc;
1192 /* tcon and ses pointer are checked in smb_init */
1193 if (tcon->ses->server == NULL)
1194 return -ECONNABORTED;
1196 pSMB->AndXCommand = 0xFF; /* none */
1197 pSMB->Fid = netfid;
1198 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1199 if(wct == 14)
1200 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1201 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1202 return -EIO;
1203 pSMB->Reserved = 0xFFFFFFFF;
1204 pSMB->WriteMode = 0;
1205 pSMB->Remaining = 0;
1207 pSMB->DataOffset =
1208 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1210 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1211 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1212 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1213 if(wct == 14)
1214 pSMB->hdr.smb_buf_length += count+1;
1215 else /* wct == 12 */
1216 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1217 if(wct == 14)
1218 pSMB->ByteCount = cpu_to_le16(count + 1);
1219 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1220 struct smb_com_writex_req * pSMBW =
1221 (struct smb_com_writex_req *)pSMB;
1222 pSMBW->ByteCount = cpu_to_le16(count + 5);
1224 iov[0].iov_base = pSMB;
1225 if(wct == 14)
1226 iov[0].iov_len = smb_hdr_len + 4;
1227 else /* wct == 12 pad bigger by four bytes */
1228 iov[0].iov_len = smb_hdr_len + 8;
1231 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1232 long_op);
1233 cifs_stats_inc(&tcon->num_writes);
1234 if (rc) {
1235 cFYI(1, ("Send error Write2 = %d", rc));
1236 *nbytes = 0;
1237 } else if(resp_buf_type == 0) {
1238 /* presumably this can not happen, but best to be safe */
1239 rc = -EIO;
1240 *nbytes = 0;
1241 } else {
1242 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1243 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1244 *nbytes = (*nbytes) << 16;
1245 *nbytes += le16_to_cpu(pSMBr->Count);
1248 cifs_small_buf_release(pSMB);
1249 if(resp_buf_type == CIFS_SMALL_BUFFER)
1250 cifs_small_buf_release(iov[0].iov_base);
1251 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1252 cifs_buf_release(iov[0].iov_base);
1254 /* Note: On -EAGAIN error only caller can retry on handle based calls
1255 since file handle passed in no longer valid */
1257 return rc;
1262 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1263 const __u16 smb_file_id, const __u64 len,
1264 const __u64 offset, const __u32 numUnlock,
1265 const __u32 numLock, const __u8 lockType, const int waitFlag)
1267 int rc = 0;
1268 LOCK_REQ *pSMB = NULL;
1269 LOCK_RSP *pSMBr = NULL;
1270 int bytes_returned;
1271 int timeout = 0;
1272 __u16 count;
1274 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1275 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1277 if (rc)
1278 return rc;
1280 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1282 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1283 timeout = -1; /* no response expected */
1284 pSMB->Timeout = 0;
1285 } else if (waitFlag == TRUE) {
1286 timeout = 3; /* blocking operation, no timeout */
1287 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1288 } else {
1289 pSMB->Timeout = 0;
1292 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1293 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1294 pSMB->LockType = lockType;
1295 pSMB->AndXCommand = 0xFF; /* none */
1296 pSMB->Fid = smb_file_id; /* netfid stays le */
1298 if((numLock != 0) || (numUnlock != 0)) {
1299 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1300 /* BB where to store pid high? */
1301 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1302 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1303 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1304 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1305 count = sizeof(LOCKING_ANDX_RANGE);
1306 } else {
1307 /* oplock break */
1308 count = 0;
1310 pSMB->hdr.smb_buf_length += count;
1311 pSMB->ByteCount = cpu_to_le16(count);
1313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1314 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1315 cifs_stats_inc(&tcon->num_locks);
1316 if (rc) {
1317 cFYI(1, ("Send error in Lock = %d", rc));
1319 cifs_small_buf_release(pSMB);
1321 /* Note: On -EAGAIN error only caller can retry on handle based calls
1322 since file handle passed in no longer valid */
1323 return rc;
1327 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1329 int rc = 0;
1330 CLOSE_REQ *pSMB = NULL;
1331 CLOSE_RSP *pSMBr = NULL;
1332 int bytes_returned;
1333 cFYI(1, ("In CIFSSMBClose"));
1335 /* do not retry on dead session on close */
1336 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1337 if(rc == -EAGAIN)
1338 return 0;
1339 if (rc)
1340 return rc;
1342 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1344 pSMB->FileID = (__u16) smb_file_id;
1345 pSMB->LastWriteTime = 0;
1346 pSMB->ByteCount = 0;
1347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1349 cifs_stats_inc(&tcon->num_closes);
1350 if (rc) {
1351 if(rc!=-EINTR) {
1352 /* EINTR is expected when user ctl-c to kill app */
1353 cERROR(1, ("Send error in Close = %d", rc));
1357 cifs_small_buf_release(pSMB);
1359 /* Since session is dead, file will be closed on server already */
1360 if(rc == -EAGAIN)
1361 rc = 0;
1363 return rc;
1367 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1368 const char *fromName, const char *toName,
1369 const struct nls_table *nls_codepage, int remap)
1371 int rc = 0;
1372 RENAME_REQ *pSMB = NULL;
1373 RENAME_RSP *pSMBr = NULL;
1374 int bytes_returned;
1375 int name_len, name_len2;
1376 __u16 count;
1378 cFYI(1, ("In CIFSSMBRename"));
1379 renameRetry:
1380 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1381 (void **) &pSMBr);
1382 if (rc)
1383 return rc;
1385 pSMB->BufferFormat = 0x04;
1386 pSMB->SearchAttributes =
1387 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1388 ATTR_DIRECTORY);
1390 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1391 name_len =
1392 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1393 PATH_MAX, nls_codepage, remap);
1394 name_len++; /* trailing null */
1395 name_len *= 2;
1396 pSMB->OldFileName[name_len] = 0x04; /* pad */
1397 /* protocol requires ASCII signature byte on Unicode string */
1398 pSMB->OldFileName[name_len + 1] = 0x00;
1399 name_len2 =
1400 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1401 toName, PATH_MAX, nls_codepage, remap);
1402 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1403 name_len2 *= 2; /* convert to bytes */
1404 } else { /* BB improve the check for buffer overruns BB */
1405 name_len = strnlen(fromName, PATH_MAX);
1406 name_len++; /* trailing null */
1407 strncpy(pSMB->OldFileName, fromName, name_len);
1408 name_len2 = strnlen(toName, PATH_MAX);
1409 name_len2++; /* trailing null */
1410 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1411 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1412 name_len2++; /* trailing null */
1413 name_len2++; /* signature byte */
1416 count = 1 /* 1st signature byte */ + name_len + name_len2;
1417 pSMB->hdr.smb_buf_length += count;
1418 pSMB->ByteCount = cpu_to_le16(count);
1420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1422 cifs_stats_inc(&tcon->num_renames);
1423 if (rc) {
1424 cFYI(1, ("Send error in rename = %d", rc));
1427 cifs_buf_release(pSMB);
1429 if (rc == -EAGAIN)
1430 goto renameRetry;
1432 return rc;
1435 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1436 int netfid, char * target_name,
1437 const struct nls_table * nls_codepage, int remap)
1439 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1440 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1441 struct set_file_rename * rename_info;
1442 char *data_offset;
1443 char dummy_string[30];
1444 int rc = 0;
1445 int bytes_returned = 0;
1446 int len_of_str;
1447 __u16 params, param_offset, offset, count, byte_count;
1449 cFYI(1, ("Rename to File by handle"));
1450 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1451 (void **) &pSMBr);
1452 if (rc)
1453 return rc;
1455 params = 6;
1456 pSMB->MaxSetupCount = 0;
1457 pSMB->Reserved = 0;
1458 pSMB->Flags = 0;
1459 pSMB->Timeout = 0;
1460 pSMB->Reserved2 = 0;
1461 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1462 offset = param_offset + params;
1464 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1465 rename_info = (struct set_file_rename *) data_offset;
1466 pSMB->MaxParameterCount = cpu_to_le16(2);
1467 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1468 pSMB->SetupCount = 1;
1469 pSMB->Reserved3 = 0;
1470 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1471 byte_count = 3 /* pad */ + params;
1472 pSMB->ParameterCount = cpu_to_le16(params);
1473 pSMB->TotalParameterCount = pSMB->ParameterCount;
1474 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1475 pSMB->DataOffset = cpu_to_le16(offset);
1476 /* construct random name ".cifs_tmp<inodenum><mid>" */
1477 rename_info->overwrite = cpu_to_le32(1);
1478 rename_info->root_fid = 0;
1479 /* unicode only call */
1480 if(target_name == NULL) {
1481 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1482 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1483 dummy_string, 24, nls_codepage, remap);
1484 } else {
1485 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1486 target_name, PATH_MAX, nls_codepage, remap);
1488 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1489 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1490 byte_count += count;
1491 pSMB->DataCount = cpu_to_le16(count);
1492 pSMB->TotalDataCount = pSMB->DataCount;
1493 pSMB->Fid = netfid;
1494 pSMB->InformationLevel =
1495 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1496 pSMB->Reserved4 = 0;
1497 pSMB->hdr.smb_buf_length += byte_count;
1498 pSMB->ByteCount = cpu_to_le16(byte_count);
1499 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1501 cifs_stats_inc(&pTcon->num_t2renames);
1502 if (rc) {
1503 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1506 cifs_buf_release(pSMB);
1508 /* Note: On -EAGAIN error only caller can retry on handle based calls
1509 since file handle passed in no longer valid */
1511 return rc;
1515 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1516 const __u16 target_tid, const char *toName, const int flags,
1517 const struct nls_table *nls_codepage, int remap)
1519 int rc = 0;
1520 COPY_REQ *pSMB = NULL;
1521 COPY_RSP *pSMBr = NULL;
1522 int bytes_returned;
1523 int name_len, name_len2;
1524 __u16 count;
1526 cFYI(1, ("In CIFSSMBCopy"));
1527 copyRetry:
1528 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1529 (void **) &pSMBr);
1530 if (rc)
1531 return rc;
1533 pSMB->BufferFormat = 0x04;
1534 pSMB->Tid2 = target_tid;
1536 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1538 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1539 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1540 fromName, PATH_MAX, nls_codepage,
1541 remap);
1542 name_len++; /* trailing null */
1543 name_len *= 2;
1544 pSMB->OldFileName[name_len] = 0x04; /* pad */
1545 /* protocol requires ASCII signature byte on Unicode string */
1546 pSMB->OldFileName[name_len + 1] = 0x00;
1547 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1548 toName, PATH_MAX, nls_codepage, remap);
1549 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1550 name_len2 *= 2; /* convert to bytes */
1551 } else { /* BB improve the check for buffer overruns BB */
1552 name_len = strnlen(fromName, PATH_MAX);
1553 name_len++; /* trailing null */
1554 strncpy(pSMB->OldFileName, fromName, name_len);
1555 name_len2 = strnlen(toName, PATH_MAX);
1556 name_len2++; /* trailing null */
1557 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1558 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1559 name_len2++; /* trailing null */
1560 name_len2++; /* signature byte */
1563 count = 1 /* 1st signature byte */ + name_len + name_len2;
1564 pSMB->hdr.smb_buf_length += count;
1565 pSMB->ByteCount = cpu_to_le16(count);
1567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1569 if (rc) {
1570 cFYI(1, ("Send error in copy = %d with %d files copied",
1571 rc, le16_to_cpu(pSMBr->CopyCount)));
1573 if (pSMB)
1574 cifs_buf_release(pSMB);
1576 if (rc == -EAGAIN)
1577 goto copyRetry;
1579 return rc;
1583 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1584 const char *fromName, const char *toName,
1585 const struct nls_table *nls_codepage)
1587 TRANSACTION2_SPI_REQ *pSMB = NULL;
1588 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1589 char *data_offset;
1590 int name_len;
1591 int name_len_target;
1592 int rc = 0;
1593 int bytes_returned = 0;
1594 __u16 params, param_offset, offset, byte_count;
1596 cFYI(1, ("In Symlink Unix style"));
1597 createSymLinkRetry:
1598 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1599 (void **) &pSMBr);
1600 if (rc)
1601 return rc;
1603 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1604 name_len =
1605 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1606 /* find define for this maxpathcomponent */
1607 , nls_codepage);
1608 name_len++; /* trailing null */
1609 name_len *= 2;
1611 } else { /* BB improve the check for buffer overruns BB */
1612 name_len = strnlen(fromName, PATH_MAX);
1613 name_len++; /* trailing null */
1614 strncpy(pSMB->FileName, fromName, name_len);
1616 params = 6 + name_len;
1617 pSMB->MaxSetupCount = 0;
1618 pSMB->Reserved = 0;
1619 pSMB->Flags = 0;
1620 pSMB->Timeout = 0;
1621 pSMB->Reserved2 = 0;
1622 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1623 InformationLevel) - 4;
1624 offset = param_offset + params;
1626 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1627 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1628 name_len_target =
1629 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1630 /* find define for this maxpathcomponent */
1631 , nls_codepage);
1632 name_len_target++; /* trailing null */
1633 name_len_target *= 2;
1634 } else { /* BB improve the check for buffer overruns BB */
1635 name_len_target = strnlen(toName, PATH_MAX);
1636 name_len_target++; /* trailing null */
1637 strncpy(data_offset, toName, name_len_target);
1640 pSMB->MaxParameterCount = cpu_to_le16(2);
1641 /* BB find exact max on data count below from sess */
1642 pSMB->MaxDataCount = cpu_to_le16(1000);
1643 pSMB->SetupCount = 1;
1644 pSMB->Reserved3 = 0;
1645 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1646 byte_count = 3 /* pad */ + params + name_len_target;
1647 pSMB->DataCount = cpu_to_le16(name_len_target);
1648 pSMB->ParameterCount = cpu_to_le16(params);
1649 pSMB->TotalDataCount = pSMB->DataCount;
1650 pSMB->TotalParameterCount = pSMB->ParameterCount;
1651 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1652 pSMB->DataOffset = cpu_to_le16(offset);
1653 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1654 pSMB->Reserved4 = 0;
1655 pSMB->hdr.smb_buf_length += byte_count;
1656 pSMB->ByteCount = cpu_to_le16(byte_count);
1657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1659 cifs_stats_inc(&tcon->num_symlinks);
1660 if (rc) {
1661 cFYI(1,
1662 ("Send error in SetPathInfo (create symlink) = %d",
1663 rc));
1666 if (pSMB)
1667 cifs_buf_release(pSMB);
1669 if (rc == -EAGAIN)
1670 goto createSymLinkRetry;
1672 return rc;
1676 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1677 const char *fromName, const char *toName,
1678 const struct nls_table *nls_codepage, int remap)
1680 TRANSACTION2_SPI_REQ *pSMB = NULL;
1681 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1682 char *data_offset;
1683 int name_len;
1684 int name_len_target;
1685 int rc = 0;
1686 int bytes_returned = 0;
1687 __u16 params, param_offset, offset, byte_count;
1689 cFYI(1, ("In Create Hard link Unix style"));
1690 createHardLinkRetry:
1691 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1692 (void **) &pSMBr);
1693 if (rc)
1694 return rc;
1696 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1697 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1698 PATH_MAX, nls_codepage, remap);
1699 name_len++; /* trailing null */
1700 name_len *= 2;
1702 } else { /* BB improve the check for buffer overruns BB */
1703 name_len = strnlen(toName, PATH_MAX);
1704 name_len++; /* trailing null */
1705 strncpy(pSMB->FileName, toName, name_len);
1707 params = 6 + name_len;
1708 pSMB->MaxSetupCount = 0;
1709 pSMB->Reserved = 0;
1710 pSMB->Flags = 0;
1711 pSMB->Timeout = 0;
1712 pSMB->Reserved2 = 0;
1713 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1714 InformationLevel) - 4;
1715 offset = param_offset + params;
1717 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1718 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1719 name_len_target =
1720 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1721 nls_codepage, remap);
1722 name_len_target++; /* trailing null */
1723 name_len_target *= 2;
1724 } else { /* BB improve the check for buffer overruns BB */
1725 name_len_target = strnlen(fromName, PATH_MAX);
1726 name_len_target++; /* trailing null */
1727 strncpy(data_offset, fromName, name_len_target);
1730 pSMB->MaxParameterCount = cpu_to_le16(2);
1731 /* BB find exact max on data count below from sess*/
1732 pSMB->MaxDataCount = cpu_to_le16(1000);
1733 pSMB->SetupCount = 1;
1734 pSMB->Reserved3 = 0;
1735 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1736 byte_count = 3 /* pad */ + params + name_len_target;
1737 pSMB->ParameterCount = cpu_to_le16(params);
1738 pSMB->TotalParameterCount = pSMB->ParameterCount;
1739 pSMB->DataCount = cpu_to_le16(name_len_target);
1740 pSMB->TotalDataCount = pSMB->DataCount;
1741 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1742 pSMB->DataOffset = cpu_to_le16(offset);
1743 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1744 pSMB->Reserved4 = 0;
1745 pSMB->hdr.smb_buf_length += byte_count;
1746 pSMB->ByteCount = cpu_to_le16(byte_count);
1747 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1748 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1749 cifs_stats_inc(&tcon->num_hardlinks);
1750 if (rc) {
1751 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1754 cifs_buf_release(pSMB);
1755 if (rc == -EAGAIN)
1756 goto createHardLinkRetry;
1758 return rc;
1762 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1763 const char *fromName, const char *toName,
1764 const struct nls_table *nls_codepage, int remap)
1766 int rc = 0;
1767 NT_RENAME_REQ *pSMB = NULL;
1768 RENAME_RSP *pSMBr = NULL;
1769 int bytes_returned;
1770 int name_len, name_len2;
1771 __u16 count;
1773 cFYI(1, ("In CIFSCreateHardLink"));
1774 winCreateHardLinkRetry:
1776 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1777 (void **) &pSMBr);
1778 if (rc)
1779 return rc;
1781 pSMB->SearchAttributes =
1782 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1783 ATTR_DIRECTORY);
1784 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1785 pSMB->ClusterCount = 0;
1787 pSMB->BufferFormat = 0x04;
1789 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1790 name_len =
1791 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1792 PATH_MAX, nls_codepage, remap);
1793 name_len++; /* trailing null */
1794 name_len *= 2;
1795 pSMB->OldFileName[name_len] = 0; /* pad */
1796 pSMB->OldFileName[name_len + 1] = 0x04;
1797 name_len2 =
1798 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1799 toName, PATH_MAX, nls_codepage, remap);
1800 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1801 name_len2 *= 2; /* convert to bytes */
1802 } else { /* BB improve the check for buffer overruns BB */
1803 name_len = strnlen(fromName, PATH_MAX);
1804 name_len++; /* trailing null */
1805 strncpy(pSMB->OldFileName, fromName, name_len);
1806 name_len2 = strnlen(toName, PATH_MAX);
1807 name_len2++; /* trailing null */
1808 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1809 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1810 name_len2++; /* trailing null */
1811 name_len2++; /* signature byte */
1814 count = 1 /* string type byte */ + name_len + name_len2;
1815 pSMB->hdr.smb_buf_length += count;
1816 pSMB->ByteCount = cpu_to_le16(count);
1818 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1819 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1820 cifs_stats_inc(&tcon->num_hardlinks);
1821 if (rc) {
1822 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1824 cifs_buf_release(pSMB);
1825 if (rc == -EAGAIN)
1826 goto winCreateHardLinkRetry;
1828 return rc;
1832 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1833 const unsigned char *searchName,
1834 char *symlinkinfo, const int buflen,
1835 const struct nls_table *nls_codepage)
1837 /* SMB_QUERY_FILE_UNIX_LINK */
1838 TRANSACTION2_QPI_REQ *pSMB = NULL;
1839 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1840 int rc = 0;
1841 int bytes_returned;
1842 int name_len;
1843 __u16 params, byte_count;
1845 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1847 querySymLinkRetry:
1848 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1849 (void **) &pSMBr);
1850 if (rc)
1851 return rc;
1853 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1854 name_len =
1855 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1856 /* find define for this maxpathcomponent */
1857 , nls_codepage);
1858 name_len++; /* trailing null */
1859 name_len *= 2;
1860 } else { /* BB improve the check for buffer overruns BB */
1861 name_len = strnlen(searchName, PATH_MAX);
1862 name_len++; /* trailing null */
1863 strncpy(pSMB->FileName, searchName, name_len);
1866 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1867 pSMB->TotalDataCount = 0;
1868 pSMB->MaxParameterCount = cpu_to_le16(2);
1869 /* BB find exact max data count below from sess structure BB */
1870 pSMB->MaxDataCount = cpu_to_le16(4000);
1871 pSMB->MaxSetupCount = 0;
1872 pSMB->Reserved = 0;
1873 pSMB->Flags = 0;
1874 pSMB->Timeout = 0;
1875 pSMB->Reserved2 = 0;
1876 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1877 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1878 pSMB->DataCount = 0;
1879 pSMB->DataOffset = 0;
1880 pSMB->SetupCount = 1;
1881 pSMB->Reserved3 = 0;
1882 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1883 byte_count = params + 1 /* pad */ ;
1884 pSMB->TotalParameterCount = cpu_to_le16(params);
1885 pSMB->ParameterCount = pSMB->TotalParameterCount;
1886 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1887 pSMB->Reserved4 = 0;
1888 pSMB->hdr.smb_buf_length += byte_count;
1889 pSMB->ByteCount = cpu_to_le16(byte_count);
1891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1893 if (rc) {
1894 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1895 } else {
1896 /* decode response */
1898 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1899 if (rc || (pSMBr->ByteCount < 2))
1900 /* BB also check enough total bytes returned */
1901 rc = -EIO; /* bad smb */
1902 else {
1903 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1904 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1906 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1907 name_len = UniStrnlen((wchar_t *) ((char *)
1908 &pSMBr->hdr.Protocol +data_offset),
1909 min_t(const int, buflen,count) / 2);
1910 /* BB FIXME investigate remapping reserved chars here */
1911 cifs_strfromUCS_le(symlinkinfo,
1912 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
1913 data_offset),
1914 name_len, nls_codepage);
1915 } else {
1916 strncpy(symlinkinfo,
1917 (char *) &pSMBr->hdr.Protocol +
1918 data_offset,
1919 min_t(const int, buflen, count));
1921 symlinkinfo[buflen] = 0;
1922 /* just in case so calling code does not go off the end of buffer */
1925 cifs_buf_release(pSMB);
1926 if (rc == -EAGAIN)
1927 goto querySymLinkRetry;
1928 return rc;
1931 /* Initialize NT TRANSACT SMB into small smb request buffer.
1932 This assumes that all NT TRANSACTS that we init here have
1933 total parm and data under about 400 bytes (to fit in small cifs
1934 buffer size), which is the case so far, it easily fits. NB:
1935 Setup words themselves and ByteCount
1936 MaxSetupCount (size of returned setup area) and
1937 MaxParameterCount (returned parms size) must be set by caller */
1938 static int
1939 smb_init_ntransact(const __u16 sub_command, const int setup_count,
1940 const int parm_len, struct cifsTconInfo *tcon,
1941 void ** ret_buf)
1943 int rc;
1944 __u32 temp_offset;
1945 struct smb_com_ntransact_req * pSMB;
1947 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1948 (void **)&pSMB);
1949 if (rc)
1950 return rc;
1951 *ret_buf = (void *)pSMB;
1952 pSMB->Reserved = 0;
1953 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1954 pSMB->TotalDataCount = 0;
1955 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1956 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1957 pSMB->ParameterCount = pSMB->TotalParameterCount;
1958 pSMB->DataCount = pSMB->TotalDataCount;
1959 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1960 (setup_count * 2) - 4 /* for rfc1001 length itself */;
1961 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1962 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1963 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1964 pSMB->SubCommand = cpu_to_le16(sub_command);
1965 return 0;
1968 static int
1969 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1970 int * pdatalen, int * pparmlen)
1972 char * end_of_smb;
1973 __u32 data_count, data_offset, parm_count, parm_offset;
1974 struct smb_com_ntransact_rsp * pSMBr;
1976 if(buf == NULL)
1977 return -EINVAL;
1979 pSMBr = (struct smb_com_ntransact_rsp *)buf;
1981 /* ByteCount was converted from little endian in SendReceive */
1982 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
1983 (char *)&pSMBr->ByteCount;
1986 data_offset = le32_to_cpu(pSMBr->DataOffset);
1987 data_count = le32_to_cpu(pSMBr->DataCount);
1988 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
1989 parm_count = le32_to_cpu(pSMBr->ParameterCount);
1991 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
1992 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
1994 /* should we also check that parm and data areas do not overlap? */
1995 if(*ppparm > end_of_smb) {
1996 cFYI(1,("parms start after end of smb"));
1997 return -EINVAL;
1998 } else if(parm_count + *ppparm > end_of_smb) {
1999 cFYI(1,("parm end after end of smb"));
2000 return -EINVAL;
2001 } else if(*ppdata > end_of_smb) {
2002 cFYI(1,("data starts after end of smb"));
2003 return -EINVAL;
2004 } else if(data_count + *ppdata > end_of_smb) {
2005 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2006 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2007 return -EINVAL;
2008 } else if(parm_count + data_count > pSMBr->ByteCount) {
2009 cFYI(1,("parm count and data count larger than SMB"));
2010 return -EINVAL;
2012 return 0;
2016 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2017 const unsigned char *searchName,
2018 char *symlinkinfo, const int buflen,__u16 fid,
2019 const struct nls_table *nls_codepage)
2021 int rc = 0;
2022 int bytes_returned;
2023 int name_len;
2024 struct smb_com_transaction_ioctl_req * pSMB;
2025 struct smb_com_transaction_ioctl_rsp * pSMBr;
2027 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2028 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2029 (void **) &pSMBr);
2030 if (rc)
2031 return rc;
2033 pSMB->TotalParameterCount = 0 ;
2034 pSMB->TotalDataCount = 0;
2035 pSMB->MaxParameterCount = cpu_to_le32(2);
2036 /* BB find exact data count max from sess structure BB */
2037 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2038 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2039 pSMB->MaxSetupCount = 4;
2040 pSMB->Reserved = 0;
2041 pSMB->ParameterOffset = 0;
2042 pSMB->DataCount = 0;
2043 pSMB->DataOffset = 0;
2044 pSMB->SetupCount = 4;
2045 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2046 pSMB->ParameterCount = pSMB->TotalParameterCount;
2047 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2048 pSMB->IsFsctl = 1; /* FSCTL */
2049 pSMB->IsRootFlag = 0;
2050 pSMB->Fid = fid; /* file handle always le */
2051 pSMB->ByteCount = 0;
2053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2055 if (rc) {
2056 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2057 } else { /* decode response */
2058 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2059 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2060 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2061 /* BB also check enough total bytes returned */
2062 rc = -EIO; /* bad smb */
2063 else {
2064 if(data_count && (data_count < 2048)) {
2065 char * end_of_smb = 2 /* sizeof byte count */ +
2066 pSMBr->ByteCount +
2067 (char *)&pSMBr->ByteCount;
2069 struct reparse_data * reparse_buf = (struct reparse_data *)
2070 ((char *)&pSMBr->hdr.Protocol + data_offset);
2071 if((char*)reparse_buf >= end_of_smb) {
2072 rc = -EIO;
2073 goto qreparse_out;
2075 if((reparse_buf->LinkNamesBuf +
2076 reparse_buf->TargetNameOffset +
2077 reparse_buf->TargetNameLen) >
2078 end_of_smb) {
2079 cFYI(1,("reparse buf extended beyond SMB"));
2080 rc = -EIO;
2081 goto qreparse_out;
2084 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2085 name_len = UniStrnlen((wchar_t *)
2086 (reparse_buf->LinkNamesBuf +
2087 reparse_buf->TargetNameOffset),
2088 min(buflen/2, reparse_buf->TargetNameLen / 2));
2089 cifs_strfromUCS_le(symlinkinfo,
2090 (__le16 *) (reparse_buf->LinkNamesBuf +
2091 reparse_buf->TargetNameOffset),
2092 name_len, nls_codepage);
2093 } else { /* ASCII names */
2094 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2095 reparse_buf->TargetNameOffset,
2096 min_t(const int, buflen, reparse_buf->TargetNameLen));
2098 } else {
2099 rc = -EIO;
2100 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2102 symlinkinfo[buflen] = 0; /* just in case so the caller
2103 does not go off the end of the buffer */
2104 cFYI(1,("readlink result - %s ",symlinkinfo));
2107 qreparse_out:
2108 cifs_buf_release(pSMB);
2110 /* Note: On -EAGAIN error only caller can retry on handle based calls
2111 since file handle passed in no longer valid */
2113 return rc;
2116 #ifdef CONFIG_CIFS_POSIX
2118 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2119 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2121 /* u8 cifs fields do not need le conversion */
2122 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2123 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2124 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2125 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2127 return;
2130 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2131 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2132 const int acl_type,const int size_of_data_area)
2134 int size = 0;
2135 int i;
2136 __u16 count;
2137 struct cifs_posix_ace * pACE;
2138 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2139 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2141 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2142 return -EOPNOTSUPP;
2144 if(acl_type & ACL_TYPE_ACCESS) {
2145 count = le16_to_cpu(cifs_acl->access_entry_count);
2146 pACE = &cifs_acl->ace_array[0];
2147 size = sizeof(struct cifs_posix_acl);
2148 size += sizeof(struct cifs_posix_ace) * count;
2149 /* check if we would go beyond end of SMB */
2150 if(size_of_data_area < size) {
2151 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2152 return -EINVAL;
2154 } else if(acl_type & ACL_TYPE_DEFAULT) {
2155 count = le16_to_cpu(cifs_acl->access_entry_count);
2156 size = sizeof(struct cifs_posix_acl);
2157 size += sizeof(struct cifs_posix_ace) * count;
2158 /* skip past access ACEs to get to default ACEs */
2159 pACE = &cifs_acl->ace_array[count];
2160 count = le16_to_cpu(cifs_acl->default_entry_count);
2161 size += sizeof(struct cifs_posix_ace) * count;
2162 /* check if we would go beyond end of SMB */
2163 if(size_of_data_area < size)
2164 return -EINVAL;
2165 } else {
2166 /* illegal type */
2167 return -EINVAL;
2170 size = posix_acl_xattr_size(count);
2171 if((buflen == 0) || (local_acl == NULL)) {
2172 /* used to query ACL EA size */
2173 } else if(size > buflen) {
2174 return -ERANGE;
2175 } else /* buffer big enough */ {
2176 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2177 for(i = 0;i < count ;i++) {
2178 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2179 pACE ++;
2182 return size;
2185 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2186 const posix_acl_xattr_entry * local_ace)
2188 __u16 rc = 0; /* 0 = ACL converted ok */
2190 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2191 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2192 /* BB is there a better way to handle the large uid? */
2193 if(local_ace->e_id == cpu_to_le32(-1)) {
2194 /* Probably no need to le convert -1 on any arch but can not hurt */
2195 cifs_ace->cifs_uid = cpu_to_le64(-1);
2196 } else
2197 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2198 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2199 return rc;
2202 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2203 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2204 const int acl_type)
2206 __u16 rc = 0;
2207 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2208 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2209 int count;
2210 int i;
2212 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2213 return 0;
2215 count = posix_acl_xattr_count((size_t)buflen);
2216 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2217 count, buflen, le32_to_cpu(local_acl->a_version)));
2218 if(le32_to_cpu(local_acl->a_version) != 2) {
2219 cFYI(1,("unknown POSIX ACL version %d",
2220 le32_to_cpu(local_acl->a_version)));
2221 return 0;
2223 cifs_acl->version = cpu_to_le16(1);
2224 if(acl_type == ACL_TYPE_ACCESS)
2225 cifs_acl->access_entry_count = cpu_to_le16(count);
2226 else if(acl_type == ACL_TYPE_DEFAULT)
2227 cifs_acl->default_entry_count = cpu_to_le16(count);
2228 else {
2229 cFYI(1,("unknown ACL type %d",acl_type));
2230 return 0;
2232 for(i=0;i<count;i++) {
2233 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2234 &local_acl->a_entries[i]);
2235 if(rc != 0) {
2236 /* ACE not converted */
2237 break;
2240 if(rc == 0) {
2241 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2242 rc += sizeof(struct cifs_posix_acl);
2243 /* BB add check to make sure ACL does not overflow SMB */
2245 return rc;
2249 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2250 const unsigned char *searchName,
2251 char *acl_inf, const int buflen, const int acl_type,
2252 const struct nls_table *nls_codepage, int remap)
2254 /* SMB_QUERY_POSIX_ACL */
2255 TRANSACTION2_QPI_REQ *pSMB = NULL;
2256 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2257 int rc = 0;
2258 int bytes_returned;
2259 int name_len;
2260 __u16 params, byte_count;
2262 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2264 queryAclRetry:
2265 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2266 (void **) &pSMBr);
2267 if (rc)
2268 return rc;
2270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271 name_len =
2272 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2273 PATH_MAX, nls_codepage, remap);
2274 name_len++; /* trailing null */
2275 name_len *= 2;
2276 pSMB->FileName[name_len] = 0;
2277 pSMB->FileName[name_len+1] = 0;
2278 } else { /* BB improve the check for buffer overruns BB */
2279 name_len = strnlen(searchName, PATH_MAX);
2280 name_len++; /* trailing null */
2281 strncpy(pSMB->FileName, searchName, name_len);
2284 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2285 pSMB->TotalDataCount = 0;
2286 pSMB->MaxParameterCount = cpu_to_le16(2);
2287 /* BB find exact max data count below from sess structure BB */
2288 pSMB->MaxDataCount = cpu_to_le16(4000);
2289 pSMB->MaxSetupCount = 0;
2290 pSMB->Reserved = 0;
2291 pSMB->Flags = 0;
2292 pSMB->Timeout = 0;
2293 pSMB->Reserved2 = 0;
2294 pSMB->ParameterOffset = cpu_to_le16(
2295 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2296 pSMB->DataCount = 0;
2297 pSMB->DataOffset = 0;
2298 pSMB->SetupCount = 1;
2299 pSMB->Reserved3 = 0;
2300 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2301 byte_count = params + 1 /* pad */ ;
2302 pSMB->TotalParameterCount = cpu_to_le16(params);
2303 pSMB->ParameterCount = pSMB->TotalParameterCount;
2304 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2305 pSMB->Reserved4 = 0;
2306 pSMB->hdr.smb_buf_length += byte_count;
2307 pSMB->ByteCount = cpu_to_le16(byte_count);
2309 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2310 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2311 cifs_stats_inc(&tcon->num_acl_get);
2312 if (rc) {
2313 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2314 } else {
2315 /* decode response */
2317 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2318 if (rc || (pSMBr->ByteCount < 2))
2319 /* BB also check enough total bytes returned */
2320 rc = -EIO; /* bad smb */
2321 else {
2322 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2323 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2324 rc = cifs_copy_posix_acl(acl_inf,
2325 (char *)&pSMBr->hdr.Protocol+data_offset,
2326 buflen,acl_type,count);
2329 cifs_buf_release(pSMB);
2330 if (rc == -EAGAIN)
2331 goto queryAclRetry;
2332 return rc;
2336 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2337 const unsigned char *fileName,
2338 const char *local_acl, const int buflen,
2339 const int acl_type,
2340 const struct nls_table *nls_codepage, int remap)
2342 struct smb_com_transaction2_spi_req *pSMB = NULL;
2343 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2344 char *parm_data;
2345 int name_len;
2346 int rc = 0;
2347 int bytes_returned = 0;
2348 __u16 params, byte_count, data_count, param_offset, offset;
2350 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2351 setAclRetry:
2352 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2353 (void **) &pSMBr);
2354 if (rc)
2355 return rc;
2356 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2357 name_len =
2358 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2359 PATH_MAX, nls_codepage, remap);
2360 name_len++; /* trailing null */
2361 name_len *= 2;
2362 } else { /* BB improve the check for buffer overruns BB */
2363 name_len = strnlen(fileName, PATH_MAX);
2364 name_len++; /* trailing null */
2365 strncpy(pSMB->FileName, fileName, name_len);
2367 params = 6 + name_len;
2368 pSMB->MaxParameterCount = cpu_to_le16(2);
2369 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2370 pSMB->MaxSetupCount = 0;
2371 pSMB->Reserved = 0;
2372 pSMB->Flags = 0;
2373 pSMB->Timeout = 0;
2374 pSMB->Reserved2 = 0;
2375 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2376 InformationLevel) - 4;
2377 offset = param_offset + params;
2378 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2379 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2381 /* convert to on the wire format for POSIX ACL */
2382 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2384 if(data_count == 0) {
2385 rc = -EOPNOTSUPP;
2386 goto setACLerrorExit;
2388 pSMB->DataOffset = cpu_to_le16(offset);
2389 pSMB->SetupCount = 1;
2390 pSMB->Reserved3 = 0;
2391 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2392 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2393 byte_count = 3 /* pad */ + params + data_count;
2394 pSMB->DataCount = cpu_to_le16(data_count);
2395 pSMB->TotalDataCount = pSMB->DataCount;
2396 pSMB->ParameterCount = cpu_to_le16(params);
2397 pSMB->TotalParameterCount = pSMB->ParameterCount;
2398 pSMB->Reserved4 = 0;
2399 pSMB->hdr.smb_buf_length += byte_count;
2400 pSMB->ByteCount = cpu_to_le16(byte_count);
2401 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2402 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2403 if (rc) {
2404 cFYI(1, ("Set POSIX ACL returned %d", rc));
2407 setACLerrorExit:
2408 cifs_buf_release(pSMB);
2409 if (rc == -EAGAIN)
2410 goto setAclRetry;
2411 return rc;
2414 /* BB fix tabs in this function FIXME BB */
2416 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2417 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2419 int rc = 0;
2420 struct smb_t2_qfi_req *pSMB = NULL;
2421 struct smb_t2_qfi_rsp *pSMBr = NULL;
2422 int bytes_returned;
2423 __u16 params, byte_count;
2425 cFYI(1,("In GetExtAttr"));
2426 if(tcon == NULL)
2427 return -ENODEV;
2429 GetExtAttrRetry:
2430 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2431 (void **) &pSMBr);
2432 if (rc)
2433 return rc;
2435 params = 2 /* level */ +2 /* fid */;
2436 pSMB->t2.TotalDataCount = 0;
2437 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2438 /* BB find exact max data count below from sess structure BB */
2439 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2440 pSMB->t2.MaxSetupCount = 0;
2441 pSMB->t2.Reserved = 0;
2442 pSMB->t2.Flags = 0;
2443 pSMB->t2.Timeout = 0;
2444 pSMB->t2.Reserved2 = 0;
2445 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2446 Fid) - 4);
2447 pSMB->t2.DataCount = 0;
2448 pSMB->t2.DataOffset = 0;
2449 pSMB->t2.SetupCount = 1;
2450 pSMB->t2.Reserved3 = 0;
2451 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2452 byte_count = params + 1 /* pad */ ;
2453 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2454 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2455 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2456 pSMB->Pad = 0;
2457 pSMB->Fid = netfid;
2458 pSMB->hdr.smb_buf_length += byte_count;
2459 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2461 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2462 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2463 if (rc) {
2464 cFYI(1, ("error %d in GetExtAttr", rc));
2465 } else {
2466 /* decode response */
2467 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2468 if (rc || (pSMBr->ByteCount < 2))
2469 /* BB also check enough total bytes returned */
2470 /* If rc should we check for EOPNOSUPP and
2471 disable the srvino flag? or in caller? */
2472 rc = -EIO; /* bad smb */
2473 else {
2474 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2475 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2476 struct file_chattr_info * pfinfo;
2477 /* BB Do we need a cast or hash here ? */
2478 if(count != 16) {
2479 cFYI(1, ("Illegal size ret in GetExtAttr"));
2480 rc = -EIO;
2481 goto GetExtAttrOut;
2483 pfinfo = (struct file_chattr_info *)
2484 (data_offset + (char *) &pSMBr->hdr.Protocol);
2485 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2486 *pMask = le64_to_cpu(pfinfo->mask);
2489 GetExtAttrOut:
2490 cifs_buf_release(pSMB);
2491 if (rc == -EAGAIN)
2492 goto GetExtAttrRetry;
2493 return rc;
2497 #endif /* CONFIG_POSIX */
2500 /* security id for everyone */
2501 const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2502 /* group users */
2503 const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2505 /* Convert CIFS ACL to POSIX form */
2506 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2508 return 0;
2511 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2513 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2514 /* BB fix up return info */ char *acl_inf, const int buflen,
2515 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2517 int rc = 0;
2518 int buf_type = 0;
2519 QUERY_SEC_DESC_REQ * pSMB;
2520 struct kvec iov[1];
2522 cFYI(1, ("GetCifsACL"));
2524 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2525 8 /* parm len */, tcon, (void **) &pSMB);
2526 if (rc)
2527 return rc;
2529 pSMB->MaxParameterCount = cpu_to_le32(4);
2530 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2531 pSMB->MaxSetupCount = 0;
2532 pSMB->Fid = fid; /* file handle always le */
2533 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2534 CIFS_ACL_DACL);
2535 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2536 pSMB->hdr.smb_buf_length += 11;
2537 iov[0].iov_base = (char *)pSMB;
2538 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2540 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2541 cifs_stats_inc(&tcon->num_acl_get);
2542 if (rc) {
2543 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2544 } else { /* decode response */
2545 struct cifs_sid * psec_desc;
2546 __le32 * parm;
2547 int parm_len;
2548 int data_len;
2549 int acl_len;
2550 struct smb_com_ntransact_rsp * pSMBr;
2552 /* validate_nttransact */
2553 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2554 (char **)&psec_desc,
2555 &parm_len, &data_len);
2557 if(rc)
2558 goto qsec_out;
2559 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2561 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2563 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2564 rc = -EIO; /* bad smb */
2565 goto qsec_out;
2568 /* BB check that data area is minimum length and as big as acl_len */
2570 acl_len = le32_to_cpu(*(__le32 *)parm);
2571 /* BB check if(acl_len > bufsize) */
2573 parse_sec_desc(psec_desc, acl_len);
2575 qsec_out:
2576 if(buf_type == CIFS_SMALL_BUFFER)
2577 cifs_small_buf_release(iov[0].iov_base);
2578 else if(buf_type == CIFS_LARGE_BUFFER)
2579 cifs_buf_release(iov[0].iov_base);
2580 cifs_small_buf_release(pSMB);
2581 return rc;
2585 /* Legacy Query Path Information call for lookup to old servers such
2586 as Win9x/WinME */
2587 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2588 const unsigned char *searchName,
2589 FILE_ALL_INFO * pFinfo,
2590 const struct nls_table *nls_codepage, int remap)
2592 QUERY_INFORMATION_REQ * pSMB;
2593 QUERY_INFORMATION_RSP * pSMBr;
2594 int rc = 0;
2595 int bytes_returned;
2596 int name_len;
2598 cFYI(1, ("In SMBQPath path %s", searchName));
2599 QInfRetry:
2600 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2601 (void **) &pSMBr);
2602 if (rc)
2603 return rc;
2605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2606 name_len =
2607 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2608 PATH_MAX, nls_codepage, remap);
2609 name_len++; /* trailing null */
2610 name_len *= 2;
2611 } else {
2612 name_len = strnlen(searchName, PATH_MAX);
2613 name_len++; /* trailing null */
2614 strncpy(pSMB->FileName, searchName, name_len);
2616 pSMB->BufferFormat = 0x04;
2617 name_len++; /* account for buffer type byte */
2618 pSMB->hdr.smb_buf_length += (__u16) name_len;
2619 pSMB->ByteCount = cpu_to_le16(name_len);
2621 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2622 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2623 if (rc) {
2624 cFYI(1, ("Send error in QueryInfo = %d", rc));
2625 } else if (pFinfo) { /* decode response */
2626 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2627 pFinfo->AllocationSize =
2628 cpu_to_le64(le32_to_cpu(pSMBr->size));
2629 pFinfo->EndOfFile = pFinfo->AllocationSize;
2630 pFinfo->Attributes =
2631 cpu_to_le32(le16_to_cpu(pSMBr->attr));
2632 } else
2633 rc = -EIO; /* bad buffer passed in */
2635 cifs_buf_release(pSMB);
2637 if (rc == -EAGAIN)
2638 goto QInfRetry;
2640 return rc;
2647 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2648 const unsigned char *searchName,
2649 FILE_ALL_INFO * pFindData,
2650 const struct nls_table *nls_codepage, int remap)
2652 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2653 TRANSACTION2_QPI_REQ *pSMB = NULL;
2654 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2655 int rc = 0;
2656 int bytes_returned;
2657 int name_len;
2658 __u16 params, byte_count;
2660 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2661 QPathInfoRetry:
2662 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2663 (void **) &pSMBr);
2664 if (rc)
2665 return rc;
2667 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2668 name_len =
2669 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2670 PATH_MAX, nls_codepage, remap);
2671 name_len++; /* trailing null */
2672 name_len *= 2;
2673 } else { /* BB improve the check for buffer overruns BB */
2674 name_len = strnlen(searchName, PATH_MAX);
2675 name_len++; /* trailing null */
2676 strncpy(pSMB->FileName, searchName, name_len);
2679 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2680 pSMB->TotalDataCount = 0;
2681 pSMB->MaxParameterCount = cpu_to_le16(2);
2682 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2683 pSMB->MaxSetupCount = 0;
2684 pSMB->Reserved = 0;
2685 pSMB->Flags = 0;
2686 pSMB->Timeout = 0;
2687 pSMB->Reserved2 = 0;
2688 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2689 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2690 pSMB->DataCount = 0;
2691 pSMB->DataOffset = 0;
2692 pSMB->SetupCount = 1;
2693 pSMB->Reserved3 = 0;
2694 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2695 byte_count = params + 1 /* pad */ ;
2696 pSMB->TotalParameterCount = cpu_to_le16(params);
2697 pSMB->ParameterCount = pSMB->TotalParameterCount;
2698 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2699 pSMB->Reserved4 = 0;
2700 pSMB->hdr.smb_buf_length += byte_count;
2701 pSMB->ByteCount = cpu_to_le16(byte_count);
2703 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2704 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2705 if (rc) {
2706 cFYI(1, ("Send error in QPathInfo = %d", rc));
2707 } else { /* decode response */
2708 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2710 if (rc || (pSMBr->ByteCount < 40))
2711 rc = -EIO; /* bad smb */
2712 else if (pFindData){
2713 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2714 memcpy((char *) pFindData,
2715 (char *) &pSMBr->hdr.Protocol +
2716 data_offset, sizeof (FILE_ALL_INFO));
2717 } else
2718 rc = -ENOMEM;
2720 cifs_buf_release(pSMB);
2721 if (rc == -EAGAIN)
2722 goto QPathInfoRetry;
2724 return rc;
2728 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2729 const unsigned char *searchName,
2730 FILE_UNIX_BASIC_INFO * pFindData,
2731 const struct nls_table *nls_codepage, int remap)
2733 /* SMB_QUERY_FILE_UNIX_BASIC */
2734 TRANSACTION2_QPI_REQ *pSMB = NULL;
2735 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2736 int rc = 0;
2737 int bytes_returned = 0;
2738 int name_len;
2739 __u16 params, byte_count;
2741 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2742 UnixQPathInfoRetry:
2743 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2744 (void **) &pSMBr);
2745 if (rc)
2746 return rc;
2748 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2749 name_len =
2750 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2751 PATH_MAX, nls_codepage, remap);
2752 name_len++; /* trailing null */
2753 name_len *= 2;
2754 } else { /* BB improve the check for buffer overruns BB */
2755 name_len = strnlen(searchName, PATH_MAX);
2756 name_len++; /* trailing null */
2757 strncpy(pSMB->FileName, searchName, name_len);
2760 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2761 pSMB->TotalDataCount = 0;
2762 pSMB->MaxParameterCount = cpu_to_le16(2);
2763 /* BB find exact max SMB PDU from sess structure BB */
2764 pSMB->MaxDataCount = cpu_to_le16(4000);
2765 pSMB->MaxSetupCount = 0;
2766 pSMB->Reserved = 0;
2767 pSMB->Flags = 0;
2768 pSMB->Timeout = 0;
2769 pSMB->Reserved2 = 0;
2770 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2771 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2772 pSMB->DataCount = 0;
2773 pSMB->DataOffset = 0;
2774 pSMB->SetupCount = 1;
2775 pSMB->Reserved3 = 0;
2776 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2777 byte_count = params + 1 /* pad */ ;
2778 pSMB->TotalParameterCount = cpu_to_le16(params);
2779 pSMB->ParameterCount = pSMB->TotalParameterCount;
2780 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2781 pSMB->Reserved4 = 0;
2782 pSMB->hdr.smb_buf_length += byte_count;
2783 pSMB->ByteCount = cpu_to_le16(byte_count);
2785 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2786 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2787 if (rc) {
2788 cFYI(1, ("Send error in QPathInfo = %d", rc));
2789 } else { /* decode response */
2790 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2792 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2793 rc = -EIO; /* bad smb */
2794 } else {
2795 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2796 memcpy((char *) pFindData,
2797 (char *) &pSMBr->hdr.Protocol +
2798 data_offset,
2799 sizeof (FILE_UNIX_BASIC_INFO));
2802 cifs_buf_release(pSMB);
2803 if (rc == -EAGAIN)
2804 goto UnixQPathInfoRetry;
2806 return rc;
2809 #if 0 /* function unused at present */
2810 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2811 const char *searchName, FILE_ALL_INFO * findData,
2812 const struct nls_table *nls_codepage)
2814 /* level 257 SMB_ */
2815 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2816 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2817 int rc = 0;
2818 int bytes_returned;
2819 int name_len;
2820 __u16 params, byte_count;
2822 cFYI(1, ("In FindUnique"));
2823 findUniqueRetry:
2824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2825 (void **) &pSMBr);
2826 if (rc)
2827 return rc;
2829 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2830 name_len =
2831 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2832 /* find define for this maxpathcomponent */
2833 , nls_codepage);
2834 name_len++; /* trailing null */
2835 name_len *= 2;
2836 } else { /* BB improve the check for buffer overruns BB */
2837 name_len = strnlen(searchName, PATH_MAX);
2838 name_len++; /* trailing null */
2839 strncpy(pSMB->FileName, searchName, name_len);
2842 params = 12 + name_len /* includes null */ ;
2843 pSMB->TotalDataCount = 0; /* no EAs */
2844 pSMB->MaxParameterCount = cpu_to_le16(2);
2845 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2846 pSMB->MaxSetupCount = 0;
2847 pSMB->Reserved = 0;
2848 pSMB->Flags = 0;
2849 pSMB->Timeout = 0;
2850 pSMB->Reserved2 = 0;
2851 pSMB->ParameterOffset = cpu_to_le16(
2852 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2853 pSMB->DataCount = 0;
2854 pSMB->DataOffset = 0;
2855 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2856 pSMB->Reserved3 = 0;
2857 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2858 byte_count = params + 1 /* pad */ ;
2859 pSMB->TotalParameterCount = cpu_to_le16(params);
2860 pSMB->ParameterCount = pSMB->TotalParameterCount;
2861 pSMB->SearchAttributes =
2862 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2863 ATTR_DIRECTORY);
2864 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2865 pSMB->SearchFlags = cpu_to_le16(1);
2866 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2867 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2868 pSMB->hdr.smb_buf_length += byte_count;
2869 pSMB->ByteCount = cpu_to_le16(byte_count);
2871 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2872 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2874 if (rc) {
2875 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2876 } else { /* decode response */
2877 cifs_stats_inc(&tcon->num_ffirst);
2878 /* BB fill in */
2881 cifs_buf_release(pSMB);
2882 if (rc == -EAGAIN)
2883 goto findUniqueRetry;
2885 return rc;
2887 #endif /* end unused (temporarily) function */
2889 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2891 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2892 const char *searchName,
2893 const struct nls_table *nls_codepage,
2894 __u16 * pnetfid,
2895 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2897 /* level 257 SMB_ */
2898 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2899 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2900 T2_FFIRST_RSP_PARMS * parms;
2901 int rc = 0;
2902 int bytes_returned = 0;
2903 int name_len;
2904 __u16 params, byte_count;
2906 cFYI(1, ("In FindFirst for %s",searchName));
2908 findFirstRetry:
2909 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2910 (void **) &pSMBr);
2911 if (rc)
2912 return rc;
2914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2915 name_len =
2916 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2917 PATH_MAX, nls_codepage, remap);
2918 /* We can not add the asterik earlier in case
2919 it got remapped to 0xF03A as if it were part of the
2920 directory name instead of a wildcard */
2921 name_len *= 2;
2922 pSMB->FileName[name_len] = dirsep;
2923 pSMB->FileName[name_len+1] = 0;
2924 pSMB->FileName[name_len+2] = '*';
2925 pSMB->FileName[name_len+3] = 0;
2926 name_len += 4; /* now the trailing null */
2927 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2928 pSMB->FileName[name_len+1] = 0;
2929 name_len += 2;
2930 } else { /* BB add check for overrun of SMB buf BB */
2931 name_len = strnlen(searchName, PATH_MAX);
2932 /* BB fix here and in unicode clause above ie
2933 if(name_len > buffersize-header)
2934 free buffer exit; BB */
2935 strncpy(pSMB->FileName, searchName, name_len);
2936 pSMB->FileName[name_len] = dirsep;
2937 pSMB->FileName[name_len+1] = '*';
2938 pSMB->FileName[name_len+2] = 0;
2939 name_len += 3;
2942 params = 12 + name_len /* includes null */ ;
2943 pSMB->TotalDataCount = 0; /* no EAs */
2944 pSMB->MaxParameterCount = cpu_to_le16(10);
2945 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2946 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2947 pSMB->MaxSetupCount = 0;
2948 pSMB->Reserved = 0;
2949 pSMB->Flags = 0;
2950 pSMB->Timeout = 0;
2951 pSMB->Reserved2 = 0;
2952 byte_count = params + 1 /* pad */ ;
2953 pSMB->TotalParameterCount = cpu_to_le16(params);
2954 pSMB->ParameterCount = pSMB->TotalParameterCount;
2955 pSMB->ParameterOffset = cpu_to_le16(
2956 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2957 pSMB->DataCount = 0;
2958 pSMB->DataOffset = 0;
2959 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2960 pSMB->Reserved3 = 0;
2961 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2962 pSMB->SearchAttributes =
2963 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2964 ATTR_DIRECTORY);
2965 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2966 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2967 CIFS_SEARCH_RETURN_RESUME);
2968 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2970 /* BB what should we set StorageType to? Does it matter? BB */
2971 pSMB->SearchStorageType = 0;
2972 pSMB->hdr.smb_buf_length += byte_count;
2973 pSMB->ByteCount = cpu_to_le16(byte_count);
2975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2977 cifs_stats_inc(&tcon->num_ffirst);
2979 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2980 /* BB Add code to handle unsupported level rc */
2981 cFYI(1, ("Error in FindFirst = %d", rc));
2983 if (pSMB)
2984 cifs_buf_release(pSMB);
2986 /* BB eventually could optimize out free and realloc of buf */
2987 /* for this case */
2988 if (rc == -EAGAIN)
2989 goto findFirstRetry;
2990 } else { /* decode response */
2991 /* BB remember to free buffer if error BB */
2992 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2993 if(rc == 0) {
2994 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2995 psrch_inf->unicode = TRUE;
2996 else
2997 psrch_inf->unicode = FALSE;
2999 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3000 psrch_inf->srch_entries_start =
3001 (char *) &pSMBr->hdr.Protocol +
3002 le16_to_cpu(pSMBr->t2.DataOffset);
3003 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3004 le16_to_cpu(pSMBr->t2.ParameterOffset));
3006 if(parms->EndofSearch)
3007 psrch_inf->endOfSearch = TRUE;
3008 else
3009 psrch_inf->endOfSearch = FALSE;
3011 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3012 psrch_inf->index_of_last_entry =
3013 psrch_inf->entries_in_buffer;
3014 *pnetfid = parms->SearchHandle;
3015 } else {
3016 cifs_buf_release(pSMB);
3020 return rc;
3023 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3024 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3026 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3027 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3028 T2_FNEXT_RSP_PARMS * parms;
3029 char *response_data;
3030 int rc = 0;
3031 int bytes_returned, name_len;
3032 __u16 params, byte_count;
3034 cFYI(1, ("In FindNext"));
3036 if(psrch_inf->endOfSearch == TRUE)
3037 return -ENOENT;
3039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3040 (void **) &pSMBr);
3041 if (rc)
3042 return rc;
3044 params = 14; /* includes 2 bytes of null string, converted to LE below */
3045 byte_count = 0;
3046 pSMB->TotalDataCount = 0; /* no EAs */
3047 pSMB->MaxParameterCount = cpu_to_le16(8);
3048 pSMB->MaxDataCount =
3049 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3050 pSMB->MaxSetupCount = 0;
3051 pSMB->Reserved = 0;
3052 pSMB->Flags = 0;
3053 pSMB->Timeout = 0;
3054 pSMB->Reserved2 = 0;
3055 pSMB->ParameterOffset = cpu_to_le16(
3056 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3057 pSMB->DataCount = 0;
3058 pSMB->DataOffset = 0;
3059 pSMB->SetupCount = 1;
3060 pSMB->Reserved3 = 0;
3061 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3062 pSMB->SearchHandle = searchHandle; /* always kept as le */
3063 pSMB->SearchCount =
3064 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3065 /* test for Unix extensions */
3066 /* if (tcon->ses->capabilities & CAP_UNIX) {
3067 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3068 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3069 } else {
3070 pSMB->InformationLevel =
3071 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3072 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3073 } */
3074 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3075 pSMB->ResumeKey = psrch_inf->resume_key;
3076 pSMB->SearchFlags =
3077 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3079 name_len = psrch_inf->resume_name_len;
3080 params += name_len;
3081 if(name_len < PATH_MAX) {
3082 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3083 byte_count += name_len;
3084 /* 14 byte parm len above enough for 2 byte null terminator */
3085 pSMB->ResumeFileName[name_len] = 0;
3086 pSMB->ResumeFileName[name_len+1] = 0;
3087 } else {
3088 rc = -EINVAL;
3089 goto FNext2_err_exit;
3091 byte_count = params + 1 /* pad */ ;
3092 pSMB->TotalParameterCount = cpu_to_le16(params);
3093 pSMB->ParameterCount = pSMB->TotalParameterCount;
3094 pSMB->hdr.smb_buf_length += byte_count;
3095 pSMB->ByteCount = cpu_to_le16(byte_count);
3097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3099 cifs_stats_inc(&tcon->num_fnext);
3100 if (rc) {
3101 if (rc == -EBADF) {
3102 psrch_inf->endOfSearch = TRUE;
3103 rc = 0; /* search probably was closed at end of search above */
3104 } else
3105 cFYI(1, ("FindNext returned = %d", rc));
3106 } else { /* decode response */
3107 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3109 if(rc == 0) {
3110 /* BB fixme add lock for file (srch_info) struct here */
3111 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3112 psrch_inf->unicode = TRUE;
3113 else
3114 psrch_inf->unicode = FALSE;
3115 response_data = (char *) &pSMBr->hdr.Protocol +
3116 le16_to_cpu(pSMBr->t2.ParameterOffset);
3117 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3118 response_data = (char *)&pSMBr->hdr.Protocol +
3119 le16_to_cpu(pSMBr->t2.DataOffset);
3120 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3121 psrch_inf->srch_entries_start = response_data;
3122 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3123 if(parms->EndofSearch)
3124 psrch_inf->endOfSearch = TRUE;
3125 else
3126 psrch_inf->endOfSearch = FALSE;
3128 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3129 psrch_inf->index_of_last_entry +=
3130 psrch_inf->entries_in_buffer;
3131 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3133 /* BB fixme add unlock here */
3138 /* BB On error, should we leave previous search buf (and count and
3139 last entry fields) intact or free the previous one? */
3141 /* Note: On -EAGAIN error only caller can retry on handle based calls
3142 since file handle passed in no longer valid */
3143 FNext2_err_exit:
3144 if (rc != 0)
3145 cifs_buf_release(pSMB);
3147 return rc;
3151 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3153 int rc = 0;
3154 FINDCLOSE_REQ *pSMB = NULL;
3155 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3156 int bytes_returned;
3158 cFYI(1, ("In CIFSSMBFindClose"));
3159 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3161 /* no sense returning error if session restarted
3162 as file handle has been closed */
3163 if(rc == -EAGAIN)
3164 return 0;
3165 if (rc)
3166 return rc;
3168 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3169 pSMB->FileID = searchHandle;
3170 pSMB->ByteCount = 0;
3171 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3172 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3173 if (rc) {
3174 cERROR(1, ("Send error in FindClose = %d", rc));
3176 cifs_stats_inc(&tcon->num_fclose);
3177 cifs_small_buf_release(pSMB);
3179 /* Since session is dead, search handle closed on server already */
3180 if (rc == -EAGAIN)
3181 rc = 0;
3183 return rc;
3187 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3188 const unsigned char *searchName,
3189 __u64 * inode_number,
3190 const struct nls_table *nls_codepage, int remap)
3192 int rc = 0;
3193 TRANSACTION2_QPI_REQ *pSMB = NULL;
3194 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3195 int name_len, bytes_returned;
3196 __u16 params, byte_count;
3198 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3199 if(tcon == NULL)
3200 return -ENODEV;
3202 GetInodeNumberRetry:
3203 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3204 (void **) &pSMBr);
3205 if (rc)
3206 return rc;
3209 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3210 name_len =
3211 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3212 PATH_MAX,nls_codepage, remap);
3213 name_len++; /* trailing null */
3214 name_len *= 2;
3215 } else { /* BB improve the check for buffer overruns BB */
3216 name_len = strnlen(searchName, PATH_MAX);
3217 name_len++; /* trailing null */
3218 strncpy(pSMB->FileName, searchName, name_len);
3221 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3222 pSMB->TotalDataCount = 0;
3223 pSMB->MaxParameterCount = cpu_to_le16(2);
3224 /* BB find exact max data count below from sess structure BB */
3225 pSMB->MaxDataCount = cpu_to_le16(4000);
3226 pSMB->MaxSetupCount = 0;
3227 pSMB->Reserved = 0;
3228 pSMB->Flags = 0;
3229 pSMB->Timeout = 0;
3230 pSMB->Reserved2 = 0;
3231 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3232 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3233 pSMB->DataCount = 0;
3234 pSMB->DataOffset = 0;
3235 pSMB->SetupCount = 1;
3236 pSMB->Reserved3 = 0;
3237 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3238 byte_count = params + 1 /* pad */ ;
3239 pSMB->TotalParameterCount = cpu_to_le16(params);
3240 pSMB->ParameterCount = pSMB->TotalParameterCount;
3241 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3242 pSMB->Reserved4 = 0;
3243 pSMB->hdr.smb_buf_length += byte_count;
3244 pSMB->ByteCount = cpu_to_le16(byte_count);
3246 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3247 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3248 if (rc) {
3249 cFYI(1, ("error %d in QueryInternalInfo", rc));
3250 } else {
3251 /* decode response */
3252 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3253 if (rc || (pSMBr->ByteCount < 2))
3254 /* BB also check enough total bytes returned */
3255 /* If rc should we check for EOPNOSUPP and
3256 disable the srvino flag? or in caller? */
3257 rc = -EIO; /* bad smb */
3258 else {
3259 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3260 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3261 struct file_internal_info * pfinfo;
3262 /* BB Do we need a cast or hash here ? */
3263 if(count < 8) {
3264 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3265 rc = -EIO;
3266 goto GetInodeNumOut;
3268 pfinfo = (struct file_internal_info *)
3269 (data_offset + (char *) &pSMBr->hdr.Protocol);
3270 *inode_number = pfinfo->UniqueId;
3273 GetInodeNumOut:
3274 cifs_buf_release(pSMB);
3275 if (rc == -EAGAIN)
3276 goto GetInodeNumberRetry;
3277 return rc;
3281 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3282 const unsigned char *searchName,
3283 unsigned char **targetUNCs,
3284 unsigned int *number_of_UNC_in_array,
3285 const struct nls_table *nls_codepage, int remap)
3287 /* TRANS2_GET_DFS_REFERRAL */
3288 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3289 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3290 struct dfs_referral_level_3 * referrals = NULL;
3291 int rc = 0;
3292 int bytes_returned;
3293 int name_len;
3294 unsigned int i;
3295 char * temp;
3296 __u16 params, byte_count;
3297 *number_of_UNC_in_array = 0;
3298 *targetUNCs = NULL;
3300 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3301 if (ses == NULL)
3302 return -ENODEV;
3303 getDFSRetry:
3304 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3305 (void **) &pSMBr);
3306 if (rc)
3307 return rc;
3309 /* server pointer checked in called function,
3310 but should never be null here anyway */
3311 pSMB->hdr.Mid = GetNextMid(ses->server);
3312 pSMB->hdr.Tid = ses->ipc_tid;
3313 pSMB->hdr.Uid = ses->Suid;
3314 if (ses->capabilities & CAP_STATUS32) {
3315 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3317 if (ses->capabilities & CAP_DFS) {
3318 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3321 if (ses->capabilities & CAP_UNICODE) {
3322 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3323 name_len =
3324 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3325 searchName, PATH_MAX, nls_codepage, remap);
3326 name_len++; /* trailing null */
3327 name_len *= 2;
3328 } else { /* BB improve the check for buffer overruns BB */
3329 name_len = strnlen(searchName, PATH_MAX);
3330 name_len++; /* trailing null */
3331 strncpy(pSMB->RequestFileName, searchName, name_len);
3334 params = 2 /* level */ + name_len /*includes null */ ;
3335 pSMB->TotalDataCount = 0;
3336 pSMB->DataCount = 0;
3337 pSMB->DataOffset = 0;
3338 pSMB->MaxParameterCount = 0;
3339 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3340 pSMB->MaxSetupCount = 0;
3341 pSMB->Reserved = 0;
3342 pSMB->Flags = 0;
3343 pSMB->Timeout = 0;
3344 pSMB->Reserved2 = 0;
3345 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3346 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3347 pSMB->SetupCount = 1;
3348 pSMB->Reserved3 = 0;
3349 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3350 byte_count = params + 3 /* pad */ ;
3351 pSMB->ParameterCount = cpu_to_le16(params);
3352 pSMB->TotalParameterCount = pSMB->ParameterCount;
3353 pSMB->MaxReferralLevel = cpu_to_le16(3);
3354 pSMB->hdr.smb_buf_length += byte_count;
3355 pSMB->ByteCount = cpu_to_le16(byte_count);
3357 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3359 if (rc) {
3360 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3361 } else { /* decode response */
3362 /* BB Add logic to parse referrals here */
3363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3365 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3366 rc = -EIO; /* bad smb */
3367 else {
3368 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3369 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3371 cFYI(1,
3372 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3373 pSMBr->ByteCount, data_offset));
3374 referrals =
3375 (struct dfs_referral_level_3 *)
3376 (8 /* sizeof start of data block */ +
3377 data_offset +
3378 (char *) &pSMBr->hdr.Protocol);
3379 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",
3380 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)));
3381 /* BB This field is actually two bytes in from start of
3382 data block so we could do safety check that DataBlock
3383 begins at address of pSMBr->NumberOfReferrals */
3384 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3386 /* BB Fix below so can return more than one referral */
3387 if(*number_of_UNC_in_array > 1)
3388 *number_of_UNC_in_array = 1;
3390 /* get the length of the strings describing refs */
3391 name_len = 0;
3392 for(i=0;i<*number_of_UNC_in_array;i++) {
3393 /* make sure that DfsPathOffset not past end */
3394 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3395 if (offset > data_count) {
3396 /* if invalid referral, stop here and do
3397 not try to copy any more */
3398 *number_of_UNC_in_array = i;
3399 break;
3401 temp = ((char *)referrals) + offset;
3403 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3404 name_len += UniStrnlen((wchar_t *)temp,data_count);
3405 } else {
3406 name_len += strnlen(temp,data_count);
3408 referrals++;
3409 /* BB add check that referral pointer does not fall off end PDU */
3412 /* BB add check for name_len bigger than bcc */
3413 *targetUNCs =
3414 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3415 if(*targetUNCs == NULL) {
3416 rc = -ENOMEM;
3417 goto GetDFSRefExit;
3419 /* copy the ref strings */
3420 referrals =
3421 (struct dfs_referral_level_3 *)
3422 (8 /* sizeof data hdr */ +
3423 data_offset +
3424 (char *) &pSMBr->hdr.Protocol);
3426 for(i=0;i<*number_of_UNC_in_array;i++) {
3427 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3428 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3429 cifs_strfromUCS_le(*targetUNCs,
3430 (__le16 *) temp, name_len, nls_codepage);
3431 } else {
3432 strncpy(*targetUNCs,temp,name_len);
3434 /* BB update target_uncs pointers */
3435 referrals++;
3437 temp = *targetUNCs;
3438 temp[name_len] = 0;
3442 GetDFSRefExit:
3443 if (pSMB)
3444 cifs_buf_release(pSMB);
3446 if (rc == -EAGAIN)
3447 goto getDFSRetry;
3449 return rc;
3452 /* Query File System Info such as free space to old servers such as Win 9x */
3454 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3456 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3457 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3458 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3459 FILE_SYSTEM_ALLOC_INFO *response_data;
3460 int rc = 0;
3461 int bytes_returned = 0;
3462 __u16 params, byte_count;
3464 cFYI(1, ("OldQFSInfo"));
3465 oldQFSInfoRetry:
3466 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3467 (void **) &pSMBr);
3468 if (rc)
3469 return rc;
3470 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3471 (void **) &pSMBr);
3472 if (rc)
3473 return rc;
3475 params = 2; /* level */
3476 pSMB->TotalDataCount = 0;
3477 pSMB->MaxParameterCount = cpu_to_le16(2);
3478 pSMB->MaxDataCount = cpu_to_le16(1000);
3479 pSMB->MaxSetupCount = 0;
3480 pSMB->Reserved = 0;
3481 pSMB->Flags = 0;
3482 pSMB->Timeout = 0;
3483 pSMB->Reserved2 = 0;
3484 byte_count = params + 1 /* pad */ ;
3485 pSMB->TotalParameterCount = cpu_to_le16(params);
3486 pSMB->ParameterCount = pSMB->TotalParameterCount;
3487 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3488 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3489 pSMB->DataCount = 0;
3490 pSMB->DataOffset = 0;
3491 pSMB->SetupCount = 1;
3492 pSMB->Reserved3 = 0;
3493 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3494 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3495 pSMB->hdr.smb_buf_length += byte_count;
3496 pSMB->ByteCount = cpu_to_le16(byte_count);
3498 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3500 if (rc) {
3501 cFYI(1, ("Send error in QFSInfo = %d", rc));
3502 } else { /* decode response */
3503 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3505 if (rc || (pSMBr->ByteCount < 18))
3506 rc = -EIO; /* bad smb */
3507 else {
3508 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3509 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3510 pSMBr->ByteCount, data_offset));
3512 response_data =
3513 (FILE_SYSTEM_ALLOC_INFO *)
3514 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3515 FSData->f_bsize =
3516 le16_to_cpu(response_data->BytesPerSector) *
3517 le32_to_cpu(response_data->
3518 SectorsPerAllocationUnit);
3519 FSData->f_blocks =
3520 le32_to_cpu(response_data->TotalAllocationUnits);
3521 FSData->f_bfree = FSData->f_bavail =
3522 le32_to_cpu(response_data->FreeAllocationUnits);
3523 cFYI(1,
3524 ("Blocks: %lld Free: %lld Block size %ld",
3525 (unsigned long long)FSData->f_blocks,
3526 (unsigned long long)FSData->f_bfree,
3527 FSData->f_bsize));
3530 cifs_buf_release(pSMB);
3532 if (rc == -EAGAIN)
3533 goto oldQFSInfoRetry;
3535 return rc;
3539 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3541 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3542 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3543 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3544 FILE_SYSTEM_INFO *response_data;
3545 int rc = 0;
3546 int bytes_returned = 0;
3547 __u16 params, byte_count;
3549 cFYI(1, ("In QFSInfo"));
3550 QFSInfoRetry:
3551 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3552 (void **) &pSMBr);
3553 if (rc)
3554 return rc;
3556 params = 2; /* level */
3557 pSMB->TotalDataCount = 0;
3558 pSMB->MaxParameterCount = cpu_to_le16(2);
3559 pSMB->MaxDataCount = cpu_to_le16(1000);
3560 pSMB->MaxSetupCount = 0;
3561 pSMB->Reserved = 0;
3562 pSMB->Flags = 0;
3563 pSMB->Timeout = 0;
3564 pSMB->Reserved2 = 0;
3565 byte_count = params + 1 /* pad */ ;
3566 pSMB->TotalParameterCount = cpu_to_le16(params);
3567 pSMB->ParameterCount = pSMB->TotalParameterCount;
3568 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3569 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3570 pSMB->DataCount = 0;
3571 pSMB->DataOffset = 0;
3572 pSMB->SetupCount = 1;
3573 pSMB->Reserved3 = 0;
3574 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3575 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3576 pSMB->hdr.smb_buf_length += byte_count;
3577 pSMB->ByteCount = cpu_to_le16(byte_count);
3579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3580 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3581 if (rc) {
3582 cFYI(1, ("Send error in QFSInfo = %d", rc));
3583 } else { /* decode response */
3584 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3586 if (rc || (pSMBr->ByteCount < 24))
3587 rc = -EIO; /* bad smb */
3588 else {
3589 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3591 response_data =
3592 (FILE_SYSTEM_INFO
3593 *) (((char *) &pSMBr->hdr.Protocol) +
3594 data_offset);
3595 FSData->f_bsize =
3596 le32_to_cpu(response_data->BytesPerSector) *
3597 le32_to_cpu(response_data->
3598 SectorsPerAllocationUnit);
3599 FSData->f_blocks =
3600 le64_to_cpu(response_data->TotalAllocationUnits);
3601 FSData->f_bfree = FSData->f_bavail =
3602 le64_to_cpu(response_data->FreeAllocationUnits);
3603 cFYI(1,
3604 ("Blocks: %lld Free: %lld Block size %ld",
3605 (unsigned long long)FSData->f_blocks,
3606 (unsigned long long)FSData->f_bfree,
3607 FSData->f_bsize));
3610 cifs_buf_release(pSMB);
3612 if (rc == -EAGAIN)
3613 goto QFSInfoRetry;
3615 return rc;
3619 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3621 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3622 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3623 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3624 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3625 int rc = 0;
3626 int bytes_returned = 0;
3627 __u16 params, byte_count;
3629 cFYI(1, ("In QFSAttributeInfo"));
3630 QFSAttributeRetry:
3631 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3632 (void **) &pSMBr);
3633 if (rc)
3634 return rc;
3636 params = 2; /* level */
3637 pSMB->TotalDataCount = 0;
3638 pSMB->MaxParameterCount = cpu_to_le16(2);
3639 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3640 pSMB->MaxSetupCount = 0;
3641 pSMB->Reserved = 0;
3642 pSMB->Flags = 0;
3643 pSMB->Timeout = 0;
3644 pSMB->Reserved2 = 0;
3645 byte_count = params + 1 /* pad */ ;
3646 pSMB->TotalParameterCount = cpu_to_le16(params);
3647 pSMB->ParameterCount = pSMB->TotalParameterCount;
3648 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3649 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3650 pSMB->DataCount = 0;
3651 pSMB->DataOffset = 0;
3652 pSMB->SetupCount = 1;
3653 pSMB->Reserved3 = 0;
3654 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3655 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3656 pSMB->hdr.smb_buf_length += byte_count;
3657 pSMB->ByteCount = cpu_to_le16(byte_count);
3659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3661 if (rc) {
3662 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3663 } else { /* decode response */
3664 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3666 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3667 rc = -EIO; /* bad smb */
3668 } else {
3669 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3670 response_data =
3671 (FILE_SYSTEM_ATTRIBUTE_INFO
3672 *) (((char *) &pSMBr->hdr.Protocol) +
3673 data_offset);
3674 memcpy(&tcon->fsAttrInfo, response_data,
3675 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3678 cifs_buf_release(pSMB);
3680 if (rc == -EAGAIN)
3681 goto QFSAttributeRetry;
3683 return rc;
3687 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3689 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3690 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3691 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3692 FILE_SYSTEM_DEVICE_INFO *response_data;
3693 int rc = 0;
3694 int bytes_returned = 0;
3695 __u16 params, byte_count;
3697 cFYI(1, ("In QFSDeviceInfo"));
3698 QFSDeviceRetry:
3699 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3700 (void **) &pSMBr);
3701 if (rc)
3702 return rc;
3704 params = 2; /* level */
3705 pSMB->TotalDataCount = 0;
3706 pSMB->MaxParameterCount = cpu_to_le16(2);
3707 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3708 pSMB->MaxSetupCount = 0;
3709 pSMB->Reserved = 0;
3710 pSMB->Flags = 0;
3711 pSMB->Timeout = 0;
3712 pSMB->Reserved2 = 0;
3713 byte_count = params + 1 /* pad */ ;
3714 pSMB->TotalParameterCount = cpu_to_le16(params);
3715 pSMB->ParameterCount = pSMB->TotalParameterCount;
3716 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3717 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3719 pSMB->DataCount = 0;
3720 pSMB->DataOffset = 0;
3721 pSMB->SetupCount = 1;
3722 pSMB->Reserved3 = 0;
3723 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3724 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3725 pSMB->hdr.smb_buf_length += byte_count;
3726 pSMB->ByteCount = cpu_to_le16(byte_count);
3728 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3729 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3730 if (rc) {
3731 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3732 } else { /* decode response */
3733 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3735 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3736 rc = -EIO; /* bad smb */
3737 else {
3738 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3739 response_data =
3740 (FILE_SYSTEM_DEVICE_INFO *)
3741 (((char *) &pSMBr->hdr.Protocol) +
3742 data_offset);
3743 memcpy(&tcon->fsDevInfo, response_data,
3744 sizeof (FILE_SYSTEM_DEVICE_INFO));
3747 cifs_buf_release(pSMB);
3749 if (rc == -EAGAIN)
3750 goto QFSDeviceRetry;
3752 return rc;
3756 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3758 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3759 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3760 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3761 FILE_SYSTEM_UNIX_INFO *response_data;
3762 int rc = 0;
3763 int bytes_returned = 0;
3764 __u16 params, byte_count;
3766 cFYI(1, ("In QFSUnixInfo"));
3767 QFSUnixRetry:
3768 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3769 (void **) &pSMBr);
3770 if (rc)
3771 return rc;
3773 params = 2; /* level */
3774 pSMB->TotalDataCount = 0;
3775 pSMB->DataCount = 0;
3776 pSMB->DataOffset = 0;
3777 pSMB->MaxParameterCount = cpu_to_le16(2);
3778 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3779 pSMB->MaxSetupCount = 0;
3780 pSMB->Reserved = 0;
3781 pSMB->Flags = 0;
3782 pSMB->Timeout = 0;
3783 pSMB->Reserved2 = 0;
3784 byte_count = params + 1 /* pad */ ;
3785 pSMB->ParameterCount = cpu_to_le16(params);
3786 pSMB->TotalParameterCount = pSMB->ParameterCount;
3787 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3788 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3789 pSMB->SetupCount = 1;
3790 pSMB->Reserved3 = 0;
3791 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3792 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3793 pSMB->hdr.smb_buf_length += byte_count;
3794 pSMB->ByteCount = cpu_to_le16(byte_count);
3796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3798 if (rc) {
3799 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3800 } else { /* decode response */
3801 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3803 if (rc || (pSMBr->ByteCount < 13)) {
3804 rc = -EIO; /* bad smb */
3805 } else {
3806 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3807 response_data =
3808 (FILE_SYSTEM_UNIX_INFO
3809 *) (((char *) &pSMBr->hdr.Protocol) +
3810 data_offset);
3811 memcpy(&tcon->fsUnixInfo, response_data,
3812 sizeof (FILE_SYSTEM_UNIX_INFO));
3815 cifs_buf_release(pSMB);
3817 if (rc == -EAGAIN)
3818 goto QFSUnixRetry;
3821 return rc;
3825 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3827 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3828 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3829 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3830 int rc = 0;
3831 int bytes_returned = 0;
3832 __u16 params, param_offset, offset, byte_count;
3834 cFYI(1, ("In SETFSUnixInfo"));
3835 SETFSUnixRetry:
3836 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3837 (void **) &pSMBr);
3838 if (rc)
3839 return rc;
3841 params = 4; /* 2 bytes zero followed by info level. */
3842 pSMB->MaxSetupCount = 0;
3843 pSMB->Reserved = 0;
3844 pSMB->Flags = 0;
3845 pSMB->Timeout = 0;
3846 pSMB->Reserved2 = 0;
3847 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3848 offset = param_offset + params;
3850 pSMB->MaxParameterCount = cpu_to_le16(4);
3851 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3852 pSMB->SetupCount = 1;
3853 pSMB->Reserved3 = 0;
3854 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3855 byte_count = 1 /* pad */ + params + 12;
3857 pSMB->DataCount = cpu_to_le16(12);
3858 pSMB->ParameterCount = cpu_to_le16(params);
3859 pSMB->TotalDataCount = pSMB->DataCount;
3860 pSMB->TotalParameterCount = pSMB->ParameterCount;
3861 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3862 pSMB->DataOffset = cpu_to_le16(offset);
3864 /* Params. */
3865 pSMB->FileNum = 0;
3866 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3868 /* Data. */
3869 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3870 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3871 pSMB->ClientUnixCap = cpu_to_le64(cap);
3873 pSMB->hdr.smb_buf_length += byte_count;
3874 pSMB->ByteCount = cpu_to_le16(byte_count);
3876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3878 if (rc) {
3879 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3880 } else { /* decode response */
3881 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3882 if (rc) {
3883 rc = -EIO; /* bad smb */
3886 cifs_buf_release(pSMB);
3888 if (rc == -EAGAIN)
3889 goto SETFSUnixRetry;
3891 return rc;
3897 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3898 struct kstatfs *FSData)
3900 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3901 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3902 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3903 FILE_SYSTEM_POSIX_INFO *response_data;
3904 int rc = 0;
3905 int bytes_returned = 0;
3906 __u16 params, byte_count;
3908 cFYI(1, ("In QFSPosixInfo"));
3909 QFSPosixRetry:
3910 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3911 (void **) &pSMBr);
3912 if (rc)
3913 return rc;
3915 params = 2; /* level */
3916 pSMB->TotalDataCount = 0;
3917 pSMB->DataCount = 0;
3918 pSMB->DataOffset = 0;
3919 pSMB->MaxParameterCount = cpu_to_le16(2);
3920 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3921 pSMB->MaxSetupCount = 0;
3922 pSMB->Reserved = 0;
3923 pSMB->Flags = 0;
3924 pSMB->Timeout = 0;
3925 pSMB->Reserved2 = 0;
3926 byte_count = params + 1 /* pad */ ;
3927 pSMB->ParameterCount = cpu_to_le16(params);
3928 pSMB->TotalParameterCount = pSMB->ParameterCount;
3929 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3930 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3931 pSMB->SetupCount = 1;
3932 pSMB->Reserved3 = 0;
3933 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3934 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3935 pSMB->hdr.smb_buf_length += byte_count;
3936 pSMB->ByteCount = cpu_to_le16(byte_count);
3938 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3939 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3940 if (rc) {
3941 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3942 } else { /* decode response */
3943 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3945 if (rc || (pSMBr->ByteCount < 13)) {
3946 rc = -EIO; /* bad smb */
3947 } else {
3948 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3949 response_data =
3950 (FILE_SYSTEM_POSIX_INFO
3951 *) (((char *) &pSMBr->hdr.Protocol) +
3952 data_offset);
3953 FSData->f_bsize =
3954 le32_to_cpu(response_data->BlockSize);
3955 FSData->f_blocks =
3956 le64_to_cpu(response_data->TotalBlocks);
3957 FSData->f_bfree =
3958 le64_to_cpu(response_data->BlocksAvail);
3959 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
3960 FSData->f_bavail = FSData->f_bfree;
3961 } else {
3962 FSData->f_bavail =
3963 le64_to_cpu(response_data->UserBlocksAvail);
3965 if(response_data->TotalFileNodes != cpu_to_le64(-1))
3966 FSData->f_files =
3967 le64_to_cpu(response_data->TotalFileNodes);
3968 if(response_data->FreeFileNodes != cpu_to_le64(-1))
3969 FSData->f_ffree =
3970 le64_to_cpu(response_data->FreeFileNodes);
3973 cifs_buf_release(pSMB);
3975 if (rc == -EAGAIN)
3976 goto QFSPosixRetry;
3978 return rc;
3982 /* We can not use write of zero bytes trick to
3983 set file size due to need for large file support. Also note that
3984 this SetPathInfo is preferred to SetFileInfo based method in next
3985 routine which is only needed to work around a sharing violation bug
3986 in Samba which this routine can run into */
3989 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3990 __u64 size, int SetAllocation,
3991 const struct nls_table *nls_codepage, int remap)
3993 struct smb_com_transaction2_spi_req *pSMB = NULL;
3994 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3995 struct file_end_of_file_info *parm_data;
3996 int name_len;
3997 int rc = 0;
3998 int bytes_returned = 0;
3999 __u16 params, byte_count, data_count, param_offset, offset;
4001 cFYI(1, ("In SetEOF"));
4002 SetEOFRetry:
4003 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4004 (void **) &pSMBr);
4005 if (rc)
4006 return rc;
4008 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4009 name_len =
4010 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4011 PATH_MAX, nls_codepage, remap);
4012 name_len++; /* trailing null */
4013 name_len *= 2;
4014 } else { /* BB improve the check for buffer overruns BB */
4015 name_len = strnlen(fileName, PATH_MAX);
4016 name_len++; /* trailing null */
4017 strncpy(pSMB->FileName, fileName, name_len);
4019 params = 6 + name_len;
4020 data_count = sizeof (struct file_end_of_file_info);
4021 pSMB->MaxParameterCount = cpu_to_le16(2);
4022 pSMB->MaxDataCount = cpu_to_le16(4100);
4023 pSMB->MaxSetupCount = 0;
4024 pSMB->Reserved = 0;
4025 pSMB->Flags = 0;
4026 pSMB->Timeout = 0;
4027 pSMB->Reserved2 = 0;
4028 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4029 InformationLevel) - 4;
4030 offset = param_offset + params;
4031 if(SetAllocation) {
4032 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4033 pSMB->InformationLevel =
4034 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4035 else
4036 pSMB->InformationLevel =
4037 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4038 } else /* Set File Size */ {
4039 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4040 pSMB->InformationLevel =
4041 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4042 else
4043 pSMB->InformationLevel =
4044 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4047 parm_data =
4048 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4049 offset);
4050 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4051 pSMB->DataOffset = cpu_to_le16(offset);
4052 pSMB->SetupCount = 1;
4053 pSMB->Reserved3 = 0;
4054 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4055 byte_count = 3 /* pad */ + params + data_count;
4056 pSMB->DataCount = cpu_to_le16(data_count);
4057 pSMB->TotalDataCount = pSMB->DataCount;
4058 pSMB->ParameterCount = cpu_to_le16(params);
4059 pSMB->TotalParameterCount = pSMB->ParameterCount;
4060 pSMB->Reserved4 = 0;
4061 pSMB->hdr.smb_buf_length += byte_count;
4062 parm_data->FileSize = cpu_to_le64(size);
4063 pSMB->ByteCount = cpu_to_le16(byte_count);
4064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4066 if (rc) {
4067 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4070 cifs_buf_release(pSMB);
4072 if (rc == -EAGAIN)
4073 goto SetEOFRetry;
4075 return rc;
4079 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4080 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4082 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4083 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4084 char *data_offset;
4085 struct file_end_of_file_info *parm_data;
4086 int rc = 0;
4087 int bytes_returned = 0;
4088 __u16 params, param_offset, offset, byte_count, count;
4090 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4091 (long long)size));
4092 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4094 if (rc)
4095 return rc;
4097 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4099 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4100 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4102 params = 6;
4103 pSMB->MaxSetupCount = 0;
4104 pSMB->Reserved = 0;
4105 pSMB->Flags = 0;
4106 pSMB->Timeout = 0;
4107 pSMB->Reserved2 = 0;
4108 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4109 offset = param_offset + params;
4111 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4113 count = sizeof(struct file_end_of_file_info);
4114 pSMB->MaxParameterCount = cpu_to_le16(2);
4115 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4116 pSMB->SetupCount = 1;
4117 pSMB->Reserved3 = 0;
4118 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4119 byte_count = 3 /* pad */ + params + count;
4120 pSMB->DataCount = cpu_to_le16(count);
4121 pSMB->ParameterCount = cpu_to_le16(params);
4122 pSMB->TotalDataCount = pSMB->DataCount;
4123 pSMB->TotalParameterCount = pSMB->ParameterCount;
4124 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4125 parm_data =
4126 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4127 offset);
4128 pSMB->DataOffset = cpu_to_le16(offset);
4129 parm_data->FileSize = cpu_to_le64(size);
4130 pSMB->Fid = fid;
4131 if(SetAllocation) {
4132 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4133 pSMB->InformationLevel =
4134 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4135 else
4136 pSMB->InformationLevel =
4137 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4138 } else /* Set File Size */ {
4139 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4140 pSMB->InformationLevel =
4141 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4142 else
4143 pSMB->InformationLevel =
4144 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4146 pSMB->Reserved4 = 0;
4147 pSMB->hdr.smb_buf_length += byte_count;
4148 pSMB->ByteCount = cpu_to_le16(byte_count);
4149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4151 if (rc) {
4152 cFYI(1,
4153 ("Send error in SetFileInfo (SetFileSize) = %d",
4154 rc));
4157 if (pSMB)
4158 cifs_small_buf_release(pSMB);
4160 /* Note: On -EAGAIN error only caller can retry on handle based calls
4161 since file handle passed in no longer valid */
4163 return rc;
4166 /* Some legacy servers such as NT4 require that the file times be set on
4167 an open handle, rather than by pathname - this is awkward due to
4168 potential access conflicts on the open, but it is unavoidable for these
4169 old servers since the only other choice is to go from 100 nanosecond DCE
4170 time and resort to the original setpathinfo level which takes the ancient
4171 DOS time format with 2 second granularity */
4173 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4174 __u16 fid)
4176 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4177 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4178 char *data_offset;
4179 int rc = 0;
4180 int bytes_returned = 0;
4181 __u16 params, param_offset, offset, byte_count, count;
4183 cFYI(1, ("Set Times (via SetFileInfo)"));
4184 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4186 if (rc)
4187 return rc;
4189 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4191 /* At this point there is no need to override the current pid
4192 with the pid of the opener, but that could change if we someday
4193 use an existing handle (rather than opening one on the fly) */
4194 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4195 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4197 params = 6;
4198 pSMB->MaxSetupCount = 0;
4199 pSMB->Reserved = 0;
4200 pSMB->Flags = 0;
4201 pSMB->Timeout = 0;
4202 pSMB->Reserved2 = 0;
4203 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4204 offset = param_offset + params;
4206 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4208 count = sizeof (FILE_BASIC_INFO);
4209 pSMB->MaxParameterCount = cpu_to_le16(2);
4210 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4211 pSMB->SetupCount = 1;
4212 pSMB->Reserved3 = 0;
4213 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4214 byte_count = 3 /* pad */ + params + count;
4215 pSMB->DataCount = cpu_to_le16(count);
4216 pSMB->ParameterCount = cpu_to_le16(params);
4217 pSMB->TotalDataCount = pSMB->DataCount;
4218 pSMB->TotalParameterCount = pSMB->ParameterCount;
4219 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4220 pSMB->DataOffset = cpu_to_le16(offset);
4221 pSMB->Fid = fid;
4222 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4223 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4224 else
4225 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4226 pSMB->Reserved4 = 0;
4227 pSMB->hdr.smb_buf_length += byte_count;
4228 pSMB->ByteCount = cpu_to_le16(byte_count);
4229 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4230 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4231 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4232 if (rc) {
4233 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4236 cifs_small_buf_release(pSMB);
4238 /* Note: On -EAGAIN error only caller can retry on handle based calls
4239 since file handle passed in no longer valid */
4241 return rc;
4246 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4247 const FILE_BASIC_INFO * data,
4248 const struct nls_table *nls_codepage, int remap)
4250 TRANSACTION2_SPI_REQ *pSMB = NULL;
4251 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4252 int name_len;
4253 int rc = 0;
4254 int bytes_returned = 0;
4255 char *data_offset;
4256 __u16 params, param_offset, offset, byte_count, count;
4258 cFYI(1, ("In SetTimes"));
4260 SetTimesRetry:
4261 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4262 (void **) &pSMBr);
4263 if (rc)
4264 return rc;
4266 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4267 name_len =
4268 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4269 PATH_MAX, nls_codepage, remap);
4270 name_len++; /* trailing null */
4271 name_len *= 2;
4272 } else { /* BB improve the check for buffer overruns BB */
4273 name_len = strnlen(fileName, PATH_MAX);
4274 name_len++; /* trailing null */
4275 strncpy(pSMB->FileName, fileName, name_len);
4278 params = 6 + name_len;
4279 count = sizeof (FILE_BASIC_INFO);
4280 pSMB->MaxParameterCount = cpu_to_le16(2);
4281 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4282 pSMB->MaxSetupCount = 0;
4283 pSMB->Reserved = 0;
4284 pSMB->Flags = 0;
4285 pSMB->Timeout = 0;
4286 pSMB->Reserved2 = 0;
4287 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4288 InformationLevel) - 4;
4289 offset = param_offset + params;
4290 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4291 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4292 pSMB->DataOffset = cpu_to_le16(offset);
4293 pSMB->SetupCount = 1;
4294 pSMB->Reserved3 = 0;
4295 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4296 byte_count = 3 /* pad */ + params + count;
4298 pSMB->DataCount = cpu_to_le16(count);
4299 pSMB->ParameterCount = cpu_to_le16(params);
4300 pSMB->TotalDataCount = pSMB->DataCount;
4301 pSMB->TotalParameterCount = pSMB->ParameterCount;
4302 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4303 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4304 else
4305 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4306 pSMB->Reserved4 = 0;
4307 pSMB->hdr.smb_buf_length += byte_count;
4308 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4309 pSMB->ByteCount = cpu_to_le16(byte_count);
4310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4312 if (rc) {
4313 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4316 cifs_buf_release(pSMB);
4318 if (rc == -EAGAIN)
4319 goto SetTimesRetry;
4321 return rc;
4324 /* Can not be used to set time stamps yet (due to old DOS time format) */
4325 /* Can be used to set attributes */
4326 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4327 handling it anyway and NT4 was what we thought it would be needed for
4328 Do not delete it until we prove whether needed for Win9x though */
4330 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4331 __u16 dos_attrs, const struct nls_table *nls_codepage)
4333 SETATTR_REQ *pSMB = NULL;
4334 SETATTR_RSP *pSMBr = NULL;
4335 int rc = 0;
4336 int bytes_returned;
4337 int name_len;
4339 cFYI(1, ("In SetAttrLegacy"));
4341 SetAttrLgcyRetry:
4342 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4343 (void **) &pSMBr);
4344 if (rc)
4345 return rc;
4347 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4348 name_len =
4349 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4350 PATH_MAX, nls_codepage);
4351 name_len++; /* trailing null */
4352 name_len *= 2;
4353 } else { /* BB improve the check for buffer overruns BB */
4354 name_len = strnlen(fileName, PATH_MAX);
4355 name_len++; /* trailing null */
4356 strncpy(pSMB->fileName, fileName, name_len);
4358 pSMB->attr = cpu_to_le16(dos_attrs);
4359 pSMB->BufferFormat = 0x04;
4360 pSMB->hdr.smb_buf_length += name_len + 1;
4361 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4362 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4363 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4364 if (rc) {
4365 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4368 cifs_buf_release(pSMB);
4370 if (rc == -EAGAIN)
4371 goto SetAttrLgcyRetry;
4373 return rc;
4375 #endif /* temporarily unneeded SetAttr legacy function */
4378 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4379 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4380 dev_t device, const struct nls_table *nls_codepage,
4381 int remap)
4383 TRANSACTION2_SPI_REQ *pSMB = NULL;
4384 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4385 int name_len;
4386 int rc = 0;
4387 int bytes_returned = 0;
4388 FILE_UNIX_BASIC_INFO *data_offset;
4389 __u16 params, param_offset, offset, count, byte_count;
4391 cFYI(1, ("In SetUID/GID/Mode"));
4392 setPermsRetry:
4393 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4394 (void **) &pSMBr);
4395 if (rc)
4396 return rc;
4398 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4399 name_len =
4400 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4401 PATH_MAX, nls_codepage, remap);
4402 name_len++; /* trailing null */
4403 name_len *= 2;
4404 } else { /* BB improve the check for buffer overruns BB */
4405 name_len = strnlen(fileName, PATH_MAX);
4406 name_len++; /* trailing null */
4407 strncpy(pSMB->FileName, fileName, name_len);
4410 params = 6 + name_len;
4411 count = sizeof (FILE_UNIX_BASIC_INFO);
4412 pSMB->MaxParameterCount = cpu_to_le16(2);
4413 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4414 pSMB->MaxSetupCount = 0;
4415 pSMB->Reserved = 0;
4416 pSMB->Flags = 0;
4417 pSMB->Timeout = 0;
4418 pSMB->Reserved2 = 0;
4419 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4420 InformationLevel) - 4;
4421 offset = param_offset + params;
4422 data_offset =
4423 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4424 offset);
4425 memset(data_offset, 0, count);
4426 pSMB->DataOffset = cpu_to_le16(offset);
4427 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4428 pSMB->SetupCount = 1;
4429 pSMB->Reserved3 = 0;
4430 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4431 byte_count = 3 /* pad */ + params + count;
4432 pSMB->ParameterCount = cpu_to_le16(params);
4433 pSMB->DataCount = cpu_to_le16(count);
4434 pSMB->TotalParameterCount = pSMB->ParameterCount;
4435 pSMB->TotalDataCount = pSMB->DataCount;
4436 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4437 pSMB->Reserved4 = 0;
4438 pSMB->hdr.smb_buf_length += byte_count;
4439 data_offset->Uid = cpu_to_le64(uid);
4440 data_offset->Gid = cpu_to_le64(gid);
4441 /* better to leave device as zero when it is */
4442 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4443 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4444 data_offset->Permissions = cpu_to_le64(mode);
4446 if(S_ISREG(mode))
4447 data_offset->Type = cpu_to_le32(UNIX_FILE);
4448 else if(S_ISDIR(mode))
4449 data_offset->Type = cpu_to_le32(UNIX_DIR);
4450 else if(S_ISLNK(mode))
4451 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4452 else if(S_ISCHR(mode))
4453 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4454 else if(S_ISBLK(mode))
4455 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4456 else if(S_ISFIFO(mode))
4457 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4458 else if(S_ISSOCK(mode))
4459 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4462 pSMB->ByteCount = cpu_to_le16(byte_count);
4463 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4464 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4465 if (rc) {
4466 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4469 if (pSMB)
4470 cifs_buf_release(pSMB);
4471 if (rc == -EAGAIN)
4472 goto setPermsRetry;
4473 return rc;
4476 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4477 const int notify_subdirs, const __u16 netfid,
4478 __u32 filter, struct file * pfile, int multishot,
4479 const struct nls_table *nls_codepage)
4481 int rc = 0;
4482 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4483 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4484 struct dir_notify_req *dnotify_req;
4485 int bytes_returned;
4487 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4488 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4489 (void **) &pSMBr);
4490 if (rc)
4491 return rc;
4493 pSMB->TotalParameterCount = 0 ;
4494 pSMB->TotalDataCount = 0;
4495 pSMB->MaxParameterCount = cpu_to_le32(2);
4496 /* BB find exact data count max from sess structure BB */
4497 pSMB->MaxDataCount = 0; /* same in little endian or be */
4498 /* BB VERIFY verify which is correct for above BB */
4499 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4500 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4502 pSMB->MaxSetupCount = 4;
4503 pSMB->Reserved = 0;
4504 pSMB->ParameterOffset = 0;
4505 pSMB->DataCount = 0;
4506 pSMB->DataOffset = 0;
4507 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4508 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4509 pSMB->ParameterCount = pSMB->TotalParameterCount;
4510 if(notify_subdirs)
4511 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4512 pSMB->Reserved2 = 0;
4513 pSMB->CompletionFilter = cpu_to_le32(filter);
4514 pSMB->Fid = netfid; /* file handle always le */
4515 pSMB->ByteCount = 0;
4517 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4518 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4519 if (rc) {
4520 cFYI(1, ("Error in Notify = %d", rc));
4521 } else {
4522 /* Add file to outstanding requests */
4523 /* BB change to kmem cache alloc */
4524 dnotify_req = (struct dir_notify_req *) kmalloc(
4525 sizeof(struct dir_notify_req),
4526 GFP_KERNEL);
4527 if(dnotify_req) {
4528 dnotify_req->Pid = pSMB->hdr.Pid;
4529 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4530 dnotify_req->Mid = pSMB->hdr.Mid;
4531 dnotify_req->Tid = pSMB->hdr.Tid;
4532 dnotify_req->Uid = pSMB->hdr.Uid;
4533 dnotify_req->netfid = netfid;
4534 dnotify_req->pfile = pfile;
4535 dnotify_req->filter = filter;
4536 dnotify_req->multishot = multishot;
4537 spin_lock(&GlobalMid_Lock);
4538 list_add_tail(&dnotify_req->lhead,
4539 &GlobalDnotifyReqList);
4540 spin_unlock(&GlobalMid_Lock);
4541 } else
4542 rc = -ENOMEM;
4544 cifs_buf_release(pSMB);
4545 return rc;
4547 #ifdef CONFIG_CIFS_XATTR
4548 ssize_t
4549 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4550 const unsigned char *searchName,
4551 char * EAData, size_t buf_size,
4552 const struct nls_table *nls_codepage, int remap)
4554 /* BB assumes one setup word */
4555 TRANSACTION2_QPI_REQ *pSMB = NULL;
4556 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4557 int rc = 0;
4558 int bytes_returned;
4559 int name_len;
4560 struct fea * temp_fea;
4561 char * temp_ptr;
4562 __u16 params, byte_count;
4564 cFYI(1, ("In Query All EAs path %s", searchName));
4565 QAllEAsRetry:
4566 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4567 (void **) &pSMBr);
4568 if (rc)
4569 return rc;
4571 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4572 name_len =
4573 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4574 PATH_MAX, nls_codepage, remap);
4575 name_len++; /* trailing null */
4576 name_len *= 2;
4577 } else { /* BB improve the check for buffer overruns BB */
4578 name_len = strnlen(searchName, PATH_MAX);
4579 name_len++; /* trailing null */
4580 strncpy(pSMB->FileName, searchName, name_len);
4583 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4584 pSMB->TotalDataCount = 0;
4585 pSMB->MaxParameterCount = cpu_to_le16(2);
4586 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4587 pSMB->MaxSetupCount = 0;
4588 pSMB->Reserved = 0;
4589 pSMB->Flags = 0;
4590 pSMB->Timeout = 0;
4591 pSMB->Reserved2 = 0;
4592 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4593 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4594 pSMB->DataCount = 0;
4595 pSMB->DataOffset = 0;
4596 pSMB->SetupCount = 1;
4597 pSMB->Reserved3 = 0;
4598 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4599 byte_count = params + 1 /* pad */ ;
4600 pSMB->TotalParameterCount = cpu_to_le16(params);
4601 pSMB->ParameterCount = pSMB->TotalParameterCount;
4602 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4603 pSMB->Reserved4 = 0;
4604 pSMB->hdr.smb_buf_length += byte_count;
4605 pSMB->ByteCount = cpu_to_le16(byte_count);
4607 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4609 if (rc) {
4610 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4611 } else { /* decode response */
4612 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4614 /* BB also check enough total bytes returned */
4615 /* BB we need to improve the validity checking
4616 of these trans2 responses */
4617 if (rc || (pSMBr->ByteCount < 4))
4618 rc = -EIO; /* bad smb */
4619 /* else if (pFindData){
4620 memcpy((char *) pFindData,
4621 (char *) &pSMBr->hdr.Protocol +
4622 data_offset, kl);
4623 }*/ else {
4624 /* check that length of list is not more than bcc */
4625 /* check that each entry does not go beyond length
4626 of list */
4627 /* check that each element of each entry does not
4628 go beyond end of list */
4629 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4630 struct fealist * ea_response_data;
4631 rc = 0;
4632 /* validate_trans2_offsets() */
4633 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4634 ea_response_data = (struct fealist *)
4635 (((char *) &pSMBr->hdr.Protocol) +
4636 data_offset);
4637 name_len = le32_to_cpu(ea_response_data->list_len);
4638 cFYI(1,("ea length %d", name_len));
4639 if(name_len <= 8) {
4640 /* returned EA size zeroed at top of function */
4641 cFYI(1,("empty EA list returned from server"));
4642 } else {
4643 /* account for ea list len */
4644 name_len -= 4;
4645 temp_fea = ea_response_data->list;
4646 temp_ptr = (char *)temp_fea;
4647 while(name_len > 0) {
4648 __u16 value_len;
4649 name_len -= 4;
4650 temp_ptr += 4;
4651 rc += temp_fea->name_len;
4652 /* account for prefix user. and trailing null */
4653 rc = rc + 5 + 1;
4654 if(rc<(int)buf_size) {
4655 memcpy(EAData,"user.",5);
4656 EAData+=5;
4657 memcpy(EAData,temp_ptr,temp_fea->name_len);
4658 EAData+=temp_fea->name_len;
4659 /* null terminate name */
4660 *EAData = 0;
4661 EAData = EAData + 1;
4662 } else if(buf_size == 0) {
4663 /* skip copy - calc size only */
4664 } else {
4665 /* stop before overrun buffer */
4666 rc = -ERANGE;
4667 break;
4669 name_len -= temp_fea->name_len;
4670 temp_ptr += temp_fea->name_len;
4671 /* account for trailing null */
4672 name_len--;
4673 temp_ptr++;
4674 value_len = le16_to_cpu(temp_fea->value_len);
4675 name_len -= value_len;
4676 temp_ptr += value_len;
4677 /* BB check that temp_ptr is still within smb BB*/
4678 /* no trailing null to account for in value len */
4679 /* go on to next EA */
4680 temp_fea = (struct fea *)temp_ptr;
4685 if (pSMB)
4686 cifs_buf_release(pSMB);
4687 if (rc == -EAGAIN)
4688 goto QAllEAsRetry;
4690 return (ssize_t)rc;
4693 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4694 const unsigned char * searchName,const unsigned char * ea_name,
4695 unsigned char * ea_value, size_t buf_size,
4696 const struct nls_table *nls_codepage, int remap)
4698 TRANSACTION2_QPI_REQ *pSMB = NULL;
4699 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4700 int rc = 0;
4701 int bytes_returned;
4702 int name_len;
4703 struct fea * temp_fea;
4704 char * temp_ptr;
4705 __u16 params, byte_count;
4707 cFYI(1, ("In Query EA path %s", searchName));
4708 QEARetry:
4709 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4710 (void **) &pSMBr);
4711 if (rc)
4712 return rc;
4714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4715 name_len =
4716 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4717 PATH_MAX, nls_codepage, remap);
4718 name_len++; /* trailing null */
4719 name_len *= 2;
4720 } else { /* BB improve the check for buffer overruns BB */
4721 name_len = strnlen(searchName, PATH_MAX);
4722 name_len++; /* trailing null */
4723 strncpy(pSMB->FileName, searchName, name_len);
4726 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4727 pSMB->TotalDataCount = 0;
4728 pSMB->MaxParameterCount = cpu_to_le16(2);
4729 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4730 pSMB->MaxSetupCount = 0;
4731 pSMB->Reserved = 0;
4732 pSMB->Flags = 0;
4733 pSMB->Timeout = 0;
4734 pSMB->Reserved2 = 0;
4735 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4736 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4737 pSMB->DataCount = 0;
4738 pSMB->DataOffset = 0;
4739 pSMB->SetupCount = 1;
4740 pSMB->Reserved3 = 0;
4741 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4742 byte_count = params + 1 /* pad */ ;
4743 pSMB->TotalParameterCount = cpu_to_le16(params);
4744 pSMB->ParameterCount = pSMB->TotalParameterCount;
4745 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4746 pSMB->Reserved4 = 0;
4747 pSMB->hdr.smb_buf_length += byte_count;
4748 pSMB->ByteCount = cpu_to_le16(byte_count);
4750 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4751 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4752 if (rc) {
4753 cFYI(1, ("Send error in Query EA = %d", rc));
4754 } else { /* decode response */
4755 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4757 /* BB also check enough total bytes returned */
4758 /* BB we need to improve the validity checking
4759 of these trans2 responses */
4760 if (rc || (pSMBr->ByteCount < 4))
4761 rc = -EIO; /* bad smb */
4762 /* else if (pFindData){
4763 memcpy((char *) pFindData,
4764 (char *) &pSMBr->hdr.Protocol +
4765 data_offset, kl);
4766 }*/ else {
4767 /* check that length of list is not more than bcc */
4768 /* check that each entry does not go beyond length
4769 of list */
4770 /* check that each element of each entry does not
4771 go beyond end of list */
4772 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4773 struct fealist * ea_response_data;
4774 rc = -ENODATA;
4775 /* validate_trans2_offsets() */
4776 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4777 ea_response_data = (struct fealist *)
4778 (((char *) &pSMBr->hdr.Protocol) +
4779 data_offset);
4780 name_len = le32_to_cpu(ea_response_data->list_len);
4781 cFYI(1,("ea length %d", name_len));
4782 if(name_len <= 8) {
4783 /* returned EA size zeroed at top of function */
4784 cFYI(1,("empty EA list returned from server"));
4785 } else {
4786 /* account for ea list len */
4787 name_len -= 4;
4788 temp_fea = ea_response_data->list;
4789 temp_ptr = (char *)temp_fea;
4790 /* loop through checking if we have a matching
4791 name and then return the associated value */
4792 while(name_len > 0) {
4793 __u16 value_len;
4794 name_len -= 4;
4795 temp_ptr += 4;
4796 value_len = le16_to_cpu(temp_fea->value_len);
4797 /* BB validate that value_len falls within SMB,
4798 even though maximum for name_len is 255 */
4799 if(memcmp(temp_fea->name,ea_name,
4800 temp_fea->name_len) == 0) {
4801 /* found a match */
4802 rc = value_len;
4803 /* account for prefix user. and trailing null */
4804 if(rc<=(int)buf_size) {
4805 memcpy(ea_value,
4806 temp_fea->name+temp_fea->name_len+1,
4807 rc);
4808 /* ea values, unlike ea names,
4809 are not null terminated */
4810 } else if(buf_size == 0) {
4811 /* skip copy - calc size only */
4812 } else {
4813 /* stop before overrun buffer */
4814 rc = -ERANGE;
4816 break;
4818 name_len -= temp_fea->name_len;
4819 temp_ptr += temp_fea->name_len;
4820 /* account for trailing null */
4821 name_len--;
4822 temp_ptr++;
4823 name_len -= value_len;
4824 temp_ptr += value_len;
4825 /* no trailing null to account for in value len */
4826 /* go on to next EA */
4827 temp_fea = (struct fea *)temp_ptr;
4832 if (pSMB)
4833 cifs_buf_release(pSMB);
4834 if (rc == -EAGAIN)
4835 goto QEARetry;
4837 return (ssize_t)rc;
4841 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4842 const char * ea_name, const void * ea_value,
4843 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4844 int remap)
4846 struct smb_com_transaction2_spi_req *pSMB = NULL;
4847 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4848 struct fealist *parm_data;
4849 int name_len;
4850 int rc = 0;
4851 int bytes_returned = 0;
4852 __u16 params, param_offset, byte_count, offset, count;
4854 cFYI(1, ("In SetEA"));
4855 SetEARetry:
4856 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4857 (void **) &pSMBr);
4858 if (rc)
4859 return rc;
4861 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4862 name_len =
4863 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4864 PATH_MAX, nls_codepage, remap);
4865 name_len++; /* trailing null */
4866 name_len *= 2;
4867 } else { /* BB improve the check for buffer overruns BB */
4868 name_len = strnlen(fileName, PATH_MAX);
4869 name_len++; /* trailing null */
4870 strncpy(pSMB->FileName, fileName, name_len);
4873 params = 6 + name_len;
4875 /* done calculating parms using name_len of file name,
4876 now use name_len to calculate length of ea name
4877 we are going to create in the inode xattrs */
4878 if(ea_name == NULL)
4879 name_len = 0;
4880 else
4881 name_len = strnlen(ea_name,255);
4883 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4884 pSMB->MaxParameterCount = cpu_to_le16(2);
4885 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4886 pSMB->MaxSetupCount = 0;
4887 pSMB->Reserved = 0;
4888 pSMB->Flags = 0;
4889 pSMB->Timeout = 0;
4890 pSMB->Reserved2 = 0;
4891 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4892 InformationLevel) - 4;
4893 offset = param_offset + params;
4894 pSMB->InformationLevel =
4895 cpu_to_le16(SMB_SET_FILE_EA);
4897 parm_data =
4898 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4899 offset);
4900 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4901 pSMB->DataOffset = cpu_to_le16(offset);
4902 pSMB->SetupCount = 1;
4903 pSMB->Reserved3 = 0;
4904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4905 byte_count = 3 /* pad */ + params + count;
4906 pSMB->DataCount = cpu_to_le16(count);
4907 parm_data->list_len = cpu_to_le32(count);
4908 parm_data->list[0].EA_flags = 0;
4909 /* we checked above that name len is less than 255 */
4910 parm_data->list[0].name_len = (__u8)name_len;;
4911 /* EA names are always ASCII */
4912 if(ea_name)
4913 strncpy(parm_data->list[0].name,ea_name,name_len);
4914 parm_data->list[0].name[name_len] = 0;
4915 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4916 /* caller ensures that ea_value_len is less than 64K but
4917 we need to ensure that it fits within the smb */
4919 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4920 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4921 if(ea_value_len)
4922 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4924 pSMB->TotalDataCount = pSMB->DataCount;
4925 pSMB->ParameterCount = cpu_to_le16(params);
4926 pSMB->TotalParameterCount = pSMB->ParameterCount;
4927 pSMB->Reserved4 = 0;
4928 pSMB->hdr.smb_buf_length += byte_count;
4929 pSMB->ByteCount = cpu_to_le16(byte_count);
4930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4932 if (rc) {
4933 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4936 cifs_buf_release(pSMB);
4938 if (rc == -EAGAIN)
4939 goto SetEARetry;
4941 return rc;
4944 #endif