[CIFS] CIFS writepage improvements - eliminate double copy
[linux-2.6/verdex.git] / fs / cifs / cifssmb.c
blobb4f7b9859e3bedeb895a62d21ed44eda58354de8
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"
41 #ifdef CONFIG_CIFS_POSIX
42 static struct {
43 int index;
44 char *name;
45 } protocols[] = {
46 {CIFS_PROT, "\2NT LM 0.12"},
47 {CIFS_PROT, "\2POSIX 2"},
48 {BAD_PROT, "\2"}
50 #else
51 static struct {
52 int index;
53 char *name;
54 } protocols[] = {
55 {CIFS_PROT, "\2NT LM 0.12"},
56 {BAD_PROT, "\2"}
58 #endif
61 /* Mark as invalid, all open files on tree connections since they
62 were closed when session to server was lost */
63 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
65 struct cifsFileInfo *open_file = NULL;
66 struct list_head * tmp;
67 struct list_head * tmp1;
69 /* list all files open on tree connection and mark them invalid */
70 write_lock(&GlobalSMBSeslock);
71 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
72 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
73 if(open_file) {
74 open_file->invalidHandle = TRUE;
77 write_unlock(&GlobalSMBSeslock);
78 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
79 to this tcon */
82 /* If the return code is zero, this function must fill in request_buf pointer */
83 static int
84 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
85 void **request_buf /* returned */)
87 int rc = 0;
89 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
90 check for tcp and smb session status done differently
91 for those three - in the calling routine */
92 if(tcon) {
93 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
94 (tcon->ses->server)){
95 struct nls_table *nls_codepage;
96 /* Give Demultiplex thread up to 10 seconds to
97 reconnect, should be greater than cifs socket
98 timeout which is 7 seconds */
99 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
100 wait_event_interruptible_timeout(tcon->ses->server->response_q,
101 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
102 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
103 /* on "soft" mounts we wait once */
104 if((tcon->retry == FALSE) ||
105 (tcon->ses->status == CifsExiting)) {
106 cFYI(1,("gave up waiting on reconnect in smb_init"));
107 return -EHOSTDOWN;
108 } /* else "hard" mount - keep retrying
109 until process is killed or server
110 comes back on-line */
111 } else /* TCP session is reestablished now */
112 break;
116 nls_codepage = load_nls_default();
117 /* need to prevent multiple threads trying to
118 simultaneously reconnect the same SMB session */
119 down(&tcon->ses->sesSem);
120 if(tcon->ses->status == CifsNeedReconnect)
121 rc = cifs_setup_session(0, tcon->ses,
122 nls_codepage);
123 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
124 mark_open_files_invalid(tcon);
125 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
126 , nls_codepage);
127 up(&tcon->ses->sesSem);
128 if(rc == 0)
129 atomic_inc(&tconInfoReconnectCount);
131 cFYI(1, ("reconnect tcon rc = %d", rc));
132 /* Removed call to reopen open files here -
133 it is safer (and faster) to reopen files
134 one at a time as needed in read and write */
136 /* Check if handle based operation so we
137 know whether we can continue or not without
138 returning to caller to reset file handle */
139 switch(smb_command) {
140 case SMB_COM_READ_ANDX:
141 case SMB_COM_WRITE_ANDX:
142 case SMB_COM_CLOSE:
143 case SMB_COM_FIND_CLOSE2:
144 case SMB_COM_LOCKING_ANDX: {
145 unload_nls(nls_codepage);
146 return -EAGAIN;
149 } else {
150 up(&tcon->ses->sesSem);
152 unload_nls(nls_codepage);
154 } else {
155 return -EIO;
158 if(rc)
159 return rc;
161 *request_buf = cifs_small_buf_get();
162 if (*request_buf == NULL) {
163 /* BB should we add a retry in here if not a writepage? */
164 return -ENOMEM;
167 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
169 #ifdef CONFIG_CIFS_STATS
170 if(tcon != NULL) {
171 atomic_inc(&tcon->num_smbs_sent);
173 #endif /* CONFIG_CIFS_STATS */
174 return rc;
177 /* If the return code is zero, this function must fill in request_buf pointer */
178 static int
179 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
180 void **request_buf /* returned */ ,
181 void **response_buf /* returned */ )
183 int rc = 0;
185 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
186 check for tcp and smb session status done differently
187 for those three - in the calling routine */
188 if(tcon) {
189 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
190 (tcon->ses->server)){
191 struct nls_table *nls_codepage;
192 /* Give Demultiplex thread up to 10 seconds to
193 reconnect, should be greater than cifs socket
194 timeout which is 7 seconds */
195 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
196 wait_event_interruptible_timeout(tcon->ses->server->response_q,
197 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
198 if(tcon->ses->server->tcpStatus ==
199 CifsNeedReconnect) {
200 /* on "soft" mounts we wait once */
201 if((tcon->retry == FALSE) ||
202 (tcon->ses->status == CifsExiting)) {
203 cFYI(1,("gave up waiting on reconnect in smb_init"));
204 return -EHOSTDOWN;
205 } /* else "hard" mount - keep retrying
206 until process is killed or server
207 comes on-line */
208 } else /* TCP session is reestablished now */
209 break;
213 nls_codepage = load_nls_default();
214 /* need to prevent multiple threads trying to
215 simultaneously reconnect the same SMB session */
216 down(&tcon->ses->sesSem);
217 if(tcon->ses->status == CifsNeedReconnect)
218 rc = cifs_setup_session(0, tcon->ses,
219 nls_codepage);
220 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
221 mark_open_files_invalid(tcon);
222 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
223 tcon, nls_codepage);
224 up(&tcon->ses->sesSem);
225 if(rc == 0)
226 atomic_inc(&tconInfoReconnectCount);
228 cFYI(1, ("reconnect tcon rc = %d", rc));
229 /* Removed call to reopen open files here -
230 it is safer (and faster) to reopen files
231 one at a time as needed in read and write */
233 /* Check if handle based operation so we
234 know whether we can continue or not without
235 returning to caller to reset file handle */
236 switch(smb_command) {
237 case SMB_COM_READ_ANDX:
238 case SMB_COM_WRITE_ANDX:
239 case SMB_COM_CLOSE:
240 case SMB_COM_FIND_CLOSE2:
241 case SMB_COM_LOCKING_ANDX: {
242 unload_nls(nls_codepage);
243 return -EAGAIN;
246 } else {
247 up(&tcon->ses->sesSem);
249 unload_nls(nls_codepage);
251 } else {
252 return -EIO;
255 if(rc)
256 return rc;
258 *request_buf = cifs_buf_get();
259 if (*request_buf == NULL) {
260 /* BB should we add a retry in here if not a writepage? */
261 return -ENOMEM;
263 /* Although the original thought was we needed the response buf for */
264 /* potential retries of smb operations it turns out we can determine */
265 /* from the mid flags when the request buffer can be resent without */
266 /* having to use a second distinct buffer for the response */
267 *response_buf = *request_buf;
269 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
270 wct /*wct */ );
272 #ifdef CONFIG_CIFS_STATS
273 if(tcon != NULL) {
274 atomic_inc(&tcon->num_smbs_sent);
276 #endif /* CONFIG_CIFS_STATS */
277 return rc;
280 static int validate_t2(struct smb_t2_rsp * pSMB)
282 int rc = -EINVAL;
283 int total_size;
284 char * pBCC;
286 /* check for plausible wct, bcc and t2 data and parm sizes */
287 /* check for parm and data offset going beyond end of smb */
288 if(pSMB->hdr.WordCount >= 10) {
289 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
290 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
291 /* check that bcc is at least as big as parms + data */
292 /* check that bcc is less than negotiated smb buffer */
293 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
294 if(total_size < 512) {
295 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
296 /* BCC le converted in SendReceive */
297 pBCC = (pSMB->hdr.WordCount * 2) +
298 sizeof(struct smb_hdr) +
299 (char *)pSMB;
300 if((total_size <= (*(u16 *)pBCC)) &&
301 (total_size <
302 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
303 return 0;
309 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
310 sizeof(struct smb_t2_rsp) + 16);
311 return rc;
314 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
316 NEGOTIATE_REQ *pSMB;
317 NEGOTIATE_RSP *pSMBr;
318 int rc = 0;
319 int bytes_returned;
320 struct TCP_Server_Info * server;
321 u16 count;
323 if(ses->server)
324 server = ses->server;
325 else {
326 rc = -EIO;
327 return rc;
329 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
330 (void **) &pSMB, (void **) &pSMBr);
331 if (rc)
332 return rc;
334 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
335 if (extended_security)
336 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
338 count = strlen(protocols[0].name) + 1;
339 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
340 /* null guaranteed to be at end of source and target buffers anyway */
342 pSMB->hdr.smb_buf_length += count;
343 pSMB->ByteCount = cpu_to_le16(count);
345 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
347 if (rc == 0) {
348 server->secMode = pSMBr->SecurityMode;
349 server->secType = NTLM; /* BB override default for
350 NTLMv2 or kerberos v5 */
351 /* one byte - no need to convert this or EncryptionKeyLen
352 from little endian */
353 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
354 /* probably no need to store and check maxvcs */
355 server->maxBuf =
356 min(le32_to_cpu(pSMBr->MaxBufferSize),
357 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
358 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
359 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
360 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
361 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
362 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
363 /* BB with UTC do we ever need to be using srvr timezone? */
364 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
365 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
366 CIFS_CRYPTO_KEY_SIZE);
367 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
368 && (pSMBr->EncryptionKeyLength == 0)) {
369 /* decode security blob */
370 } else
371 rc = -EIO;
373 /* BB might be helpful to save off the domain of server here */
375 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
376 (server->capabilities & CAP_EXTENDED_SECURITY)) {
377 count = pSMBr->ByteCount;
378 if (count < 16)
379 rc = -EIO;
380 else if (count == 16) {
381 server->secType = RawNTLMSSP;
382 if (server->socketUseCount.counter > 1) {
383 if (memcmp
384 (server->server_GUID,
385 pSMBr->u.extended_response.
386 GUID, 16) != 0) {
387 cFYI(1,
388 ("UID of server does not match previous connection to same ip address"));
389 memcpy(server->
390 server_GUID,
391 pSMBr->u.
392 extended_response.
393 GUID, 16);
395 } else
396 memcpy(server->server_GUID,
397 pSMBr->u.extended_response.
398 GUID, 16);
399 } else {
400 rc = decode_negTokenInit(pSMBr->u.
401 extended_response.
402 SecurityBlob,
403 count - 16,
404 &server->secType);
405 if(rc == 1) {
406 /* BB Need to fill struct for sessetup here */
407 rc = -EOPNOTSUPP;
408 } else {
409 rc = -EINVAL;
412 } else
413 server->capabilities &= ~CAP_EXTENDED_SECURITY;
414 if(sign_CIFS_PDUs == FALSE) {
415 if(server->secMode & SECMODE_SIGN_REQUIRED)
416 cERROR(1,
417 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
418 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
419 } else if(sign_CIFS_PDUs == 1) {
420 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
421 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
425 if (pSMB)
426 cifs_buf_release(pSMB);
427 return rc;
431 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
433 struct smb_hdr *smb_buffer;
434 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
435 int rc = 0;
436 int length;
438 cFYI(1, ("In tree disconnect"));
440 * If last user of the connection and
441 * connection alive - disconnect it
442 * If this is the last connection on the server session disconnect it
443 * (and inside session disconnect we should check if tcp socket needs
444 * to be freed and kernel thread woken up).
446 if (tcon)
447 down(&tcon->tconSem);
448 else
449 return -EIO;
451 atomic_dec(&tcon->useCount);
452 if (atomic_read(&tcon->useCount) > 0) {
453 up(&tcon->tconSem);
454 return -EBUSY;
457 /* No need to return error on this operation if tid invalidated and
458 closed on server already e.g. due to tcp session crashing */
459 if(tcon->tidStatus == CifsNeedReconnect) {
460 up(&tcon->tconSem);
461 return 0;
464 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
465 up(&tcon->tconSem);
466 return -EIO;
468 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
469 (void **)&smb_buffer);
470 if (rc) {
471 up(&tcon->tconSem);
472 return rc;
473 } else {
474 smb_buffer_response = smb_buffer; /* BB removeme BB */
476 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
477 &length, 0);
478 if (rc)
479 cFYI(1, ("Tree disconnect failed %d", rc));
481 if (smb_buffer)
482 cifs_small_buf_release(smb_buffer);
483 up(&tcon->tconSem);
485 /* No need to return error on this operation if tid invalidated and
486 closed on server already e.g. due to tcp session crashing */
487 if (rc == -EAGAIN)
488 rc = 0;
490 return rc;
494 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
496 struct smb_hdr *smb_buffer_response;
497 LOGOFF_ANDX_REQ *pSMB;
498 int rc = 0;
499 int length;
501 cFYI(1, ("In SMBLogoff for session disconnect"));
502 if (ses)
503 down(&ses->sesSem);
504 else
505 return -EIO;
507 atomic_dec(&ses->inUse);
508 if (atomic_read(&ses->inUse) > 0) {
509 up(&ses->sesSem);
510 return -EBUSY;
512 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
513 if (rc) {
514 up(&ses->sesSem);
515 return rc;
518 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
520 if(ses->server) {
521 if(ses->server->secMode &
522 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
523 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
526 pSMB->hdr.Uid = ses->Suid;
528 pSMB->AndXCommand = 0xFF;
529 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
530 smb_buffer_response, &length, 0);
531 if (ses->server) {
532 atomic_dec(&ses->server->socketUseCount);
533 if (atomic_read(&ses->server->socketUseCount) == 0) {
534 spin_lock(&GlobalMid_Lock);
535 ses->server->tcpStatus = CifsExiting;
536 spin_unlock(&GlobalMid_Lock);
537 rc = -ESHUTDOWN;
540 if (pSMB)
541 cifs_small_buf_release(pSMB);
542 up(&ses->sesSem);
544 /* if session dead then we do not need to do ulogoff,
545 since server closed smb session, no sense reporting
546 error */
547 if (rc == -EAGAIN)
548 rc = 0;
549 return rc;
553 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
554 const struct nls_table *nls_codepage, int remap)
556 DELETE_FILE_REQ *pSMB = NULL;
557 DELETE_FILE_RSP *pSMBr = NULL;
558 int rc = 0;
559 int bytes_returned;
560 int name_len;
562 DelFileRetry:
563 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
564 (void **) &pSMBr);
565 if (rc)
566 return rc;
568 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
569 name_len =
570 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
571 PATH_MAX, nls_codepage, remap);
572 name_len++; /* trailing null */
573 name_len *= 2;
574 } else { /* BB improve check for buffer overruns BB */
575 name_len = strnlen(fileName, PATH_MAX);
576 name_len++; /* trailing null */
577 strncpy(pSMB->fileName, fileName, name_len);
579 pSMB->SearchAttributes =
580 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
581 pSMB->BufferFormat = 0x04;
582 pSMB->hdr.smb_buf_length += name_len + 1;
583 pSMB->ByteCount = cpu_to_le16(name_len + 1);
584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
586 if (rc) {
587 cFYI(1, ("Error in RMFile = %d", rc));
589 #ifdef CONFIG_CIFS_STATS
590 else {
591 atomic_inc(&tcon->num_deletes);
593 #endif
595 cifs_buf_release(pSMB);
596 if (rc == -EAGAIN)
597 goto DelFileRetry;
599 return rc;
603 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
604 const struct nls_table *nls_codepage, int remap)
606 DELETE_DIRECTORY_REQ *pSMB = NULL;
607 DELETE_DIRECTORY_RSP *pSMBr = NULL;
608 int rc = 0;
609 int bytes_returned;
610 int name_len;
612 cFYI(1, ("In CIFSSMBRmDir"));
613 RmDirRetry:
614 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
615 (void **) &pSMBr);
616 if (rc)
617 return rc;
619 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
620 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
621 PATH_MAX, nls_codepage, remap);
622 name_len++; /* trailing null */
623 name_len *= 2;
624 } else { /* BB improve check for buffer overruns BB */
625 name_len = strnlen(dirName, PATH_MAX);
626 name_len++; /* trailing null */
627 strncpy(pSMB->DirName, dirName, name_len);
630 pSMB->BufferFormat = 0x04;
631 pSMB->hdr.smb_buf_length += name_len + 1;
632 pSMB->ByteCount = cpu_to_le16(name_len + 1);
633 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
634 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
635 if (rc) {
636 cFYI(1, ("Error in RMDir = %d", rc));
638 #ifdef CONFIG_CIFS_STATS
639 else {
640 atomic_inc(&tcon->num_rmdirs);
642 #endif
644 cifs_buf_release(pSMB);
645 if (rc == -EAGAIN)
646 goto RmDirRetry;
647 return rc;
651 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
652 const char *name, const struct nls_table *nls_codepage, int remap)
654 int rc = 0;
655 CREATE_DIRECTORY_REQ *pSMB = NULL;
656 CREATE_DIRECTORY_RSP *pSMBr = NULL;
657 int bytes_returned;
658 int name_len;
660 cFYI(1, ("In CIFSSMBMkDir"));
661 MkDirRetry:
662 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
663 (void **) &pSMBr);
664 if (rc)
665 return rc;
667 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
668 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
669 PATH_MAX, nls_codepage, remap);
670 name_len++; /* trailing null */
671 name_len *= 2;
672 } else { /* BB improve check for buffer overruns BB */
673 name_len = strnlen(name, PATH_MAX);
674 name_len++; /* trailing null */
675 strncpy(pSMB->DirName, name, name_len);
678 pSMB->BufferFormat = 0x04;
679 pSMB->hdr.smb_buf_length += name_len + 1;
680 pSMB->ByteCount = cpu_to_le16(name_len + 1);
681 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
683 if (rc) {
684 cFYI(1, ("Error in Mkdir = %d", rc));
686 #ifdef CONFIG_CIFS_STATS
687 else {
688 atomic_inc(&tcon->num_mkdirs);
690 #endif
691 cifs_buf_release(pSMB);
692 if (rc == -EAGAIN)
693 goto MkDirRetry;
694 return rc;
698 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
699 const char *fileName, const int openDisposition,
700 const int access_flags, const int create_options, __u16 * netfid,
701 int *pOplock, FILE_ALL_INFO * pfile_info,
702 const struct nls_table *nls_codepage, int remap)
704 int rc = -EACCES;
705 OPEN_REQ *pSMB = NULL;
706 OPEN_RSP *pSMBr = NULL;
707 int bytes_returned;
708 int name_len;
709 __u16 count;
711 openRetry:
712 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
713 (void **) &pSMBr);
714 if (rc)
715 return rc;
717 pSMB->AndXCommand = 0xFF; /* none */
719 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
720 count = 1; /* account for one byte pad to word boundary */
721 name_len =
722 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
723 fileName, PATH_MAX, nls_codepage, remap);
724 name_len++; /* trailing null */
725 name_len *= 2;
726 pSMB->NameLength = cpu_to_le16(name_len);
727 } else { /* BB improve check for buffer overruns BB */
728 count = 0; /* no pad */
729 name_len = strnlen(fileName, PATH_MAX);
730 name_len++; /* trailing null */
731 pSMB->NameLength = cpu_to_le16(name_len);
732 strncpy(pSMB->fileName, fileName, name_len);
734 if (*pOplock & REQ_OPLOCK)
735 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
736 else if (*pOplock & REQ_BATCHOPLOCK) {
737 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
739 pSMB->DesiredAccess = cpu_to_le32(access_flags);
740 pSMB->AllocationSize = 0;
741 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
742 /* XP does not handle ATTR_POSIX_SEMANTICS */
743 /* but it helps speed up case sensitive checks for other
744 servers such as Samba */
745 if (tcon->ses->capabilities & CAP_UNIX)
746 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
748 /* if ((omode & S_IWUGO) == 0)
749 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
750 /* Above line causes problems due to vfs splitting create into two
751 pieces - need to set mode after file created not while it is
752 being created */
753 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
754 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
755 pSMB->CreateOptions = cpu_to_le32(create_options);
756 /* BB Expirement with various impersonation levels and verify */
757 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
758 pSMB->SecurityFlags =
759 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
761 count += name_len;
762 pSMB->hdr.smb_buf_length += count;
764 pSMB->ByteCount = cpu_to_le16(count);
765 /* long_op set to 1 to allow for oplock break timeouts */
766 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
767 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
768 if (rc) {
769 cFYI(1, ("Error in Open = %d", rc));
770 } else {
771 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
772 *netfid = pSMBr->Fid; /* cifs fid stays in le */
773 /* Let caller know file was created so we can set the mode. */
774 /* Do we care about the CreateAction in any other cases? */
775 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
776 *pOplock |= CIFS_CREATE_ACTION;
777 if(pfile_info) {
778 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
779 36 /* CreationTime to Attributes */);
780 /* the file_info buf is endian converted by caller */
781 pfile_info->AllocationSize = pSMBr->AllocationSize;
782 pfile_info->EndOfFile = pSMBr->EndOfFile;
783 pfile_info->NumberOfLinks = cpu_to_le32(1);
786 #ifdef CONFIG_CIFS_STATS
787 atomic_inc(&tcon->num_opens);
788 #endif
790 cifs_buf_release(pSMB);
791 if (rc == -EAGAIN)
792 goto openRetry;
793 return rc;
796 /* If no buffer passed in, then caller wants to do the copy
797 as in the case of readpages so the SMB buffer must be
798 freed by the caller */
801 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
802 const int netfid, const unsigned int count,
803 const __u64 lseek, unsigned int *nbytes, char **buf)
805 int rc = -EACCES;
806 READ_REQ *pSMB = NULL;
807 READ_RSP *pSMBr = NULL;
808 char *pReadData = NULL;
809 int bytes_returned;
811 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
813 *nbytes = 0;
814 rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
815 (void **) &pSMBr);
816 if (rc)
817 return rc;
819 /* tcon and ses pointer are checked in smb_init */
820 if (tcon->ses->server == NULL)
821 return -ECONNABORTED;
823 pSMB->AndXCommand = 0xFF; /* none */
824 pSMB->Fid = netfid;
825 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
826 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
827 pSMB->Remaining = 0;
828 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
829 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
830 pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
832 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
833 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
834 if (rc) {
835 cERROR(1, ("Send error in read = %d", rc));
836 } else {
837 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
838 data_length = data_length << 16;
839 data_length += le16_to_cpu(pSMBr->DataLength);
840 *nbytes = data_length;
842 /*check that DataLength would not go beyond end of SMB */
843 if ((data_length > CIFSMaxBufSize)
844 || (data_length > count)) {
845 cFYI(1,("bad length %d for count %d",data_length,count));
846 rc = -EIO;
847 *nbytes = 0;
848 } else {
849 pReadData =
850 (char *) (&pSMBr->hdr.Protocol) +
851 le16_to_cpu(pSMBr->DataOffset);
852 /* if(rc = copy_to_user(buf, pReadData, data_length)) {
853 cERROR(1,("Faulting on read rc = %d",rc));
854 rc = -EFAULT;
855 }*/ /* can not use copy_to_user when using page cache*/
856 if(*buf)
857 memcpy(*buf,pReadData,data_length);
860 if(*buf)
861 cifs_buf_release(pSMB);
862 else
863 *buf = (char *)pSMB;
865 /* Note: On -EAGAIN error only caller can retry on handle based calls
866 since file handle passed in no longer valid */
867 return rc;
871 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
872 const int netfid, const unsigned int count,
873 const __u64 offset, unsigned int *nbytes, const char *buf,
874 const char __user * ubuf, const int long_op)
876 int rc = -EACCES;
877 WRITE_REQ *pSMB = NULL;
878 WRITE_RSP *pSMBr = NULL;
879 int bytes_returned;
880 __u32 bytes_sent;
881 __u16 byte_count;
883 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
884 rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
885 (void **) &pSMBr);
886 if (rc)
887 return rc;
888 /* tcon and ses pointer are checked in smb_init */
889 if (tcon->ses->server == NULL)
890 return -ECONNABORTED;
892 pSMB->AndXCommand = 0xFF; /* none */
893 pSMB->Fid = netfid;
894 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
895 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
896 pSMB->Reserved = 0xFFFFFFFF;
897 pSMB->WriteMode = 0;
898 pSMB->Remaining = 0;
900 /* Can increase buffer size if buffer is big enough in some cases - ie we
901 can send more if LARGE_WRITE_X capability returned by the server and if
902 our buffer is big enough or if we convert to iovecs on socket writes
903 and eliminate the copy to the CIFS buffer */
904 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
905 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
906 } else {
907 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
908 & ~0xFF;
911 if (bytes_sent > count)
912 bytes_sent = count;
913 pSMB->DataOffset =
914 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
915 if(buf)
916 memcpy(pSMB->Data,buf,bytes_sent);
917 else if(ubuf) {
918 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
919 cifs_buf_release(pSMB);
920 return -EFAULT;
922 } else {
923 /* No buffer */
924 cifs_buf_release(pSMB);
925 return -EINVAL;
928 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
929 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
930 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
931 pSMB->hdr.smb_buf_length += bytes_sent+1;
932 pSMB->ByteCount = cpu_to_le16(byte_count);
934 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
935 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
936 if (rc) {
937 cFYI(1, ("Send error in write = %d", rc));
938 *nbytes = 0;
939 } else {
940 *nbytes = le16_to_cpu(pSMBr->CountHigh);
941 *nbytes = (*nbytes) << 16;
942 *nbytes += le16_to_cpu(pSMBr->Count);
945 cifs_buf_release(pSMB);
947 /* Note: On -EAGAIN error only caller can retry on handle based calls
948 since file handle passed in no longer valid */
950 return rc;
953 #ifdef CONFIG_CIFS_EXPERIMENTAL
955 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
956 const int netfid, const unsigned int count,
957 const __u64 offset, unsigned int *nbytes, const char *buf,
958 const int long_op)
960 int rc = -EACCES;
961 WRITE_REQ *pSMB = NULL;
962 int bytes_returned;
963 int smb_hdr_len;
964 __u32 bytes_sent;
965 __u16 byte_count;
967 cERROR(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
968 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
969 if (rc)
970 return rc;
971 /* tcon and ses pointer are checked in smb_init */
972 if (tcon->ses->server == NULL)
973 return -ECONNABORTED;
975 pSMB->AndXCommand = 0xFF; /* none */
976 pSMB->Fid = netfid;
977 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
978 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
979 pSMB->Reserved = 0xFFFFFFFF;
980 pSMB->WriteMode = 0;
981 pSMB->Remaining = 0;
983 /* Can increase buffer size if buffer is big enough in some cases - ie
984 can send more if LARGE_WRITE_X capability returned by the server and if
985 our buffer is big enough or if we convert to iovecs on socket writes
986 and eliminate the copy to the CIFS buffer */
987 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
988 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
989 } else {
990 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
991 & ~0xFF;
994 if (bytes_sent > count)
995 bytes_sent = count;
996 pSMB->DataOffset =
997 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
999 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1000 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1001 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1002 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1003 pSMB->hdr.smb_buf_length += bytes_sent+1;
1004 pSMB->ByteCount = cpu_to_le16(byte_count);
1006 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1007 buf, bytes_sent, &bytes_returned, long_op);
1008 if (rc) {
1009 cFYI(1, ("Send error in write = %d", rc));
1010 *nbytes = 0;
1011 } else {
1012 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1013 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1014 *nbytes = (*nbytes) << 16;
1015 *nbytes += le16_to_cpu(pSMBr->Count);
1018 cifs_small_buf_release(pSMB);
1020 /* Note: On -EAGAIN error only caller can retry on handle based calls
1021 since file handle passed in no longer valid */
1023 return rc;
1027 #endif /* CIFS_EXPERIMENTAL */
1030 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1031 const __u16 smb_file_id, const __u64 len,
1032 const __u64 offset, const __u32 numUnlock,
1033 const __u32 numLock, const __u8 lockType, const int waitFlag)
1035 int rc = 0;
1036 LOCK_REQ *pSMB = NULL;
1037 LOCK_RSP *pSMBr = NULL;
1038 int bytes_returned;
1039 int timeout = 0;
1040 __u16 count;
1042 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1043 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1045 if (rc)
1046 return rc;
1048 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1050 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1051 timeout = -1; /* no response expected */
1052 pSMB->Timeout = 0;
1053 } else if (waitFlag == TRUE) {
1054 timeout = 3; /* blocking operation, no timeout */
1055 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1056 } else {
1057 pSMB->Timeout = 0;
1060 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1061 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1062 pSMB->LockType = lockType;
1063 pSMB->AndXCommand = 0xFF; /* none */
1064 pSMB->Fid = smb_file_id; /* netfid stays le */
1066 if((numLock != 0) || (numUnlock != 0)) {
1067 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1068 /* BB where to store pid high? */
1069 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1070 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1071 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1072 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1073 count = sizeof(LOCKING_ANDX_RANGE);
1074 } else {
1075 /* oplock break */
1076 count = 0;
1078 pSMB->hdr.smb_buf_length += count;
1079 pSMB->ByteCount = cpu_to_le16(count);
1081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1082 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1084 if (rc) {
1085 cFYI(1, ("Send error in Lock = %d", rc));
1087 cifs_small_buf_release(pSMB);
1089 /* Note: On -EAGAIN error only caller can retry on handle based calls
1090 since file handle passed in no longer valid */
1091 return rc;
1095 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1097 int rc = 0;
1098 CLOSE_REQ *pSMB = NULL;
1099 CLOSE_RSP *pSMBr = NULL;
1100 int bytes_returned;
1101 cFYI(1, ("In CIFSSMBClose"));
1103 /* do not retry on dead session on close */
1104 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1105 if(rc == -EAGAIN)
1106 return 0;
1107 if (rc)
1108 return rc;
1110 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1112 pSMB->FileID = (__u16) smb_file_id;
1113 pSMB->LastWriteTime = 0;
1114 pSMB->ByteCount = 0;
1115 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1116 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1117 if (rc) {
1118 if(rc!=-EINTR) {
1119 /* EINTR is expected when user ctl-c to kill app */
1120 cERROR(1, ("Send error in Close = %d", rc));
1124 cifs_small_buf_release(pSMB);
1126 /* Since session is dead, file will be closed on server already */
1127 if(rc == -EAGAIN)
1128 rc = 0;
1130 return rc;
1134 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1135 const char *fromName, const char *toName,
1136 const struct nls_table *nls_codepage, int remap)
1138 int rc = 0;
1139 RENAME_REQ *pSMB = NULL;
1140 RENAME_RSP *pSMBr = NULL;
1141 int bytes_returned;
1142 int name_len, name_len2;
1143 __u16 count;
1145 cFYI(1, ("In CIFSSMBRename"));
1146 renameRetry:
1147 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1148 (void **) &pSMBr);
1149 if (rc)
1150 return rc;
1152 pSMB->BufferFormat = 0x04;
1153 pSMB->SearchAttributes =
1154 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1155 ATTR_DIRECTORY);
1157 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1158 name_len =
1159 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1160 PATH_MAX, nls_codepage, remap);
1161 name_len++; /* trailing null */
1162 name_len *= 2;
1163 pSMB->OldFileName[name_len] = 0x04; /* pad */
1164 /* protocol requires ASCII signature byte on Unicode string */
1165 pSMB->OldFileName[name_len + 1] = 0x00;
1166 name_len2 =
1167 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1168 toName, PATH_MAX, nls_codepage, remap);
1169 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1170 name_len2 *= 2; /* convert to bytes */
1171 } else { /* BB improve the check for buffer overruns BB */
1172 name_len = strnlen(fromName, PATH_MAX);
1173 name_len++; /* trailing null */
1174 strncpy(pSMB->OldFileName, fromName, name_len);
1175 name_len2 = strnlen(toName, PATH_MAX);
1176 name_len2++; /* trailing null */
1177 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1178 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1179 name_len2++; /* trailing null */
1180 name_len2++; /* signature byte */
1183 count = 1 /* 1st signature byte */ + name_len + name_len2;
1184 pSMB->hdr.smb_buf_length += count;
1185 pSMB->ByteCount = cpu_to_le16(count);
1187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1189 if (rc) {
1190 cFYI(1, ("Send error in rename = %d", rc));
1193 #ifdef CONFIG_CIFS_STATS
1194 else {
1195 atomic_inc(&tcon->num_renames);
1197 #endif
1199 cifs_buf_release(pSMB);
1201 if (rc == -EAGAIN)
1202 goto renameRetry;
1204 return rc;
1207 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1208 int netfid, char * target_name,
1209 const struct nls_table * nls_codepage, int remap)
1211 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1212 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1213 struct set_file_rename * rename_info;
1214 char *data_offset;
1215 char dummy_string[30];
1216 int rc = 0;
1217 int bytes_returned = 0;
1218 int len_of_str;
1219 __u16 params, param_offset, offset, count, byte_count;
1221 cFYI(1, ("Rename to File by handle"));
1222 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1223 (void **) &pSMBr);
1224 if (rc)
1225 return rc;
1227 params = 6;
1228 pSMB->MaxSetupCount = 0;
1229 pSMB->Reserved = 0;
1230 pSMB->Flags = 0;
1231 pSMB->Timeout = 0;
1232 pSMB->Reserved2 = 0;
1233 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1234 offset = param_offset + params;
1236 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1237 rename_info = (struct set_file_rename *) data_offset;
1238 pSMB->MaxParameterCount = cpu_to_le16(2);
1239 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1240 pSMB->SetupCount = 1;
1241 pSMB->Reserved3 = 0;
1242 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1243 byte_count = 3 /* pad */ + params;
1244 pSMB->ParameterCount = cpu_to_le16(params);
1245 pSMB->TotalParameterCount = pSMB->ParameterCount;
1246 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1247 pSMB->DataOffset = cpu_to_le16(offset);
1248 /* construct random name ".cifs_tmp<inodenum><mid>" */
1249 rename_info->overwrite = cpu_to_le32(1);
1250 rename_info->root_fid = 0;
1251 /* unicode only call */
1252 if(target_name == NULL) {
1253 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1254 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1255 dummy_string, 24, nls_codepage, remap);
1256 } else {
1257 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1258 target_name, PATH_MAX, nls_codepage, remap);
1260 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1261 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1262 byte_count += count;
1263 pSMB->DataCount = cpu_to_le16(count);
1264 pSMB->TotalDataCount = pSMB->DataCount;
1265 pSMB->Fid = netfid;
1266 pSMB->InformationLevel =
1267 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1268 pSMB->Reserved4 = 0;
1269 pSMB->hdr.smb_buf_length += byte_count;
1270 pSMB->ByteCount = cpu_to_le16(byte_count);
1271 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1272 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1273 if (rc) {
1274 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1276 #ifdef CONFIG_CIFS_STATS
1277 else {
1278 atomic_inc(&pTcon->num_t2renames);
1280 #endif
1281 cifs_buf_release(pSMB);
1283 /* Note: On -EAGAIN error only caller can retry on handle based calls
1284 since file handle passed in no longer valid */
1286 return rc;
1290 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1291 const __u16 target_tid, const char *toName, const int flags,
1292 const struct nls_table *nls_codepage, int remap)
1294 int rc = 0;
1295 COPY_REQ *pSMB = NULL;
1296 COPY_RSP *pSMBr = NULL;
1297 int bytes_returned;
1298 int name_len, name_len2;
1299 __u16 count;
1301 cFYI(1, ("In CIFSSMBCopy"));
1302 copyRetry:
1303 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1304 (void **) &pSMBr);
1305 if (rc)
1306 return rc;
1308 pSMB->BufferFormat = 0x04;
1309 pSMB->Tid2 = target_tid;
1311 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1313 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1314 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1315 fromName, PATH_MAX, nls_codepage,
1316 remap);
1317 name_len++; /* trailing null */
1318 name_len *= 2;
1319 pSMB->OldFileName[name_len] = 0x04; /* pad */
1320 /* protocol requires ASCII signature byte on Unicode string */
1321 pSMB->OldFileName[name_len + 1] = 0x00;
1322 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1323 toName, PATH_MAX, nls_codepage, remap);
1324 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1325 name_len2 *= 2; /* convert to bytes */
1326 } else { /* BB improve the check for buffer overruns BB */
1327 name_len = strnlen(fromName, PATH_MAX);
1328 name_len++; /* trailing null */
1329 strncpy(pSMB->OldFileName, fromName, name_len);
1330 name_len2 = strnlen(toName, PATH_MAX);
1331 name_len2++; /* trailing null */
1332 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1333 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1334 name_len2++; /* trailing null */
1335 name_len2++; /* signature byte */
1338 count = 1 /* 1st signature byte */ + name_len + name_len2;
1339 pSMB->hdr.smb_buf_length += count;
1340 pSMB->ByteCount = cpu_to_le16(count);
1342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1344 if (rc) {
1345 cFYI(1, ("Send error in copy = %d with %d files copied",
1346 rc, le16_to_cpu(pSMBr->CopyCount)));
1348 if (pSMB)
1349 cifs_buf_release(pSMB);
1351 if (rc == -EAGAIN)
1352 goto copyRetry;
1354 return rc;
1358 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1359 const char *fromName, const char *toName,
1360 const struct nls_table *nls_codepage)
1362 TRANSACTION2_SPI_REQ *pSMB = NULL;
1363 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1364 char *data_offset;
1365 int name_len;
1366 int name_len_target;
1367 int rc = 0;
1368 int bytes_returned = 0;
1369 __u16 params, param_offset, offset, byte_count;
1371 cFYI(1, ("In Symlink Unix style"));
1372 createSymLinkRetry:
1373 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1374 (void **) &pSMBr);
1375 if (rc)
1376 return rc;
1378 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1379 name_len =
1380 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1381 /* find define for this maxpathcomponent */
1382 , nls_codepage);
1383 name_len++; /* trailing null */
1384 name_len *= 2;
1386 } else { /* BB improve the check for buffer overruns BB */
1387 name_len = strnlen(fromName, PATH_MAX);
1388 name_len++; /* trailing null */
1389 strncpy(pSMB->FileName, fromName, name_len);
1391 params = 6 + name_len;
1392 pSMB->MaxSetupCount = 0;
1393 pSMB->Reserved = 0;
1394 pSMB->Flags = 0;
1395 pSMB->Timeout = 0;
1396 pSMB->Reserved2 = 0;
1397 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1398 InformationLevel) - 4;
1399 offset = param_offset + params;
1401 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1402 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1403 name_len_target =
1404 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1405 /* find define for this maxpathcomponent */
1406 , nls_codepage);
1407 name_len_target++; /* trailing null */
1408 name_len_target *= 2;
1409 } else { /* BB improve the check for buffer overruns BB */
1410 name_len_target = strnlen(toName, PATH_MAX);
1411 name_len_target++; /* trailing null */
1412 strncpy(data_offset, toName, name_len_target);
1415 pSMB->MaxParameterCount = cpu_to_le16(2);
1416 /* BB find exact max on data count below from sess */
1417 pSMB->MaxDataCount = cpu_to_le16(1000);
1418 pSMB->SetupCount = 1;
1419 pSMB->Reserved3 = 0;
1420 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1421 byte_count = 3 /* pad */ + params + name_len_target;
1422 pSMB->DataCount = cpu_to_le16(name_len_target);
1423 pSMB->ParameterCount = cpu_to_le16(params);
1424 pSMB->TotalDataCount = pSMB->DataCount;
1425 pSMB->TotalParameterCount = pSMB->ParameterCount;
1426 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1427 pSMB->DataOffset = cpu_to_le16(offset);
1428 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1429 pSMB->Reserved4 = 0;
1430 pSMB->hdr.smb_buf_length += byte_count;
1431 pSMB->ByteCount = cpu_to_le16(byte_count);
1432 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1433 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1434 if (rc) {
1435 cFYI(1,
1436 ("Send error in SetPathInfo (create symlink) = %d",
1437 rc));
1440 if (pSMB)
1441 cifs_buf_release(pSMB);
1443 if (rc == -EAGAIN)
1444 goto createSymLinkRetry;
1446 return rc;
1450 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1451 const char *fromName, const char *toName,
1452 const struct nls_table *nls_codepage, int remap)
1454 TRANSACTION2_SPI_REQ *pSMB = NULL;
1455 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1456 char *data_offset;
1457 int name_len;
1458 int name_len_target;
1459 int rc = 0;
1460 int bytes_returned = 0;
1461 __u16 params, param_offset, offset, byte_count;
1463 cFYI(1, ("In Create Hard link Unix style"));
1464 createHardLinkRetry:
1465 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1466 (void **) &pSMBr);
1467 if (rc)
1468 return rc;
1470 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1471 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1472 PATH_MAX, nls_codepage, remap);
1473 name_len++; /* trailing null */
1474 name_len *= 2;
1476 } else { /* BB improve the check for buffer overruns BB */
1477 name_len = strnlen(toName, PATH_MAX);
1478 name_len++; /* trailing null */
1479 strncpy(pSMB->FileName, toName, name_len);
1481 params = 6 + name_len;
1482 pSMB->MaxSetupCount = 0;
1483 pSMB->Reserved = 0;
1484 pSMB->Flags = 0;
1485 pSMB->Timeout = 0;
1486 pSMB->Reserved2 = 0;
1487 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1488 InformationLevel) - 4;
1489 offset = param_offset + params;
1491 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1492 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1493 name_len_target =
1494 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1495 nls_codepage, remap);
1496 name_len_target++; /* trailing null */
1497 name_len_target *= 2;
1498 } else { /* BB improve the check for buffer overruns BB */
1499 name_len_target = strnlen(fromName, PATH_MAX);
1500 name_len_target++; /* trailing null */
1501 strncpy(data_offset, fromName, name_len_target);
1504 pSMB->MaxParameterCount = cpu_to_le16(2);
1505 /* BB find exact max on data count below from sess*/
1506 pSMB->MaxDataCount = cpu_to_le16(1000);
1507 pSMB->SetupCount = 1;
1508 pSMB->Reserved3 = 0;
1509 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1510 byte_count = 3 /* pad */ + params + name_len_target;
1511 pSMB->ParameterCount = cpu_to_le16(params);
1512 pSMB->TotalParameterCount = pSMB->ParameterCount;
1513 pSMB->DataCount = cpu_to_le16(name_len_target);
1514 pSMB->TotalDataCount = pSMB->DataCount;
1515 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1516 pSMB->DataOffset = cpu_to_le16(offset);
1517 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1518 pSMB->Reserved4 = 0;
1519 pSMB->hdr.smb_buf_length += byte_count;
1520 pSMB->ByteCount = cpu_to_le16(byte_count);
1521 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1522 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1523 if (rc) {
1524 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1527 cifs_buf_release(pSMB);
1528 if (rc == -EAGAIN)
1529 goto createHardLinkRetry;
1531 return rc;
1535 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1536 const char *fromName, const char *toName,
1537 const struct nls_table *nls_codepage, int remap)
1539 int rc = 0;
1540 NT_RENAME_REQ *pSMB = NULL;
1541 RENAME_RSP *pSMBr = NULL;
1542 int bytes_returned;
1543 int name_len, name_len2;
1544 __u16 count;
1546 cFYI(1, ("In CIFSCreateHardLink"));
1547 winCreateHardLinkRetry:
1549 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1550 (void **) &pSMBr);
1551 if (rc)
1552 return rc;
1554 pSMB->SearchAttributes =
1555 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1556 ATTR_DIRECTORY);
1557 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1558 pSMB->ClusterCount = 0;
1560 pSMB->BufferFormat = 0x04;
1562 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1563 name_len =
1564 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1565 PATH_MAX, nls_codepage, remap);
1566 name_len++; /* trailing null */
1567 name_len *= 2;
1568 pSMB->OldFileName[name_len] = 0; /* pad */
1569 pSMB->OldFileName[name_len + 1] = 0x04;
1570 name_len2 =
1571 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1572 toName, PATH_MAX, nls_codepage, remap);
1573 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1574 name_len2 *= 2; /* convert to bytes */
1575 } else { /* BB improve the check for buffer overruns BB */
1576 name_len = strnlen(fromName, PATH_MAX);
1577 name_len++; /* trailing null */
1578 strncpy(pSMB->OldFileName, fromName, name_len);
1579 name_len2 = strnlen(toName, PATH_MAX);
1580 name_len2++; /* trailing null */
1581 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1582 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1583 name_len2++; /* trailing null */
1584 name_len2++; /* signature byte */
1587 count = 1 /* string type byte */ + name_len + name_len2;
1588 pSMB->hdr.smb_buf_length += count;
1589 pSMB->ByteCount = cpu_to_le16(count);
1591 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1592 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1593 if (rc) {
1594 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1596 cifs_buf_release(pSMB);
1597 if (rc == -EAGAIN)
1598 goto winCreateHardLinkRetry;
1600 return rc;
1604 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1605 const unsigned char *searchName,
1606 char *symlinkinfo, const int buflen,
1607 const struct nls_table *nls_codepage)
1609 /* SMB_QUERY_FILE_UNIX_LINK */
1610 TRANSACTION2_QPI_REQ *pSMB = NULL;
1611 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1612 int rc = 0;
1613 int bytes_returned;
1614 int name_len;
1615 __u16 params, byte_count;
1617 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1619 querySymLinkRetry:
1620 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1621 (void **) &pSMBr);
1622 if (rc)
1623 return rc;
1625 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1626 name_len =
1627 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1628 /* find define for this maxpathcomponent */
1629 , nls_codepage);
1630 name_len++; /* trailing null */
1631 name_len *= 2;
1632 } else { /* BB improve the check for buffer overruns BB */
1633 name_len = strnlen(searchName, PATH_MAX);
1634 name_len++; /* trailing null */
1635 strncpy(pSMB->FileName, searchName, name_len);
1638 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1639 pSMB->TotalDataCount = 0;
1640 pSMB->MaxParameterCount = cpu_to_le16(2);
1641 /* BB find exact max data count below from sess structure BB */
1642 pSMB->MaxDataCount = cpu_to_le16(4000);
1643 pSMB->MaxSetupCount = 0;
1644 pSMB->Reserved = 0;
1645 pSMB->Flags = 0;
1646 pSMB->Timeout = 0;
1647 pSMB->Reserved2 = 0;
1648 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1649 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1650 pSMB->DataCount = 0;
1651 pSMB->DataOffset = 0;
1652 pSMB->SetupCount = 1;
1653 pSMB->Reserved3 = 0;
1654 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1655 byte_count = params + 1 /* pad */ ;
1656 pSMB->TotalParameterCount = cpu_to_le16(params);
1657 pSMB->ParameterCount = pSMB->TotalParameterCount;
1658 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1659 pSMB->Reserved4 = 0;
1660 pSMB->hdr.smb_buf_length += byte_count;
1661 pSMB->ByteCount = cpu_to_le16(byte_count);
1663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1664 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1665 if (rc) {
1666 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1667 } else {
1668 /* decode response */
1670 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1671 if (rc || (pSMBr->ByteCount < 2))
1672 /* BB also check enough total bytes returned */
1673 rc = -EIO; /* bad smb */
1674 else {
1675 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1676 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1678 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1679 name_len = UniStrnlen((wchar_t *) ((char *)
1680 &pSMBr->hdr.Protocol +data_offset),
1681 min_t(const int, buflen,count) / 2);
1682 /* BB FIXME investigate remapping reserved chars here */
1683 cifs_strfromUCS_le(symlinkinfo,
1684 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1685 data_offset),
1686 name_len, nls_codepage);
1687 } else {
1688 strncpy(symlinkinfo,
1689 (char *) &pSMBr->hdr.Protocol +
1690 data_offset,
1691 min_t(const int, buflen, count));
1693 symlinkinfo[buflen] = 0;
1694 /* just in case so calling code does not go off the end of buffer */
1697 cifs_buf_release(pSMB);
1698 if (rc == -EAGAIN)
1699 goto querySymLinkRetry;
1700 return rc;
1704 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1705 const unsigned char *searchName,
1706 char *symlinkinfo, const int buflen,__u16 fid,
1707 const struct nls_table *nls_codepage)
1709 int rc = 0;
1710 int bytes_returned;
1711 int name_len;
1712 struct smb_com_transaction_ioctl_req * pSMB;
1713 struct smb_com_transaction_ioctl_rsp * pSMBr;
1715 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1716 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1717 (void **) &pSMBr);
1718 if (rc)
1719 return rc;
1721 pSMB->TotalParameterCount = 0 ;
1722 pSMB->TotalDataCount = 0;
1723 pSMB->MaxParameterCount = cpu_to_le32(2);
1724 /* BB find exact data count max from sess structure BB */
1725 pSMB->MaxDataCount = cpu_to_le32(4000);
1726 pSMB->MaxSetupCount = 4;
1727 pSMB->Reserved = 0;
1728 pSMB->ParameterOffset = 0;
1729 pSMB->DataCount = 0;
1730 pSMB->DataOffset = 0;
1731 pSMB->SetupCount = 4;
1732 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1733 pSMB->ParameterCount = pSMB->TotalParameterCount;
1734 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1735 pSMB->IsFsctl = 1; /* FSCTL */
1736 pSMB->IsRootFlag = 0;
1737 pSMB->Fid = fid; /* file handle always le */
1738 pSMB->ByteCount = 0;
1740 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1741 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1742 if (rc) {
1743 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1744 } else { /* decode response */
1745 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1746 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1747 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1748 /* BB also check enough total bytes returned */
1749 rc = -EIO; /* bad smb */
1750 else {
1751 if(data_count && (data_count < 2048)) {
1752 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1754 struct reparse_data * reparse_buf = (struct reparse_data *)
1755 ((char *)&pSMBr->hdr.Protocol + data_offset);
1756 if((char*)reparse_buf >= end_of_smb) {
1757 rc = -EIO;
1758 goto qreparse_out;
1760 if((reparse_buf->LinkNamesBuf +
1761 reparse_buf->TargetNameOffset +
1762 reparse_buf->TargetNameLen) >
1763 end_of_smb) {
1764 cFYI(1,("reparse buf extended beyond SMB"));
1765 rc = -EIO;
1766 goto qreparse_out;
1769 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1770 name_len = UniStrnlen((wchar_t *)
1771 (reparse_buf->LinkNamesBuf +
1772 reparse_buf->TargetNameOffset),
1773 min(buflen/2, reparse_buf->TargetNameLen / 2));
1774 cifs_strfromUCS_le(symlinkinfo,
1775 (wchar_t *) (reparse_buf->LinkNamesBuf +
1776 reparse_buf->TargetNameOffset),
1777 name_len, nls_codepage);
1778 } else { /* ASCII names */
1779 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1780 reparse_buf->TargetNameOffset,
1781 min_t(const int, buflen, reparse_buf->TargetNameLen));
1783 } else {
1784 rc = -EIO;
1785 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1787 symlinkinfo[buflen] = 0; /* just in case so the caller
1788 does not go off the end of the buffer */
1789 cFYI(1,("readlink result - %s ",symlinkinfo));
1792 qreparse_out:
1793 if (pSMB)
1794 cifs_buf_release(pSMB);
1796 /* Note: On -EAGAIN error only caller can retry on handle based calls
1797 since file handle passed in no longer valid */
1799 return rc;
1802 #ifdef CONFIG_CIFS_POSIX
1804 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1805 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1807 /* u8 cifs fields do not need le conversion */
1808 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1809 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1810 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1811 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1813 return;
1816 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
1817 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1818 const int acl_type,const int size_of_data_area)
1820 int size = 0;
1821 int i;
1822 __u16 count;
1823 struct cifs_posix_ace * pACE;
1824 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1825 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1827 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1828 return -EOPNOTSUPP;
1830 if(acl_type & ACL_TYPE_ACCESS) {
1831 count = le16_to_cpu(cifs_acl->access_entry_count);
1832 pACE = &cifs_acl->ace_array[0];
1833 size = sizeof(struct cifs_posix_acl);
1834 size += sizeof(struct cifs_posix_ace) * count;
1835 /* check if we would go beyond end of SMB */
1836 if(size_of_data_area < size) {
1837 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1838 return -EINVAL;
1840 } else if(acl_type & ACL_TYPE_DEFAULT) {
1841 count = le16_to_cpu(cifs_acl->access_entry_count);
1842 size = sizeof(struct cifs_posix_acl);
1843 size += sizeof(struct cifs_posix_ace) * count;
1844 /* skip past access ACEs to get to default ACEs */
1845 pACE = &cifs_acl->ace_array[count];
1846 count = le16_to_cpu(cifs_acl->default_entry_count);
1847 size += sizeof(struct cifs_posix_ace) * count;
1848 /* check if we would go beyond end of SMB */
1849 if(size_of_data_area < size)
1850 return -EINVAL;
1851 } else {
1852 /* illegal type */
1853 return -EINVAL;
1856 size = posix_acl_xattr_size(count);
1857 if((buflen == 0) || (local_acl == NULL)) {
1858 /* used to query ACL EA size */
1859 } else if(size > buflen) {
1860 return -ERANGE;
1861 } else /* buffer big enough */ {
1862 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1863 for(i = 0;i < count ;i++) {
1864 cifs_convert_ace(&local_acl->a_entries[i],pACE);
1865 pACE ++;
1868 return size;
1871 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1872 const posix_acl_xattr_entry * local_ace)
1874 __u16 rc = 0; /* 0 = ACL converted ok */
1876 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1877 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
1878 /* BB is there a better way to handle the large uid? */
1879 if(local_ace->e_id == -1) {
1880 /* Probably no need to le convert -1 on any arch but can not hurt */
1881 cifs_ace->cifs_uid = cpu_to_le64(-1);
1882 } else
1883 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1884 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1885 return rc;
1888 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1889 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1890 const int acl_type)
1892 __u16 rc = 0;
1893 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1894 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1895 int count;
1896 int i;
1898 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1899 return 0;
1901 count = posix_acl_xattr_count((size_t)buflen);
1902 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1903 count,buflen,local_acl->a_version));
1904 if(local_acl->a_version != 2) {
1905 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1906 return 0;
1908 cifs_acl->version = cpu_to_le16(1);
1909 if(acl_type == ACL_TYPE_ACCESS)
1910 cifs_acl->access_entry_count = count;
1911 else if(acl_type == ACL_TYPE_DEFAULT)
1912 cifs_acl->default_entry_count = count;
1913 else {
1914 cFYI(1,("unknown ACL type %d",acl_type));
1915 return 0;
1917 for(i=0;i<count;i++) {
1918 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1919 &local_acl->a_entries[i]);
1920 if(rc != 0) {
1921 /* ACE not converted */
1922 break;
1925 if(rc == 0) {
1926 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1927 rc += sizeof(struct cifs_posix_acl);
1928 /* BB add check to make sure ACL does not overflow SMB */
1930 return rc;
1934 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1935 const unsigned char *searchName,
1936 char *acl_inf, const int buflen, const int acl_type,
1937 const struct nls_table *nls_codepage, int remap)
1939 /* SMB_QUERY_POSIX_ACL */
1940 TRANSACTION2_QPI_REQ *pSMB = NULL;
1941 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1942 int rc = 0;
1943 int bytes_returned;
1944 int name_len;
1945 __u16 params, byte_count;
1947 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1949 queryAclRetry:
1950 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1951 (void **) &pSMBr);
1952 if (rc)
1953 return rc;
1955 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1956 name_len =
1957 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
1958 PATH_MAX, nls_codepage, remap);
1959 name_len++; /* trailing null */
1960 name_len *= 2;
1961 pSMB->FileName[name_len] = 0;
1962 pSMB->FileName[name_len+1] = 0;
1963 } else { /* BB improve the check for buffer overruns BB */
1964 name_len = strnlen(searchName, PATH_MAX);
1965 name_len++; /* trailing null */
1966 strncpy(pSMB->FileName, searchName, name_len);
1969 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1970 pSMB->TotalDataCount = 0;
1971 pSMB->MaxParameterCount = cpu_to_le16(2);
1972 /* BB find exact max data count below from sess structure BB */
1973 pSMB->MaxDataCount = cpu_to_le16(4000);
1974 pSMB->MaxSetupCount = 0;
1975 pSMB->Reserved = 0;
1976 pSMB->Flags = 0;
1977 pSMB->Timeout = 0;
1978 pSMB->Reserved2 = 0;
1979 pSMB->ParameterOffset = cpu_to_le16(
1980 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1981 pSMB->DataCount = 0;
1982 pSMB->DataOffset = 0;
1983 pSMB->SetupCount = 1;
1984 pSMB->Reserved3 = 0;
1985 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1986 byte_count = params + 1 /* pad */ ;
1987 pSMB->TotalParameterCount = cpu_to_le16(params);
1988 pSMB->ParameterCount = pSMB->TotalParameterCount;
1989 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1990 pSMB->Reserved4 = 0;
1991 pSMB->hdr.smb_buf_length += byte_count;
1992 pSMB->ByteCount = cpu_to_le16(byte_count);
1994 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1995 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1996 if (rc) {
1997 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
1998 } else {
1999 /* decode response */
2001 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2002 if (rc || (pSMBr->ByteCount < 2))
2003 /* BB also check enough total bytes returned */
2004 rc = -EIO; /* bad smb */
2005 else {
2006 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2007 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2008 rc = cifs_copy_posix_acl(acl_inf,
2009 (char *)&pSMBr->hdr.Protocol+data_offset,
2010 buflen,acl_type,count);
2013 cifs_buf_release(pSMB);
2014 if (rc == -EAGAIN)
2015 goto queryAclRetry;
2016 return rc;
2020 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2021 const unsigned char *fileName,
2022 const char *local_acl, const int buflen,
2023 const int acl_type,
2024 const struct nls_table *nls_codepage, int remap)
2026 struct smb_com_transaction2_spi_req *pSMB = NULL;
2027 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2028 char *parm_data;
2029 int name_len;
2030 int rc = 0;
2031 int bytes_returned = 0;
2032 __u16 params, byte_count, data_count, param_offset, offset;
2034 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2035 setAclRetry:
2036 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2037 (void **) &pSMBr);
2038 if (rc)
2039 return rc;
2040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2041 name_len =
2042 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2043 PATH_MAX, nls_codepage, remap);
2044 name_len++; /* trailing null */
2045 name_len *= 2;
2046 } else { /* BB improve the check for buffer overruns BB */
2047 name_len = strnlen(fileName, PATH_MAX);
2048 name_len++; /* trailing null */
2049 strncpy(pSMB->FileName, fileName, name_len);
2051 params = 6 + name_len;
2052 pSMB->MaxParameterCount = cpu_to_le16(2);
2053 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2054 pSMB->MaxSetupCount = 0;
2055 pSMB->Reserved = 0;
2056 pSMB->Flags = 0;
2057 pSMB->Timeout = 0;
2058 pSMB->Reserved2 = 0;
2059 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2060 InformationLevel) - 4;
2061 offset = param_offset + params;
2062 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2063 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2065 /* convert to on the wire format for POSIX ACL */
2066 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2068 if(data_count == 0) {
2069 rc = -EOPNOTSUPP;
2070 goto setACLerrorExit;
2072 pSMB->DataOffset = cpu_to_le16(offset);
2073 pSMB->SetupCount = 1;
2074 pSMB->Reserved3 = 0;
2075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2076 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2077 byte_count = 3 /* pad */ + params + data_count;
2078 pSMB->DataCount = cpu_to_le16(data_count);
2079 pSMB->TotalDataCount = pSMB->DataCount;
2080 pSMB->ParameterCount = cpu_to_le16(params);
2081 pSMB->TotalParameterCount = pSMB->ParameterCount;
2082 pSMB->Reserved4 = 0;
2083 pSMB->hdr.smb_buf_length += byte_count;
2084 pSMB->ByteCount = cpu_to_le16(byte_count);
2085 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2086 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2087 if (rc) {
2088 cFYI(1, ("Set POSIX ACL returned %d", rc));
2091 setACLerrorExit:
2092 cifs_buf_release(pSMB);
2093 if (rc == -EAGAIN)
2094 goto setAclRetry;
2095 return rc;
2098 /* BB fix tabs in this function FIXME BB */
2100 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2101 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2103 int rc = 0;
2104 struct smb_t2_qfi_req *pSMB = NULL;
2105 struct smb_t2_qfi_rsp *pSMBr = NULL;
2106 int bytes_returned;
2107 __u16 params, byte_count;
2109 cFYI(1,("In GetExtAttr"));
2110 if(tcon == NULL)
2111 return -ENODEV;
2113 GetExtAttrRetry:
2114 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2115 (void **) &pSMBr);
2116 if (rc)
2117 return rc;
2119 params = 2 /* level */ +2 /* fid */;
2120 pSMB->t2.TotalDataCount = 0;
2121 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2122 /* BB find exact max data count below from sess structure BB */
2123 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2124 pSMB->t2.MaxSetupCount = 0;
2125 pSMB->t2.Reserved = 0;
2126 pSMB->t2.Flags = 0;
2127 pSMB->t2.Timeout = 0;
2128 pSMB->t2.Reserved2 = 0;
2129 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2130 Fid) - 4);
2131 pSMB->t2.DataCount = 0;
2132 pSMB->t2.DataOffset = 0;
2133 pSMB->t2.SetupCount = 1;
2134 pSMB->t2.Reserved3 = 0;
2135 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2136 byte_count = params + 1 /* pad */ ;
2137 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2138 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2139 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2140 pSMB->Pad = 0;
2141 pSMB->Fid = netfid;
2142 pSMB->hdr.smb_buf_length += byte_count;
2143 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2145 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2146 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2147 if (rc) {
2148 cFYI(1, ("error %d in GetExtAttr", rc));
2149 } else {
2150 /* decode response */
2151 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2152 if (rc || (pSMBr->ByteCount < 2))
2153 /* BB also check enough total bytes returned */
2154 /* If rc should we check for EOPNOSUPP and
2155 disable the srvino flag? or in caller? */
2156 rc = -EIO; /* bad smb */
2157 else {
2158 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2159 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2160 struct file_chattr_info * pfinfo;
2161 /* BB Do we need a cast or hash here ? */
2162 if(count != 16) {
2163 cFYI(1, ("Illegal size ret in GetExtAttr"));
2164 rc = -EIO;
2165 goto GetExtAttrOut;
2167 pfinfo = (struct file_chattr_info *)
2168 (data_offset + (char *) &pSMBr->hdr.Protocol);
2169 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2170 *pMask = le64_to_cpu(pfinfo->mask);
2173 GetExtAttrOut:
2174 cifs_buf_release(pSMB);
2175 if (rc == -EAGAIN)
2176 goto GetExtAttrRetry;
2177 return rc;
2181 #endif /* CONFIG_POSIX */
2184 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2185 const unsigned char *searchName,
2186 FILE_ALL_INFO * pFindData,
2187 const struct nls_table *nls_codepage, int remap)
2189 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2190 TRANSACTION2_QPI_REQ *pSMB = NULL;
2191 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2192 int rc = 0;
2193 int bytes_returned;
2194 int name_len;
2195 __u16 params, byte_count;
2197 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2198 QPathInfoRetry:
2199 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2200 (void **) &pSMBr);
2201 if (rc)
2202 return rc;
2204 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2205 name_len =
2206 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2207 PATH_MAX, nls_codepage, remap);
2208 name_len++; /* trailing null */
2209 name_len *= 2;
2210 } else { /* BB improve the check for buffer overruns BB */
2211 name_len = strnlen(searchName, PATH_MAX);
2212 name_len++; /* trailing null */
2213 strncpy(pSMB->FileName, searchName, name_len);
2216 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2217 pSMB->TotalDataCount = 0;
2218 pSMB->MaxParameterCount = cpu_to_le16(2);
2219 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2220 pSMB->MaxSetupCount = 0;
2221 pSMB->Reserved = 0;
2222 pSMB->Flags = 0;
2223 pSMB->Timeout = 0;
2224 pSMB->Reserved2 = 0;
2225 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2226 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2227 pSMB->DataCount = 0;
2228 pSMB->DataOffset = 0;
2229 pSMB->SetupCount = 1;
2230 pSMB->Reserved3 = 0;
2231 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2232 byte_count = params + 1 /* pad */ ;
2233 pSMB->TotalParameterCount = cpu_to_le16(params);
2234 pSMB->ParameterCount = pSMB->TotalParameterCount;
2235 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2236 pSMB->Reserved4 = 0;
2237 pSMB->hdr.smb_buf_length += byte_count;
2238 pSMB->ByteCount = cpu_to_le16(byte_count);
2240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2241 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2242 if (rc) {
2243 cFYI(1, ("Send error in QPathInfo = %d", rc));
2244 } else { /* decode response */
2245 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2247 if (rc || (pSMBr->ByteCount < 40))
2248 rc = -EIO; /* bad smb */
2249 else if (pFindData){
2250 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2251 memcpy((char *) pFindData,
2252 (char *) &pSMBr->hdr.Protocol +
2253 data_offset, sizeof (FILE_ALL_INFO));
2254 } else
2255 rc = -ENOMEM;
2257 cifs_buf_release(pSMB);
2258 if (rc == -EAGAIN)
2259 goto QPathInfoRetry;
2261 return rc;
2265 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2266 const unsigned char *searchName,
2267 FILE_UNIX_BASIC_INFO * pFindData,
2268 const struct nls_table *nls_codepage, int remap)
2270 /* SMB_QUERY_FILE_UNIX_BASIC */
2271 TRANSACTION2_QPI_REQ *pSMB = NULL;
2272 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2273 int rc = 0;
2274 int bytes_returned = 0;
2275 int name_len;
2276 __u16 params, byte_count;
2278 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2279 UnixQPathInfoRetry:
2280 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2281 (void **) &pSMBr);
2282 if (rc)
2283 return rc;
2285 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2286 name_len =
2287 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2288 PATH_MAX, nls_codepage, remap);
2289 name_len++; /* trailing null */
2290 name_len *= 2;
2291 } else { /* BB improve the check for buffer overruns BB */
2292 name_len = strnlen(searchName, PATH_MAX);
2293 name_len++; /* trailing null */
2294 strncpy(pSMB->FileName, searchName, name_len);
2297 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2298 pSMB->TotalDataCount = 0;
2299 pSMB->MaxParameterCount = cpu_to_le16(2);
2300 /* BB find exact max SMB PDU from sess structure BB */
2301 pSMB->MaxDataCount = cpu_to_le16(4000);
2302 pSMB->MaxSetupCount = 0;
2303 pSMB->Reserved = 0;
2304 pSMB->Flags = 0;
2305 pSMB->Timeout = 0;
2306 pSMB->Reserved2 = 0;
2307 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2308 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2309 pSMB->DataCount = 0;
2310 pSMB->DataOffset = 0;
2311 pSMB->SetupCount = 1;
2312 pSMB->Reserved3 = 0;
2313 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2314 byte_count = params + 1 /* pad */ ;
2315 pSMB->TotalParameterCount = cpu_to_le16(params);
2316 pSMB->ParameterCount = pSMB->TotalParameterCount;
2317 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2318 pSMB->Reserved4 = 0;
2319 pSMB->hdr.smb_buf_length += byte_count;
2320 pSMB->ByteCount = cpu_to_le16(byte_count);
2322 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2323 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2324 if (rc) {
2325 cFYI(1, ("Send error in QPathInfo = %d", rc));
2326 } else { /* decode response */
2327 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2329 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2330 rc = -EIO; /* bad smb */
2331 } else {
2332 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2333 memcpy((char *) pFindData,
2334 (char *) &pSMBr->hdr.Protocol +
2335 data_offset,
2336 sizeof (FILE_UNIX_BASIC_INFO));
2339 cifs_buf_release(pSMB);
2340 if (rc == -EAGAIN)
2341 goto UnixQPathInfoRetry;
2343 return rc;
2346 #if 0 /* function unused at present */
2347 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2348 const char *searchName, FILE_ALL_INFO * findData,
2349 const struct nls_table *nls_codepage)
2351 /* level 257 SMB_ */
2352 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2353 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2354 int rc = 0;
2355 int bytes_returned;
2356 int name_len;
2357 __u16 params, byte_count;
2359 cFYI(1, ("In FindUnique"));
2360 findUniqueRetry:
2361 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2362 (void **) &pSMBr);
2363 if (rc)
2364 return rc;
2366 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2367 name_len =
2368 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2369 /* find define for this maxpathcomponent */
2370 , nls_codepage);
2371 name_len++; /* trailing null */
2372 name_len *= 2;
2373 } else { /* BB improve the check for buffer overruns BB */
2374 name_len = strnlen(searchName, PATH_MAX);
2375 name_len++; /* trailing null */
2376 strncpy(pSMB->FileName, searchName, name_len);
2379 params = 12 + name_len /* includes null */ ;
2380 pSMB->TotalDataCount = 0; /* no EAs */
2381 pSMB->MaxParameterCount = cpu_to_le16(2);
2382 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2383 pSMB->MaxSetupCount = 0;
2384 pSMB->Reserved = 0;
2385 pSMB->Flags = 0;
2386 pSMB->Timeout = 0;
2387 pSMB->Reserved2 = 0;
2388 pSMB->ParameterOffset = cpu_to_le16(
2389 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2390 pSMB->DataCount = 0;
2391 pSMB->DataOffset = 0;
2392 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2393 pSMB->Reserved3 = 0;
2394 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2395 byte_count = params + 1 /* pad */ ;
2396 pSMB->TotalParameterCount = cpu_to_le16(params);
2397 pSMB->ParameterCount = pSMB->TotalParameterCount;
2398 pSMB->SearchAttributes =
2399 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2400 ATTR_DIRECTORY);
2401 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2402 pSMB->SearchFlags = cpu_to_le16(1);
2403 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2404 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2405 pSMB->hdr.smb_buf_length += byte_count;
2406 pSMB->ByteCount = cpu_to_le16(byte_count);
2408 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2409 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2411 if (rc) {
2412 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2413 } else { /* decode response */
2415 /* BB fill in */
2418 cifs_buf_release(pSMB);
2419 if (rc == -EAGAIN)
2420 goto findUniqueRetry;
2422 return rc;
2424 #endif /* end unused (temporarily) function */
2426 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2428 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2429 const char *searchName,
2430 const struct nls_table *nls_codepage,
2431 __u16 * pnetfid,
2432 struct cifs_search_info * psrch_inf, int remap)
2434 /* level 257 SMB_ */
2435 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2436 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2437 T2_FFIRST_RSP_PARMS * parms;
2438 int rc = 0;
2439 int bytes_returned = 0;
2440 int name_len;
2441 __u16 params, byte_count;
2443 cFYI(1, ("In FindFirst for %s",searchName));
2445 findFirstRetry:
2446 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2447 (void **) &pSMBr);
2448 if (rc)
2449 return rc;
2451 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2452 name_len =
2453 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2454 PATH_MAX, nls_codepage, remap);
2455 /* We can not add the asterik earlier in case
2456 it got remapped to 0xF03A as if it were part of the
2457 directory name instead of a wildcard */
2458 name_len *= 2;
2459 pSMB->FileName[name_len] = '\\';
2460 pSMB->FileName[name_len+1] = 0;
2461 pSMB->FileName[name_len+2] = '*';
2462 pSMB->FileName[name_len+3] = 0;
2463 name_len += 4; /* now the trailing null */
2464 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2465 pSMB->FileName[name_len+1] = 0;
2466 name_len += 2;
2467 } else { /* BB add check for overrun of SMB buf BB */
2468 name_len = strnlen(searchName, PATH_MAX);
2469 /* BB fix here and in unicode clause above ie
2470 if(name_len > buffersize-header)
2471 free buffer exit; BB */
2472 strncpy(pSMB->FileName, searchName, name_len);
2473 pSMB->FileName[name_len] = '\\';
2474 pSMB->FileName[name_len+1] = '*';
2475 pSMB->FileName[name_len+2] = 0;
2476 name_len += 3;
2479 params = 12 + name_len /* includes null */ ;
2480 pSMB->TotalDataCount = 0; /* no EAs */
2481 pSMB->MaxParameterCount = cpu_to_le16(10);
2482 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2483 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2484 pSMB->MaxSetupCount = 0;
2485 pSMB->Reserved = 0;
2486 pSMB->Flags = 0;
2487 pSMB->Timeout = 0;
2488 pSMB->Reserved2 = 0;
2489 byte_count = params + 1 /* pad */ ;
2490 pSMB->TotalParameterCount = cpu_to_le16(params);
2491 pSMB->ParameterCount = pSMB->TotalParameterCount;
2492 pSMB->ParameterOffset = cpu_to_le16(
2493 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2494 pSMB->DataCount = 0;
2495 pSMB->DataOffset = 0;
2496 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2497 pSMB->Reserved3 = 0;
2498 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2499 pSMB->SearchAttributes =
2500 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2501 ATTR_DIRECTORY);
2502 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2503 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2504 CIFS_SEARCH_RETURN_RESUME);
2505 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2507 /* BB what should we set StorageType to? Does it matter? BB */
2508 pSMB->SearchStorageType = 0;
2509 pSMB->hdr.smb_buf_length += byte_count;
2510 pSMB->ByteCount = cpu_to_le16(byte_count);
2512 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2513 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2515 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2516 /* BB Add code to handle unsupported level rc */
2517 cFYI(1, ("Error in FindFirst = %d", rc));
2519 if (pSMB)
2520 cifs_buf_release(pSMB);
2522 /* BB eventually could optimize out free and realloc of buf */
2523 /* for this case */
2524 if (rc == -EAGAIN)
2525 goto findFirstRetry;
2526 } else { /* decode response */
2527 /* BB remember to free buffer if error BB */
2528 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2529 if(rc == 0) {
2530 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2531 psrch_inf->unicode = TRUE;
2532 else
2533 psrch_inf->unicode = FALSE;
2535 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2536 psrch_inf->srch_entries_start =
2537 (char *) &pSMBr->hdr.Protocol +
2538 le16_to_cpu(pSMBr->t2.DataOffset);
2539 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2540 le16_to_cpu(pSMBr->t2.ParameterOffset));
2542 if(parms->EndofSearch)
2543 psrch_inf->endOfSearch = TRUE;
2544 else
2545 psrch_inf->endOfSearch = FALSE;
2547 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2548 psrch_inf->index_of_last_entry =
2549 psrch_inf->entries_in_buffer;
2550 *pnetfid = parms->SearchHandle;
2551 } else {
2552 cifs_buf_release(pSMB);
2556 return rc;
2559 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2560 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2562 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2563 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2564 T2_FNEXT_RSP_PARMS * parms;
2565 char *response_data;
2566 int rc = 0;
2567 int bytes_returned, name_len;
2568 __u16 params, byte_count;
2570 cFYI(1, ("In FindNext"));
2572 if(psrch_inf->endOfSearch == TRUE)
2573 return -ENOENT;
2575 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2576 (void **) &pSMBr);
2577 if (rc)
2578 return rc;
2580 params = 14; /* includes 2 bytes of null string, converted to LE below */
2581 byte_count = 0;
2582 pSMB->TotalDataCount = 0; /* no EAs */
2583 pSMB->MaxParameterCount = cpu_to_le16(8);
2584 pSMB->MaxDataCount =
2585 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2586 pSMB->MaxSetupCount = 0;
2587 pSMB->Reserved = 0;
2588 pSMB->Flags = 0;
2589 pSMB->Timeout = 0;
2590 pSMB->Reserved2 = 0;
2591 pSMB->ParameterOffset = cpu_to_le16(
2592 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2593 pSMB->DataCount = 0;
2594 pSMB->DataOffset = 0;
2595 pSMB->SetupCount = 1;
2596 pSMB->Reserved3 = 0;
2597 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2598 pSMB->SearchHandle = searchHandle; /* always kept as le */
2599 pSMB->SearchCount =
2600 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2601 /* test for Unix extensions */
2602 /* if (tcon->ses->capabilities & CAP_UNIX) {
2603 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2604 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2605 } else {
2606 pSMB->InformationLevel =
2607 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2608 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2609 } */
2610 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2611 pSMB->ResumeKey = psrch_inf->resume_key;
2612 pSMB->SearchFlags =
2613 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2615 name_len = psrch_inf->resume_name_len;
2616 params += name_len;
2617 if(name_len < PATH_MAX) {
2618 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2619 byte_count += name_len;
2620 } else {
2621 rc = -EINVAL;
2622 goto FNext2_err_exit;
2624 byte_count = params + 1 /* pad */ ;
2625 pSMB->TotalParameterCount = cpu_to_le16(params);
2626 pSMB->ParameterCount = pSMB->TotalParameterCount;
2627 pSMB->hdr.smb_buf_length += byte_count;
2628 pSMB->ByteCount = cpu_to_le16(byte_count);
2630 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2631 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2633 if (rc) {
2634 if (rc == -EBADF) {
2635 psrch_inf->endOfSearch = TRUE;
2636 rc = 0; /* search probably was closed at end of search above */
2637 } else
2638 cFYI(1, ("FindNext returned = %d", rc));
2639 } else { /* decode response */
2640 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2642 if(rc == 0) {
2643 /* BB fixme add lock for file (srch_info) struct here */
2644 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2645 psrch_inf->unicode = TRUE;
2646 else
2647 psrch_inf->unicode = FALSE;
2648 response_data = (char *) &pSMBr->hdr.Protocol +
2649 le16_to_cpu(pSMBr->t2.ParameterOffset);
2650 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2651 response_data = (char *)&pSMBr->hdr.Protocol +
2652 le16_to_cpu(pSMBr->t2.DataOffset);
2653 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2654 psrch_inf->srch_entries_start = response_data;
2655 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2656 if(parms->EndofSearch)
2657 psrch_inf->endOfSearch = TRUE;
2658 else
2659 psrch_inf->endOfSearch = FALSE;
2661 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2662 psrch_inf->index_of_last_entry +=
2663 psrch_inf->entries_in_buffer;
2664 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2666 /* BB fixme add unlock here */
2671 /* BB On error, should we leave previous search buf (and count and
2672 last entry fields) intact or free the previous one? */
2674 /* Note: On -EAGAIN error only caller can retry on handle based calls
2675 since file handle passed in no longer valid */
2676 FNext2_err_exit:
2677 if (rc != 0)
2678 cifs_buf_release(pSMB);
2680 return rc;
2684 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2686 int rc = 0;
2687 FINDCLOSE_REQ *pSMB = NULL;
2688 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2689 int bytes_returned;
2691 cFYI(1, ("In CIFSSMBFindClose"));
2692 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2694 /* no sense returning error if session restarted
2695 as file handle has been closed */
2696 if(rc == -EAGAIN)
2697 return 0;
2698 if (rc)
2699 return rc;
2701 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2702 pSMB->FileID = searchHandle;
2703 pSMB->ByteCount = 0;
2704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2706 if (rc) {
2707 cERROR(1, ("Send error in FindClose = %d", rc));
2709 cifs_small_buf_release(pSMB);
2711 /* Since session is dead, search handle closed on server already */
2712 if (rc == -EAGAIN)
2713 rc = 0;
2715 return rc;
2718 #ifdef CONFIG_CIFS_EXPERIMENTAL
2720 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2721 const unsigned char *searchName,
2722 __u64 * inode_number,
2723 const struct nls_table *nls_codepage, int remap)
2725 int rc = 0;
2726 TRANSACTION2_QPI_REQ *pSMB = NULL;
2727 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2728 int name_len, bytes_returned;
2729 __u16 params, byte_count;
2731 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2732 if(tcon == NULL)
2733 return -ENODEV;
2735 GetInodeNumberRetry:
2736 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2737 (void **) &pSMBr);
2738 if (rc)
2739 return rc;
2742 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2743 name_len =
2744 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2745 PATH_MAX,nls_codepage, remap);
2746 name_len++; /* trailing null */
2747 name_len *= 2;
2748 } else { /* BB improve the check for buffer overruns BB */
2749 name_len = strnlen(searchName, PATH_MAX);
2750 name_len++; /* trailing null */
2751 strncpy(pSMB->FileName, searchName, name_len);
2754 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2755 pSMB->TotalDataCount = 0;
2756 pSMB->MaxParameterCount = cpu_to_le16(2);
2757 /* BB find exact max data count below from sess structure BB */
2758 pSMB->MaxDataCount = cpu_to_le16(4000);
2759 pSMB->MaxSetupCount = 0;
2760 pSMB->Reserved = 0;
2761 pSMB->Flags = 0;
2762 pSMB->Timeout = 0;
2763 pSMB->Reserved2 = 0;
2764 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2765 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2766 pSMB->DataCount = 0;
2767 pSMB->DataOffset = 0;
2768 pSMB->SetupCount = 1;
2769 pSMB->Reserved3 = 0;
2770 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2771 byte_count = params + 1 /* pad */ ;
2772 pSMB->TotalParameterCount = cpu_to_le16(params);
2773 pSMB->ParameterCount = pSMB->TotalParameterCount;
2774 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2775 pSMB->Reserved4 = 0;
2776 pSMB->hdr.smb_buf_length += byte_count;
2777 pSMB->ByteCount = cpu_to_le16(byte_count);
2779 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2780 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2781 if (rc) {
2782 cFYI(1, ("error %d in QueryInternalInfo", rc));
2783 } else {
2784 /* decode response */
2785 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2786 if (rc || (pSMBr->ByteCount < 2))
2787 /* BB also check enough total bytes returned */
2788 /* If rc should we check for EOPNOSUPP and
2789 disable the srvino flag? or in caller? */
2790 rc = -EIO; /* bad smb */
2791 else {
2792 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2793 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2794 struct file_internal_info * pfinfo;
2795 /* BB Do we need a cast or hash here ? */
2796 if(count < 8) {
2797 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2798 rc = -EIO;
2799 goto GetInodeNumOut;
2801 pfinfo = (struct file_internal_info *)
2802 (data_offset + (char *) &pSMBr->hdr.Protocol);
2803 *inode_number = pfinfo->UniqueId;
2806 GetInodeNumOut:
2807 cifs_buf_release(pSMB);
2808 if (rc == -EAGAIN)
2809 goto GetInodeNumberRetry;
2810 return rc;
2812 #endif /* CIFS_EXPERIMENTAL */
2815 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2816 const unsigned char *searchName,
2817 unsigned char **targetUNCs,
2818 unsigned int *number_of_UNC_in_array,
2819 const struct nls_table *nls_codepage, int remap)
2821 /* TRANS2_GET_DFS_REFERRAL */
2822 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2823 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2824 struct dfs_referral_level_3 * referrals = NULL;
2825 int rc = 0;
2826 int bytes_returned;
2827 int name_len;
2828 unsigned int i;
2829 char * temp;
2830 __u16 params, byte_count;
2831 *number_of_UNC_in_array = 0;
2832 *targetUNCs = NULL;
2834 cFYI(1, ("In GetDFSRefer the path %s", searchName));
2835 if (ses == NULL)
2836 return -ENODEV;
2837 getDFSRetry:
2838 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2839 (void **) &pSMBr);
2840 if (rc)
2841 return rc;
2843 pSMB->hdr.Tid = ses->ipc_tid;
2844 pSMB->hdr.Uid = ses->Suid;
2845 if (ses->capabilities & CAP_STATUS32) {
2846 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2848 if (ses->capabilities & CAP_DFS) {
2849 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2852 if (ses->capabilities & CAP_UNICODE) {
2853 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2854 name_len =
2855 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
2856 searchName, PATH_MAX, nls_codepage, remap);
2857 name_len++; /* trailing null */
2858 name_len *= 2;
2859 } else { /* BB improve the check for buffer overruns BB */
2860 name_len = strnlen(searchName, PATH_MAX);
2861 name_len++; /* trailing null */
2862 strncpy(pSMB->RequestFileName, searchName, name_len);
2865 params = 2 /* level */ + name_len /*includes null */ ;
2866 pSMB->TotalDataCount = 0;
2867 pSMB->DataCount = 0;
2868 pSMB->DataOffset = 0;
2869 pSMB->MaxParameterCount = 0;
2870 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2871 pSMB->MaxSetupCount = 0;
2872 pSMB->Reserved = 0;
2873 pSMB->Flags = 0;
2874 pSMB->Timeout = 0;
2875 pSMB->Reserved2 = 0;
2876 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2877 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2878 pSMB->SetupCount = 1;
2879 pSMB->Reserved3 = 0;
2880 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2881 byte_count = params + 3 /* pad */ ;
2882 pSMB->ParameterCount = cpu_to_le16(params);
2883 pSMB->TotalParameterCount = pSMB->ParameterCount;
2884 pSMB->MaxReferralLevel = cpu_to_le16(3);
2885 pSMB->hdr.smb_buf_length += byte_count;
2886 pSMB->ByteCount = cpu_to_le16(byte_count);
2888 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2889 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2890 if (rc) {
2891 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2892 } else { /* decode response */
2893 /* BB Add logic to parse referrals here */
2894 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2896 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
2897 rc = -EIO; /* bad smb */
2898 else {
2899 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2900 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2902 cFYI(1,
2903 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
2904 pSMBr->ByteCount, data_offset));
2905 referrals =
2906 (struct dfs_referral_level_3 *)
2907 (8 /* sizeof start of data block */ +
2908 data_offset +
2909 (char *) &pSMBr->hdr.Protocol);
2910 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",
2911 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)));
2912 /* BB This field is actually two bytes in from start of
2913 data block so we could do safety check that DataBlock
2914 begins at address of pSMBr->NumberOfReferrals */
2915 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2917 /* BB Fix below so can return more than one referral */
2918 if(*number_of_UNC_in_array > 1)
2919 *number_of_UNC_in_array = 1;
2921 /* get the length of the strings describing refs */
2922 name_len = 0;
2923 for(i=0;i<*number_of_UNC_in_array;i++) {
2924 /* make sure that DfsPathOffset not past end */
2925 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2926 if (offset > data_count) {
2927 /* if invalid referral, stop here and do
2928 not try to copy any more */
2929 *number_of_UNC_in_array = i;
2930 break;
2932 temp = ((char *)referrals) + offset;
2934 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2935 name_len += UniStrnlen((wchar_t *)temp,data_count);
2936 } else {
2937 name_len += strnlen(temp,data_count);
2939 referrals++;
2940 /* BB add check that referral pointer does not fall off end PDU */
2943 /* BB add check for name_len bigger than bcc */
2944 *targetUNCs =
2945 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2946 if(*targetUNCs == NULL) {
2947 rc = -ENOMEM;
2948 goto GetDFSRefExit;
2950 /* copy the ref strings */
2951 referrals =
2952 (struct dfs_referral_level_3 *)
2953 (8 /* sizeof data hdr */ +
2954 data_offset +
2955 (char *) &pSMBr->hdr.Protocol);
2957 for(i=0;i<*number_of_UNC_in_array;i++) {
2958 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2959 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2960 cifs_strfromUCS_le(*targetUNCs,
2961 (wchar_t *) temp, name_len, nls_codepage);
2962 } else {
2963 strncpy(*targetUNCs,temp,name_len);
2965 /* BB update target_uncs pointers */
2966 referrals++;
2968 temp = *targetUNCs;
2969 temp[name_len] = 0;
2973 GetDFSRefExit:
2974 if (pSMB)
2975 cifs_buf_release(pSMB);
2977 if (rc == -EAGAIN)
2978 goto getDFSRetry;
2980 return rc;
2984 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
2986 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
2987 TRANSACTION2_QFSI_REQ *pSMB = NULL;
2988 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2989 FILE_SYSTEM_INFO *response_data;
2990 int rc = 0;
2991 int bytes_returned = 0;
2992 __u16 params, byte_count;
2994 cFYI(1, ("In QFSInfo"));
2995 QFSInfoRetry:
2996 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2997 (void **) &pSMBr);
2998 if (rc)
2999 return rc;
3001 params = 2; /* level */
3002 pSMB->TotalDataCount = 0;
3003 pSMB->MaxParameterCount = cpu_to_le16(2);
3004 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3005 pSMB->MaxSetupCount = 0;
3006 pSMB->Reserved = 0;
3007 pSMB->Flags = 0;
3008 pSMB->Timeout = 0;
3009 pSMB->Reserved2 = 0;
3010 byte_count = params + 1 /* pad */ ;
3011 pSMB->TotalParameterCount = cpu_to_le16(params);
3012 pSMB->ParameterCount = pSMB->TotalParameterCount;
3013 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3014 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3015 pSMB->DataCount = 0;
3016 pSMB->DataOffset = 0;
3017 pSMB->SetupCount = 1;
3018 pSMB->Reserved3 = 0;
3019 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3020 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3021 pSMB->hdr.smb_buf_length += byte_count;
3022 pSMB->ByteCount = cpu_to_le16(byte_count);
3024 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3026 if (rc) {
3027 cERROR(1, ("Send error in QFSInfo = %d", rc));
3028 } else { /* decode response */
3029 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3031 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3032 rc = -EIO; /* bad smb */
3033 else {
3034 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3035 cFYI(1,
3036 ("Decoding qfsinfo response. BCC: %d Offset %d",
3037 pSMBr->ByteCount, data_offset));
3039 response_data =
3040 (FILE_SYSTEM_INFO
3041 *) (((char *) &pSMBr->hdr.Protocol) +
3042 data_offset);
3043 FSData->f_bsize =
3044 le32_to_cpu(response_data->BytesPerSector) *
3045 le32_to_cpu(response_data->
3046 SectorsPerAllocationUnit);
3047 FSData->f_blocks =
3048 le64_to_cpu(response_data->TotalAllocationUnits);
3049 FSData->f_bfree = FSData->f_bavail =
3050 le64_to_cpu(response_data->FreeAllocationUnits);
3051 cFYI(1,
3052 ("Blocks: %lld Free: %lld Block size %ld",
3053 (unsigned long long)FSData->f_blocks,
3054 (unsigned long long)FSData->f_bfree,
3055 FSData->f_bsize));
3058 cifs_buf_release(pSMB);
3060 if (rc == -EAGAIN)
3061 goto QFSInfoRetry;
3063 return rc;
3067 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3069 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3070 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3071 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3072 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3073 int rc = 0;
3074 int bytes_returned = 0;
3075 __u16 params, byte_count;
3077 cFYI(1, ("In QFSAttributeInfo"));
3078 QFSAttributeRetry:
3079 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3080 (void **) &pSMBr);
3081 if (rc)
3082 return rc;
3084 params = 2; /* level */
3085 pSMB->TotalDataCount = 0;
3086 pSMB->MaxParameterCount = cpu_to_le16(2);
3087 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3088 pSMB->MaxSetupCount = 0;
3089 pSMB->Reserved = 0;
3090 pSMB->Flags = 0;
3091 pSMB->Timeout = 0;
3092 pSMB->Reserved2 = 0;
3093 byte_count = params + 1 /* pad */ ;
3094 pSMB->TotalParameterCount = cpu_to_le16(params);
3095 pSMB->ParameterCount = pSMB->TotalParameterCount;
3096 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3097 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3098 pSMB->DataCount = 0;
3099 pSMB->DataOffset = 0;
3100 pSMB->SetupCount = 1;
3101 pSMB->Reserved3 = 0;
3102 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3103 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3104 pSMB->hdr.smb_buf_length += byte_count;
3105 pSMB->ByteCount = cpu_to_le16(byte_count);
3107 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3108 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3109 if (rc) {
3110 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3111 } else { /* decode response */
3112 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3114 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3115 rc = -EIO; /* bad smb */
3116 } else {
3117 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3118 response_data =
3119 (FILE_SYSTEM_ATTRIBUTE_INFO
3120 *) (((char *) &pSMBr->hdr.Protocol) +
3121 data_offset);
3122 memcpy(&tcon->fsAttrInfo, response_data,
3123 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3126 cifs_buf_release(pSMB);
3128 if (rc == -EAGAIN)
3129 goto QFSAttributeRetry;
3131 return rc;
3135 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3137 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3138 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3139 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3140 FILE_SYSTEM_DEVICE_INFO *response_data;
3141 int rc = 0;
3142 int bytes_returned = 0;
3143 __u16 params, byte_count;
3145 cFYI(1, ("In QFSDeviceInfo"));
3146 QFSDeviceRetry:
3147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3148 (void **) &pSMBr);
3149 if (rc)
3150 return rc;
3152 params = 2; /* level */
3153 pSMB->TotalDataCount = 0;
3154 pSMB->MaxParameterCount = cpu_to_le16(2);
3155 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3156 pSMB->MaxSetupCount = 0;
3157 pSMB->Reserved = 0;
3158 pSMB->Flags = 0;
3159 pSMB->Timeout = 0;
3160 pSMB->Reserved2 = 0;
3161 byte_count = params + 1 /* pad */ ;
3162 pSMB->TotalParameterCount = cpu_to_le16(params);
3163 pSMB->ParameterCount = pSMB->TotalParameterCount;
3164 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3165 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3167 pSMB->DataCount = 0;
3168 pSMB->DataOffset = 0;
3169 pSMB->SetupCount = 1;
3170 pSMB->Reserved3 = 0;
3171 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3172 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3173 pSMB->hdr.smb_buf_length += byte_count;
3174 pSMB->ByteCount = cpu_to_le16(byte_count);
3176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3178 if (rc) {
3179 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3180 } else { /* decode response */
3181 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3183 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3184 rc = -EIO; /* bad smb */
3185 else {
3186 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3187 response_data =
3188 (FILE_SYSTEM_DEVICE_INFO *)
3189 (((char *) &pSMBr->hdr.Protocol) +
3190 data_offset);
3191 memcpy(&tcon->fsDevInfo, response_data,
3192 sizeof (FILE_SYSTEM_DEVICE_INFO));
3195 cifs_buf_release(pSMB);
3197 if (rc == -EAGAIN)
3198 goto QFSDeviceRetry;
3200 return rc;
3204 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3206 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3207 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3208 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3209 FILE_SYSTEM_UNIX_INFO *response_data;
3210 int rc = 0;
3211 int bytes_returned = 0;
3212 __u16 params, byte_count;
3214 cFYI(1, ("In QFSUnixInfo"));
3215 QFSUnixRetry:
3216 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3217 (void **) &pSMBr);
3218 if (rc)
3219 return rc;
3221 params = 2; /* level */
3222 pSMB->TotalDataCount = 0;
3223 pSMB->DataCount = 0;
3224 pSMB->DataOffset = 0;
3225 pSMB->MaxParameterCount = cpu_to_le16(2);
3226 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3227 pSMB->MaxSetupCount = 0;
3228 pSMB->Reserved = 0;
3229 pSMB->Flags = 0;
3230 pSMB->Timeout = 0;
3231 pSMB->Reserved2 = 0;
3232 byte_count = params + 1 /* pad */ ;
3233 pSMB->ParameterCount = cpu_to_le16(params);
3234 pSMB->TotalParameterCount = pSMB->ParameterCount;
3235 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3236 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3237 pSMB->SetupCount = 1;
3238 pSMB->Reserved3 = 0;
3239 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3240 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3241 pSMB->hdr.smb_buf_length += byte_count;
3242 pSMB->ByteCount = cpu_to_le16(byte_count);
3244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3246 if (rc) {
3247 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3248 } else { /* decode response */
3249 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3251 if (rc || (pSMBr->ByteCount < 13)) {
3252 rc = -EIO; /* bad smb */
3253 } else {
3254 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3255 response_data =
3256 (FILE_SYSTEM_UNIX_INFO
3257 *) (((char *) &pSMBr->hdr.Protocol) +
3258 data_offset);
3259 memcpy(&tcon->fsUnixInfo, response_data,
3260 sizeof (FILE_SYSTEM_UNIX_INFO));
3263 cifs_buf_release(pSMB);
3265 if (rc == -EAGAIN)
3266 goto QFSUnixRetry;
3269 return rc;
3274 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3275 struct kstatfs *FSData)
3277 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3278 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3279 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3280 FILE_SYSTEM_POSIX_INFO *response_data;
3281 int rc = 0;
3282 int bytes_returned = 0;
3283 __u16 params, byte_count;
3285 cFYI(1, ("In QFSPosixInfo"));
3286 QFSPosixRetry:
3287 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3288 (void **) &pSMBr);
3289 if (rc)
3290 return rc;
3292 params = 2; /* level */
3293 pSMB->TotalDataCount = 0;
3294 pSMB->DataCount = 0;
3295 pSMB->DataOffset = 0;
3296 pSMB->MaxParameterCount = cpu_to_le16(2);
3297 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3298 pSMB->MaxSetupCount = 0;
3299 pSMB->Reserved = 0;
3300 pSMB->Flags = 0;
3301 pSMB->Timeout = 0;
3302 pSMB->Reserved2 = 0;
3303 byte_count = params + 1 /* pad */ ;
3304 pSMB->ParameterCount = cpu_to_le16(params);
3305 pSMB->TotalParameterCount = pSMB->ParameterCount;
3306 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3307 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3308 pSMB->SetupCount = 1;
3309 pSMB->Reserved3 = 0;
3310 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3311 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3312 pSMB->hdr.smb_buf_length += byte_count;
3313 pSMB->ByteCount = cpu_to_le16(byte_count);
3315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3317 if (rc) {
3318 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3319 } else { /* decode response */
3320 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3322 if (rc || (pSMBr->ByteCount < 13)) {
3323 rc = -EIO; /* bad smb */
3324 } else {
3325 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3326 response_data =
3327 (FILE_SYSTEM_POSIX_INFO
3328 *) (((char *) &pSMBr->hdr.Protocol) +
3329 data_offset);
3330 FSData->f_bsize =
3331 le32_to_cpu(response_data->BlockSize);
3332 FSData->f_blocks =
3333 le64_to_cpu(response_data->TotalBlocks);
3334 FSData->f_bfree =
3335 le64_to_cpu(response_data->BlocksAvail);
3336 if(response_data->UserBlocksAvail == -1) {
3337 FSData->f_bavail = FSData->f_bfree;
3338 } else {
3339 FSData->f_bavail =
3340 le64_to_cpu(response_data->UserBlocksAvail);
3342 if(response_data->TotalFileNodes != -1)
3343 FSData->f_files =
3344 le64_to_cpu(response_data->TotalFileNodes);
3345 if(response_data->FreeFileNodes != -1)
3346 FSData->f_ffree =
3347 le64_to_cpu(response_data->FreeFileNodes);
3350 cifs_buf_release(pSMB);
3352 if (rc == -EAGAIN)
3353 goto QFSPosixRetry;
3355 return rc;
3359 /* We can not use write of zero bytes trick to
3360 set file size due to need for large file support. Also note that
3361 this SetPathInfo is preferred to SetFileInfo based method in next
3362 routine which is only needed to work around a sharing violation bug
3363 in Samba which this routine can run into */
3366 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3367 __u64 size, int SetAllocation,
3368 const struct nls_table *nls_codepage, int remap)
3370 struct smb_com_transaction2_spi_req *pSMB = NULL;
3371 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3372 struct file_end_of_file_info *parm_data;
3373 int name_len;
3374 int rc = 0;
3375 int bytes_returned = 0;
3376 __u16 params, byte_count, data_count, param_offset, offset;
3378 cFYI(1, ("In SetEOF"));
3379 SetEOFRetry:
3380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3381 (void **) &pSMBr);
3382 if (rc)
3383 return rc;
3385 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3386 name_len =
3387 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3388 PATH_MAX, nls_codepage, remap);
3389 name_len++; /* trailing null */
3390 name_len *= 2;
3391 } else { /* BB improve the check for buffer overruns BB */
3392 name_len = strnlen(fileName, PATH_MAX);
3393 name_len++; /* trailing null */
3394 strncpy(pSMB->FileName, fileName, name_len);
3396 params = 6 + name_len;
3397 data_count = sizeof (struct file_end_of_file_info);
3398 pSMB->MaxParameterCount = cpu_to_le16(2);
3399 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3400 pSMB->MaxSetupCount = 0;
3401 pSMB->Reserved = 0;
3402 pSMB->Flags = 0;
3403 pSMB->Timeout = 0;
3404 pSMB->Reserved2 = 0;
3405 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3406 InformationLevel) - 4;
3407 offset = param_offset + params;
3408 if(SetAllocation) {
3409 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3410 pSMB->InformationLevel =
3411 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3412 else
3413 pSMB->InformationLevel =
3414 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3415 } else /* Set File Size */ {
3416 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3417 pSMB->InformationLevel =
3418 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3419 else
3420 pSMB->InformationLevel =
3421 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3424 parm_data =
3425 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3426 offset);
3427 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3428 pSMB->DataOffset = cpu_to_le16(offset);
3429 pSMB->SetupCount = 1;
3430 pSMB->Reserved3 = 0;
3431 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3432 byte_count = 3 /* pad */ + params + data_count;
3433 pSMB->DataCount = cpu_to_le16(data_count);
3434 pSMB->TotalDataCount = pSMB->DataCount;
3435 pSMB->ParameterCount = cpu_to_le16(params);
3436 pSMB->TotalParameterCount = pSMB->ParameterCount;
3437 pSMB->Reserved4 = 0;
3438 pSMB->hdr.smb_buf_length += byte_count;
3439 parm_data->FileSize = cpu_to_le64(size);
3440 pSMB->ByteCount = cpu_to_le16(byte_count);
3441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3443 if (rc) {
3444 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3447 cifs_buf_release(pSMB);
3449 if (rc == -EAGAIN)
3450 goto SetEOFRetry;
3452 return rc;
3456 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3457 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3459 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3460 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3461 char *data_offset;
3462 struct file_end_of_file_info *parm_data;
3463 int rc = 0;
3464 int bytes_returned = 0;
3465 __u16 params, param_offset, offset, byte_count, count;
3467 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3468 (long long)size));
3469 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3471 if (rc)
3472 return rc;
3474 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3476 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3477 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3479 params = 6;
3480 pSMB->MaxSetupCount = 0;
3481 pSMB->Reserved = 0;
3482 pSMB->Flags = 0;
3483 pSMB->Timeout = 0;
3484 pSMB->Reserved2 = 0;
3485 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3486 offset = param_offset + params;
3488 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3490 count = sizeof(struct file_end_of_file_info);
3491 pSMB->MaxParameterCount = cpu_to_le16(2);
3492 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3493 pSMB->SetupCount = 1;
3494 pSMB->Reserved3 = 0;
3495 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3496 byte_count = 3 /* pad */ + params + count;
3497 pSMB->DataCount = cpu_to_le16(count);
3498 pSMB->ParameterCount = cpu_to_le16(params);
3499 pSMB->TotalDataCount = pSMB->DataCount;
3500 pSMB->TotalParameterCount = pSMB->ParameterCount;
3501 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3502 parm_data =
3503 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3504 offset);
3505 pSMB->DataOffset = cpu_to_le16(offset);
3506 parm_data->FileSize = cpu_to_le64(size);
3507 pSMB->Fid = fid;
3508 if(SetAllocation) {
3509 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3510 pSMB->InformationLevel =
3511 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3512 else
3513 pSMB->InformationLevel =
3514 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3515 } else /* Set File Size */ {
3516 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3517 pSMB->InformationLevel =
3518 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3519 else
3520 pSMB->InformationLevel =
3521 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3523 pSMB->Reserved4 = 0;
3524 pSMB->hdr.smb_buf_length += byte_count;
3525 pSMB->ByteCount = cpu_to_le16(byte_count);
3526 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3527 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3528 if (rc) {
3529 cFYI(1,
3530 ("Send error in SetFileInfo (SetFileSize) = %d",
3531 rc));
3534 if (pSMB)
3535 cifs_small_buf_release(pSMB);
3537 /* Note: On -EAGAIN error only caller can retry on handle based calls
3538 since file handle passed in no longer valid */
3540 return rc;
3543 /* Some legacy servers such as NT4 require that the file times be set on
3544 an open handle, rather than by pathname - this is awkward due to
3545 potential access conflicts on the open, but it is unavoidable for these
3546 old servers since the only other choice is to go from 100 nanosecond DCE
3547 time and resort to the original setpathinfo level which takes the ancient
3548 DOS time format with 2 second granularity */
3550 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3551 __u16 fid)
3553 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3554 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3555 char *data_offset;
3556 int rc = 0;
3557 int bytes_returned = 0;
3558 __u16 params, param_offset, offset, byte_count, count;
3560 cFYI(1, ("Set Times (via SetFileInfo)"));
3561 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3563 if (rc)
3564 return rc;
3566 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3568 /* At this point there is no need to override the current pid
3569 with the pid of the opener, but that could change if we someday
3570 use an existing handle (rather than opening one on the fly) */
3571 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3572 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3574 params = 6;
3575 pSMB->MaxSetupCount = 0;
3576 pSMB->Reserved = 0;
3577 pSMB->Flags = 0;
3578 pSMB->Timeout = 0;
3579 pSMB->Reserved2 = 0;
3580 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3581 offset = param_offset + params;
3583 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3585 count = sizeof (FILE_BASIC_INFO);
3586 pSMB->MaxParameterCount = cpu_to_le16(2);
3587 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3588 pSMB->SetupCount = 1;
3589 pSMB->Reserved3 = 0;
3590 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3591 byte_count = 3 /* pad */ + params + count;
3592 pSMB->DataCount = cpu_to_le16(count);
3593 pSMB->ParameterCount = cpu_to_le16(params);
3594 pSMB->TotalDataCount = pSMB->DataCount;
3595 pSMB->TotalParameterCount = pSMB->ParameterCount;
3596 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3597 pSMB->DataOffset = cpu_to_le16(offset);
3598 pSMB->Fid = fid;
3599 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3600 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3601 else
3602 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3603 pSMB->Reserved4 = 0;
3604 pSMB->hdr.smb_buf_length += byte_count;
3605 pSMB->ByteCount = cpu_to_le16(byte_count);
3606 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3607 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3609 if (rc) {
3610 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3613 cifs_small_buf_release(pSMB);
3615 /* Note: On -EAGAIN error only caller can retry on handle based calls
3616 since file handle passed in no longer valid */
3618 return rc;
3623 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3624 const FILE_BASIC_INFO * data,
3625 const struct nls_table *nls_codepage, int remap)
3627 TRANSACTION2_SPI_REQ *pSMB = NULL;
3628 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3629 int name_len;
3630 int rc = 0;
3631 int bytes_returned = 0;
3632 char *data_offset;
3633 __u16 params, param_offset, offset, byte_count, count;
3635 cFYI(1, ("In SetTimes"));
3637 SetTimesRetry:
3638 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3639 (void **) &pSMBr);
3640 if (rc)
3641 return rc;
3643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3644 name_len =
3645 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3646 PATH_MAX, nls_codepage, remap);
3647 name_len++; /* trailing null */
3648 name_len *= 2;
3649 } else { /* BB improve the check for buffer overruns BB */
3650 name_len = strnlen(fileName, PATH_MAX);
3651 name_len++; /* trailing null */
3652 strncpy(pSMB->FileName, fileName, name_len);
3655 params = 6 + name_len;
3656 count = sizeof (FILE_BASIC_INFO);
3657 pSMB->MaxParameterCount = cpu_to_le16(2);
3658 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3659 pSMB->MaxSetupCount = 0;
3660 pSMB->Reserved = 0;
3661 pSMB->Flags = 0;
3662 pSMB->Timeout = 0;
3663 pSMB->Reserved2 = 0;
3664 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3665 InformationLevel) - 4;
3666 offset = param_offset + params;
3667 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3668 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3669 pSMB->DataOffset = cpu_to_le16(offset);
3670 pSMB->SetupCount = 1;
3671 pSMB->Reserved3 = 0;
3672 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3673 byte_count = 3 /* pad */ + params + count;
3675 pSMB->DataCount = cpu_to_le16(count);
3676 pSMB->ParameterCount = cpu_to_le16(params);
3677 pSMB->TotalDataCount = pSMB->DataCount;
3678 pSMB->TotalParameterCount = pSMB->ParameterCount;
3679 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3680 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3681 else
3682 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3683 pSMB->Reserved4 = 0;
3684 pSMB->hdr.smb_buf_length += byte_count;
3685 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3686 pSMB->ByteCount = cpu_to_le16(byte_count);
3687 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3688 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3689 if (rc) {
3690 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3693 cifs_buf_release(pSMB);
3695 if (rc == -EAGAIN)
3696 goto SetTimesRetry;
3698 return rc;
3701 /* Can not be used to set time stamps yet (due to old DOS time format) */
3702 /* Can be used to set attributes */
3703 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
3704 handling it anyway and NT4 was what we thought it would be needed for
3705 Do not delete it until we prove whether needed for Win9x though */
3707 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3708 __u16 dos_attrs, const struct nls_table *nls_codepage)
3710 SETATTR_REQ *pSMB = NULL;
3711 SETATTR_RSP *pSMBr = NULL;
3712 int rc = 0;
3713 int bytes_returned;
3714 int name_len;
3716 cFYI(1, ("In SetAttrLegacy"));
3718 SetAttrLgcyRetry:
3719 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3720 (void **) &pSMBr);
3721 if (rc)
3722 return rc;
3724 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3725 name_len =
3726 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
3727 PATH_MAX, nls_codepage);
3728 name_len++; /* trailing null */
3729 name_len *= 2;
3730 } else { /* BB improve the check for buffer overruns BB */
3731 name_len = strnlen(fileName, PATH_MAX);
3732 name_len++; /* trailing null */
3733 strncpy(pSMB->fileName, fileName, name_len);
3735 pSMB->attr = cpu_to_le16(dos_attrs);
3736 pSMB->BufferFormat = 0x04;
3737 pSMB->hdr.smb_buf_length += name_len + 1;
3738 pSMB->ByteCount = cpu_to_le16(name_len + 1);
3739 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3740 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3741 if (rc) {
3742 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3745 cifs_buf_release(pSMB);
3747 if (rc == -EAGAIN)
3748 goto SetAttrLgcyRetry;
3750 return rc;
3752 #endif /* temporarily unneeded SetAttr legacy function */
3755 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
3756 char *fileName, __u64 mode, __u64 uid, __u64 gid,
3757 dev_t device, const struct nls_table *nls_codepage,
3758 int remap)
3760 TRANSACTION2_SPI_REQ *pSMB = NULL;
3761 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3762 int name_len;
3763 int rc = 0;
3764 int bytes_returned = 0;
3765 FILE_UNIX_BASIC_INFO *data_offset;
3766 __u16 params, param_offset, offset, count, byte_count;
3768 cFYI(1, ("In SetUID/GID/Mode"));
3769 setPermsRetry:
3770 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3771 (void **) &pSMBr);
3772 if (rc)
3773 return rc;
3775 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3776 name_len =
3777 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3778 PATH_MAX, nls_codepage, remap);
3779 name_len++; /* trailing null */
3780 name_len *= 2;
3781 } else { /* BB improve the check for buffer overruns BB */
3782 name_len = strnlen(fileName, PATH_MAX);
3783 name_len++; /* trailing null */
3784 strncpy(pSMB->FileName, fileName, name_len);
3787 params = 6 + name_len;
3788 count = sizeof (FILE_UNIX_BASIC_INFO);
3789 pSMB->MaxParameterCount = cpu_to_le16(2);
3790 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3791 pSMB->MaxSetupCount = 0;
3792 pSMB->Reserved = 0;
3793 pSMB->Flags = 0;
3794 pSMB->Timeout = 0;
3795 pSMB->Reserved2 = 0;
3796 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3797 InformationLevel) - 4;
3798 offset = param_offset + params;
3799 data_offset =
3800 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3801 offset);
3802 memset(data_offset, 0, count);
3803 pSMB->DataOffset = cpu_to_le16(offset);
3804 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3805 pSMB->SetupCount = 1;
3806 pSMB->Reserved3 = 0;
3807 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3808 byte_count = 3 /* pad */ + params + count;
3809 pSMB->ParameterCount = cpu_to_le16(params);
3810 pSMB->DataCount = cpu_to_le16(count);
3811 pSMB->TotalParameterCount = pSMB->ParameterCount;
3812 pSMB->TotalDataCount = pSMB->DataCount;
3813 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3814 pSMB->Reserved4 = 0;
3815 pSMB->hdr.smb_buf_length += byte_count;
3816 data_offset->Uid = cpu_to_le64(uid);
3817 data_offset->Gid = cpu_to_le64(gid);
3818 /* better to leave device as zero when it is */
3819 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3820 data_offset->DevMinor = cpu_to_le64(MINOR(device));
3821 data_offset->Permissions = cpu_to_le64(mode);
3823 if(S_ISREG(mode))
3824 data_offset->Type = cpu_to_le32(UNIX_FILE);
3825 else if(S_ISDIR(mode))
3826 data_offset->Type = cpu_to_le32(UNIX_DIR);
3827 else if(S_ISLNK(mode))
3828 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3829 else if(S_ISCHR(mode))
3830 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3831 else if(S_ISBLK(mode))
3832 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3833 else if(S_ISFIFO(mode))
3834 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3835 else if(S_ISSOCK(mode))
3836 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3839 pSMB->ByteCount = cpu_to_le16(byte_count);
3840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3842 if (rc) {
3843 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3846 if (pSMB)
3847 cifs_buf_release(pSMB);
3848 if (rc == -EAGAIN)
3849 goto setPermsRetry;
3850 return rc;
3853 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
3854 const int notify_subdirs, const __u16 netfid,
3855 __u32 filter, const struct nls_table *nls_codepage)
3857 int rc = 0;
3858 struct smb_com_transaction_change_notify_req * pSMB = NULL;
3859 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3860 int bytes_returned;
3862 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3863 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3864 (void **) &pSMBr);
3865 if (rc)
3866 return rc;
3868 pSMB->TotalParameterCount = 0 ;
3869 pSMB->TotalDataCount = 0;
3870 pSMB->MaxParameterCount = cpu_to_le32(2);
3871 /* BB find exact data count max from sess structure BB */
3872 pSMB->MaxDataCount = 0; /* same in little endian or be */
3873 pSMB->MaxSetupCount = 4;
3874 pSMB->Reserved = 0;
3875 pSMB->ParameterOffset = 0;
3876 pSMB->DataCount = 0;
3877 pSMB->DataOffset = 0;
3878 pSMB->SetupCount = 4; /* single byte does not need le conversion */
3879 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3880 pSMB->ParameterCount = pSMB->TotalParameterCount;
3881 if(notify_subdirs)
3882 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3883 pSMB->Reserved2 = 0;
3884 pSMB->CompletionFilter = cpu_to_le32(filter);
3885 pSMB->Fid = netfid; /* file handle always le */
3886 pSMB->ByteCount = 0;
3888 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3889 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3890 if (rc) {
3891 cFYI(1, ("Error in Notify = %d", rc));
3893 cifs_buf_release(pSMB);
3894 return rc;
3896 #ifdef CONFIG_CIFS_XATTR
3897 ssize_t
3898 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3899 const unsigned char *searchName,
3900 char * EAData, size_t buf_size,
3901 const struct nls_table *nls_codepage, int remap)
3903 /* BB assumes one setup word */
3904 TRANSACTION2_QPI_REQ *pSMB = NULL;
3905 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3906 int rc = 0;
3907 int bytes_returned;
3908 int name_len;
3909 struct fea * temp_fea;
3910 char * temp_ptr;
3911 __u16 params, byte_count;
3913 cFYI(1, ("In Query All EAs path %s", searchName));
3914 QAllEAsRetry:
3915 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3916 (void **) &pSMBr);
3917 if (rc)
3918 return rc;
3920 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3921 name_len =
3922 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3923 PATH_MAX, nls_codepage, remap);
3924 name_len++; /* trailing null */
3925 name_len *= 2;
3926 } else { /* BB improve the check for buffer overruns BB */
3927 name_len = strnlen(searchName, PATH_MAX);
3928 name_len++; /* trailing null */
3929 strncpy(pSMB->FileName, searchName, name_len);
3932 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3933 pSMB->TotalDataCount = 0;
3934 pSMB->MaxParameterCount = cpu_to_le16(2);
3935 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3936 pSMB->MaxSetupCount = 0;
3937 pSMB->Reserved = 0;
3938 pSMB->Flags = 0;
3939 pSMB->Timeout = 0;
3940 pSMB->Reserved2 = 0;
3941 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3942 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3943 pSMB->DataCount = 0;
3944 pSMB->DataOffset = 0;
3945 pSMB->SetupCount = 1;
3946 pSMB->Reserved3 = 0;
3947 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3948 byte_count = params + 1 /* pad */ ;
3949 pSMB->TotalParameterCount = cpu_to_le16(params);
3950 pSMB->ParameterCount = pSMB->TotalParameterCount;
3951 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3952 pSMB->Reserved4 = 0;
3953 pSMB->hdr.smb_buf_length += byte_count;
3954 pSMB->ByteCount = cpu_to_le16(byte_count);
3956 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3957 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3958 if (rc) {
3959 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3960 } else { /* decode response */
3961 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3963 /* BB also check enough total bytes returned */
3964 /* BB we need to improve the validity checking
3965 of these trans2 responses */
3966 if (rc || (pSMBr->ByteCount < 4))
3967 rc = -EIO; /* bad smb */
3968 /* else if (pFindData){
3969 memcpy((char *) pFindData,
3970 (char *) &pSMBr->hdr.Protocol +
3971 data_offset, kl);
3972 }*/ else {
3973 /* check that length of list is not more than bcc */
3974 /* check that each entry does not go beyond length
3975 of list */
3976 /* check that each element of each entry does not
3977 go beyond end of list */
3978 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3979 struct fealist * ea_response_data;
3980 rc = 0;
3981 /* validate_trans2_offsets() */
3982 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
3983 ea_response_data = (struct fealist *)
3984 (((char *) &pSMBr->hdr.Protocol) +
3985 data_offset);
3986 name_len = le32_to_cpu(ea_response_data->list_len);
3987 cFYI(1,("ea length %d", name_len));
3988 if(name_len <= 8) {
3989 /* returned EA size zeroed at top of function */
3990 cFYI(1,("empty EA list returned from server"));
3991 } else {
3992 /* account for ea list len */
3993 name_len -= 4;
3994 temp_fea = ea_response_data->list;
3995 temp_ptr = (char *)temp_fea;
3996 while(name_len > 0) {
3997 __u16 value_len;
3998 name_len -= 4;
3999 temp_ptr += 4;
4000 rc += temp_fea->name_len;
4001 /* account for prefix user. and trailing null */
4002 rc = rc + 5 + 1;
4003 if(rc<(int)buf_size) {
4004 memcpy(EAData,"user.",5);
4005 EAData+=5;
4006 memcpy(EAData,temp_ptr,temp_fea->name_len);
4007 EAData+=temp_fea->name_len;
4008 /* null terminate name */
4009 *EAData = 0;
4010 EAData = EAData + 1;
4011 } else if(buf_size == 0) {
4012 /* skip copy - calc size only */
4013 } else {
4014 /* stop before overrun buffer */
4015 rc = -ERANGE;
4016 break;
4018 name_len -= temp_fea->name_len;
4019 temp_ptr += temp_fea->name_len;
4020 /* account for trailing null */
4021 name_len--;
4022 temp_ptr++;
4023 value_len = le16_to_cpu(temp_fea->value_len);
4024 name_len -= value_len;
4025 temp_ptr += value_len;
4026 /* BB check that temp_ptr is still within smb BB*/
4027 /* no trailing null to account for in value len */
4028 /* go on to next EA */
4029 temp_fea = (struct fea *)temp_ptr;
4034 if (pSMB)
4035 cifs_buf_release(pSMB);
4036 if (rc == -EAGAIN)
4037 goto QAllEAsRetry;
4039 return (ssize_t)rc;
4042 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4043 const unsigned char * searchName,const unsigned char * ea_name,
4044 unsigned char * ea_value, size_t buf_size,
4045 const struct nls_table *nls_codepage, int remap)
4047 TRANSACTION2_QPI_REQ *pSMB = NULL;
4048 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4049 int rc = 0;
4050 int bytes_returned;
4051 int name_len;
4052 struct fea * temp_fea;
4053 char * temp_ptr;
4054 __u16 params, byte_count;
4056 cFYI(1, ("In Query EA path %s", searchName));
4057 QEARetry:
4058 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4059 (void **) &pSMBr);
4060 if (rc)
4061 return rc;
4063 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4064 name_len =
4065 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4066 PATH_MAX, nls_codepage, remap);
4067 name_len++; /* trailing null */
4068 name_len *= 2;
4069 } else { /* BB improve the check for buffer overruns BB */
4070 name_len = strnlen(searchName, PATH_MAX);
4071 name_len++; /* trailing null */
4072 strncpy(pSMB->FileName, searchName, name_len);
4075 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4076 pSMB->TotalDataCount = 0;
4077 pSMB->MaxParameterCount = cpu_to_le16(2);
4078 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4079 pSMB->MaxSetupCount = 0;
4080 pSMB->Reserved = 0;
4081 pSMB->Flags = 0;
4082 pSMB->Timeout = 0;
4083 pSMB->Reserved2 = 0;
4084 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4085 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4086 pSMB->DataCount = 0;
4087 pSMB->DataOffset = 0;
4088 pSMB->SetupCount = 1;
4089 pSMB->Reserved3 = 0;
4090 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4091 byte_count = params + 1 /* pad */ ;
4092 pSMB->TotalParameterCount = cpu_to_le16(params);
4093 pSMB->ParameterCount = pSMB->TotalParameterCount;
4094 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4095 pSMB->Reserved4 = 0;
4096 pSMB->hdr.smb_buf_length += byte_count;
4097 pSMB->ByteCount = cpu_to_le16(byte_count);
4099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4101 if (rc) {
4102 cFYI(1, ("Send error in Query EA = %d", rc));
4103 } else { /* decode response */
4104 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4106 /* BB also check enough total bytes returned */
4107 /* BB we need to improve the validity checking
4108 of these trans2 responses */
4109 if (rc || (pSMBr->ByteCount < 4))
4110 rc = -EIO; /* bad smb */
4111 /* else if (pFindData){
4112 memcpy((char *) pFindData,
4113 (char *) &pSMBr->hdr.Protocol +
4114 data_offset, kl);
4115 }*/ else {
4116 /* check that length of list is not more than bcc */
4117 /* check that each entry does not go beyond length
4118 of list */
4119 /* check that each element of each entry does not
4120 go beyond end of list */
4121 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4122 struct fealist * ea_response_data;
4123 rc = -ENODATA;
4124 /* validate_trans2_offsets() */
4125 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4126 ea_response_data = (struct fealist *)
4127 (((char *) &pSMBr->hdr.Protocol) +
4128 data_offset);
4129 name_len = le32_to_cpu(ea_response_data->list_len);
4130 cFYI(1,("ea length %d", name_len));
4131 if(name_len <= 8) {
4132 /* returned EA size zeroed at top of function */
4133 cFYI(1,("empty EA list returned from server"));
4134 } else {
4135 /* account for ea list len */
4136 name_len -= 4;
4137 temp_fea = ea_response_data->list;
4138 temp_ptr = (char *)temp_fea;
4139 /* loop through checking if we have a matching
4140 name and then return the associated value */
4141 while(name_len > 0) {
4142 __u16 value_len;
4143 name_len -= 4;
4144 temp_ptr += 4;
4145 value_len = le16_to_cpu(temp_fea->value_len);
4146 /* BB validate that value_len falls within SMB,
4147 even though maximum for name_len is 255 */
4148 if(memcmp(temp_fea->name,ea_name,
4149 temp_fea->name_len) == 0) {
4150 /* found a match */
4151 rc = value_len;
4152 /* account for prefix user. and trailing null */
4153 if(rc<=(int)buf_size) {
4154 memcpy(ea_value,
4155 temp_fea->name+temp_fea->name_len+1,
4156 rc);
4157 /* ea values, unlike ea names,
4158 are not null terminated */
4159 } else if(buf_size == 0) {
4160 /* skip copy - calc size only */
4161 } else {
4162 /* stop before overrun buffer */
4163 rc = -ERANGE;
4165 break;
4167 name_len -= temp_fea->name_len;
4168 temp_ptr += temp_fea->name_len;
4169 /* account for trailing null */
4170 name_len--;
4171 temp_ptr++;
4172 name_len -= value_len;
4173 temp_ptr += value_len;
4174 /* no trailing null to account for in value len */
4175 /* go on to next EA */
4176 temp_fea = (struct fea *)temp_ptr;
4181 if (pSMB)
4182 cifs_buf_release(pSMB);
4183 if (rc == -EAGAIN)
4184 goto QEARetry;
4186 return (ssize_t)rc;
4190 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4191 const char * ea_name, const void * ea_value,
4192 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4193 int remap)
4195 struct smb_com_transaction2_spi_req *pSMB = NULL;
4196 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4197 struct fealist *parm_data;
4198 int name_len;
4199 int rc = 0;
4200 int bytes_returned = 0;
4201 __u16 params, param_offset, byte_count, offset, count;
4203 cFYI(1, ("In SetEA"));
4204 SetEARetry:
4205 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4206 (void **) &pSMBr);
4207 if (rc)
4208 return rc;
4210 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4211 name_len =
4212 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4213 PATH_MAX, nls_codepage, remap);
4214 name_len++; /* trailing null */
4215 name_len *= 2;
4216 } else { /* BB improve the check for buffer overruns BB */
4217 name_len = strnlen(fileName, PATH_MAX);
4218 name_len++; /* trailing null */
4219 strncpy(pSMB->FileName, fileName, name_len);
4222 params = 6 + name_len;
4224 /* done calculating parms using name_len of file name,
4225 now use name_len to calculate length of ea name
4226 we are going to create in the inode xattrs */
4227 if(ea_name == NULL)
4228 name_len = 0;
4229 else
4230 name_len = strnlen(ea_name,255);
4232 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4233 pSMB->MaxParameterCount = cpu_to_le16(2);
4234 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4235 pSMB->MaxSetupCount = 0;
4236 pSMB->Reserved = 0;
4237 pSMB->Flags = 0;
4238 pSMB->Timeout = 0;
4239 pSMB->Reserved2 = 0;
4240 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4241 InformationLevel) - 4;
4242 offset = param_offset + params;
4243 pSMB->InformationLevel =
4244 cpu_to_le16(SMB_SET_FILE_EA);
4246 parm_data =
4247 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4248 offset);
4249 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4250 pSMB->DataOffset = cpu_to_le16(offset);
4251 pSMB->SetupCount = 1;
4252 pSMB->Reserved3 = 0;
4253 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4254 byte_count = 3 /* pad */ + params + count;
4255 pSMB->DataCount = cpu_to_le16(count);
4256 parm_data->list_len = cpu_to_le32(count);
4257 parm_data->list[0].EA_flags = 0;
4258 /* we checked above that name len is less than 255 */
4259 parm_data->list[0].name_len = (__u8)name_len;;
4260 /* EA names are always ASCII */
4261 if(ea_name)
4262 strncpy(parm_data->list[0].name,ea_name,name_len);
4263 parm_data->list[0].name[name_len] = 0;
4264 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4265 /* caller ensures that ea_value_len is less than 64K but
4266 we need to ensure that it fits within the smb */
4268 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4269 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4270 if(ea_value_len)
4271 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4273 pSMB->TotalDataCount = pSMB->DataCount;
4274 pSMB->ParameterCount = cpu_to_le16(params);
4275 pSMB->TotalParameterCount = pSMB->ParameterCount;
4276 pSMB->Reserved4 = 0;
4277 pSMB->hdr.smb_buf_length += byte_count;
4278 pSMB->ByteCount = cpu_to_le16(byte_count);
4279 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4280 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4281 if (rc) {
4282 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4285 cifs_buf_release(pSMB);
4287 if (rc == -EAGAIN)
4288 goto SetEARetry;
4290 return rc;
4293 #endif