[TG3]: 5780 PHY fixes
[linux-2.6/libata-dev.git] / fs / cifs / cifssmb.c
blob0db0b313d7150f49795c0cc2a765d1abe298f0b0
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
954 int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
955 const int netfid, const unsigned int count,
956 const __u64 offset, unsigned int *nbytes, const char __user *buf,
957 const int long_op)
959 int rc = -EACCES;
960 WRITE_REQ *pSMB = NULL;
961 WRITE_RSP *pSMBr = NULL;
962 /*int bytes_returned;*/
963 unsigned bytes_sent;
964 __u16 byte_count;
966 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
968 if (rc)
969 return rc;
971 pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
973 /* tcon and ses pointer are checked in smb_init */
974 if (tcon->ses->server == NULL)
975 return -ECONNABORTED;
977 pSMB->AndXCommand = 0xFF; /* none */
978 pSMB->Fid = netfid;
979 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
980 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
981 pSMB->Reserved = 0xFFFFFFFF;
982 pSMB->WriteMode = 0;
983 pSMB->Remaining = 0;
984 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
985 if (bytes_sent > count)
986 bytes_sent = count;
987 pSMB->DataLengthHigh = 0;
988 pSMB->DataOffset =
989 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
991 byte_count = bytes_sent + 1 /* pad */ ;
992 pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
993 pSMB->DataLengthHigh = 0;
994 pSMB->hdr.smb_buf_length += byte_count;
995 pSMB->ByteCount = cpu_to_le16(byte_count);
997 /* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */
999 if (rc) {
1000 cFYI(1, ("Send error in write2 (large write) = %d", rc));
1001 *nbytes = 0;
1002 } else
1003 *nbytes = le16_to_cpu(pSMBr->Count);
1005 cifs_small_buf_release(pSMB);
1007 /* Note: On -EAGAIN error only caller can retry on handle based calls
1008 since file handle passed in no longer valid */
1010 return rc;
1012 #endif /* CIFS_EXPERIMENTAL */
1015 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1016 const __u16 smb_file_id, const __u64 len,
1017 const __u64 offset, const __u32 numUnlock,
1018 const __u32 numLock, const __u8 lockType, const int waitFlag)
1020 int rc = 0;
1021 LOCK_REQ *pSMB = NULL;
1022 LOCK_RSP *pSMBr = NULL;
1023 int bytes_returned;
1024 int timeout = 0;
1025 __u16 count;
1027 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1028 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1030 if (rc)
1031 return rc;
1033 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1035 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1036 timeout = -1; /* no response expected */
1037 pSMB->Timeout = 0;
1038 } else if (waitFlag == TRUE) {
1039 timeout = 3; /* blocking operation, no timeout */
1040 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1041 } else {
1042 pSMB->Timeout = 0;
1045 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1046 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1047 pSMB->LockType = lockType;
1048 pSMB->AndXCommand = 0xFF; /* none */
1049 pSMB->Fid = smb_file_id; /* netfid stays le */
1051 if((numLock != 0) || (numUnlock != 0)) {
1052 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1053 /* BB where to store pid high? */
1054 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1055 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1056 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1057 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1058 count = sizeof(LOCKING_ANDX_RANGE);
1059 } else {
1060 /* oplock break */
1061 count = 0;
1063 pSMB->hdr.smb_buf_length += count;
1064 pSMB->ByteCount = cpu_to_le16(count);
1066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1067 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1069 if (rc) {
1070 cFYI(1, ("Send error in Lock = %d", rc));
1072 cifs_small_buf_release(pSMB);
1074 /* Note: On -EAGAIN error only caller can retry on handle based calls
1075 since file handle passed in no longer valid */
1076 return rc;
1080 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1082 int rc = 0;
1083 CLOSE_REQ *pSMB = NULL;
1084 CLOSE_RSP *pSMBr = NULL;
1085 int bytes_returned;
1086 cFYI(1, ("In CIFSSMBClose"));
1088 /* do not retry on dead session on close */
1089 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1090 if(rc == -EAGAIN)
1091 return 0;
1092 if (rc)
1093 return rc;
1095 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1097 pSMB->FileID = (__u16) smb_file_id;
1098 pSMB->LastWriteTime = 0;
1099 pSMB->ByteCount = 0;
1100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1102 if (rc) {
1103 if(rc!=-EINTR) {
1104 /* EINTR is expected when user ctl-c to kill app */
1105 cERROR(1, ("Send error in Close = %d", rc));
1109 cifs_small_buf_release(pSMB);
1111 /* Since session is dead, file will be closed on server already */
1112 if(rc == -EAGAIN)
1113 rc = 0;
1115 return rc;
1119 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1120 const char *fromName, const char *toName,
1121 const struct nls_table *nls_codepage, int remap)
1123 int rc = 0;
1124 RENAME_REQ *pSMB = NULL;
1125 RENAME_RSP *pSMBr = NULL;
1126 int bytes_returned;
1127 int name_len, name_len2;
1128 __u16 count;
1130 cFYI(1, ("In CIFSSMBRename"));
1131 renameRetry:
1132 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1133 (void **) &pSMBr);
1134 if (rc)
1135 return rc;
1137 pSMB->BufferFormat = 0x04;
1138 pSMB->SearchAttributes =
1139 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1140 ATTR_DIRECTORY);
1142 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1143 name_len =
1144 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1145 PATH_MAX, nls_codepage, remap);
1146 name_len++; /* trailing null */
1147 name_len *= 2;
1148 pSMB->OldFileName[name_len] = 0x04; /* pad */
1149 /* protocol requires ASCII signature byte on Unicode string */
1150 pSMB->OldFileName[name_len + 1] = 0x00;
1151 name_len2 =
1152 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1153 toName, PATH_MAX, nls_codepage, remap);
1154 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1155 name_len2 *= 2; /* convert to bytes */
1156 } else { /* BB improve the check for buffer overruns BB */
1157 name_len = strnlen(fromName, PATH_MAX);
1158 name_len++; /* trailing null */
1159 strncpy(pSMB->OldFileName, fromName, name_len);
1160 name_len2 = strnlen(toName, PATH_MAX);
1161 name_len2++; /* trailing null */
1162 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1163 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1164 name_len2++; /* trailing null */
1165 name_len2++; /* signature byte */
1168 count = 1 /* 1st signature byte */ + name_len + name_len2;
1169 pSMB->hdr.smb_buf_length += count;
1170 pSMB->ByteCount = cpu_to_le16(count);
1172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1174 if (rc) {
1175 cFYI(1, ("Send error in rename = %d", rc));
1178 #ifdef CONFIG_CIFS_STATS
1179 else {
1180 atomic_inc(&tcon->num_renames);
1182 #endif
1184 cifs_buf_release(pSMB);
1186 if (rc == -EAGAIN)
1187 goto renameRetry;
1189 return rc;
1192 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1193 int netfid, char * target_name,
1194 const struct nls_table * nls_codepage, int remap)
1196 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1197 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1198 struct set_file_rename * rename_info;
1199 char *data_offset;
1200 char dummy_string[30];
1201 int rc = 0;
1202 int bytes_returned = 0;
1203 int len_of_str;
1204 __u16 params, param_offset, offset, count, byte_count;
1206 cFYI(1, ("Rename to File by handle"));
1207 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1208 (void **) &pSMBr);
1209 if (rc)
1210 return rc;
1212 params = 6;
1213 pSMB->MaxSetupCount = 0;
1214 pSMB->Reserved = 0;
1215 pSMB->Flags = 0;
1216 pSMB->Timeout = 0;
1217 pSMB->Reserved2 = 0;
1218 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1219 offset = param_offset + params;
1221 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1222 rename_info = (struct set_file_rename *) data_offset;
1223 pSMB->MaxParameterCount = cpu_to_le16(2);
1224 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1225 pSMB->SetupCount = 1;
1226 pSMB->Reserved3 = 0;
1227 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1228 byte_count = 3 /* pad */ + params;
1229 pSMB->ParameterCount = cpu_to_le16(params);
1230 pSMB->TotalParameterCount = pSMB->ParameterCount;
1231 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1232 pSMB->DataOffset = cpu_to_le16(offset);
1233 /* construct random name ".cifs_tmp<inodenum><mid>" */
1234 rename_info->overwrite = cpu_to_le32(1);
1235 rename_info->root_fid = 0;
1236 /* unicode only call */
1237 if(target_name == NULL) {
1238 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1239 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1240 dummy_string, 24, nls_codepage, remap);
1241 } else {
1242 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1243 target_name, PATH_MAX, nls_codepage, remap);
1245 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1246 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1247 byte_count += count;
1248 pSMB->DataCount = cpu_to_le16(count);
1249 pSMB->TotalDataCount = pSMB->DataCount;
1250 pSMB->Fid = netfid;
1251 pSMB->InformationLevel =
1252 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1253 pSMB->Reserved4 = 0;
1254 pSMB->hdr.smb_buf_length += byte_count;
1255 pSMB->ByteCount = cpu_to_le16(byte_count);
1256 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1258 if (rc) {
1259 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1261 #ifdef CONFIG_CIFS_STATS
1262 else {
1263 atomic_inc(&pTcon->num_t2renames);
1265 #endif
1266 cifs_buf_release(pSMB);
1268 /* Note: On -EAGAIN error only caller can retry on handle based calls
1269 since file handle passed in no longer valid */
1271 return rc;
1275 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1276 const __u16 target_tid, const char *toName, const int flags,
1277 const struct nls_table *nls_codepage, int remap)
1279 int rc = 0;
1280 COPY_REQ *pSMB = NULL;
1281 COPY_RSP *pSMBr = NULL;
1282 int bytes_returned;
1283 int name_len, name_len2;
1284 __u16 count;
1286 cFYI(1, ("In CIFSSMBCopy"));
1287 copyRetry:
1288 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1289 (void **) &pSMBr);
1290 if (rc)
1291 return rc;
1293 pSMB->BufferFormat = 0x04;
1294 pSMB->Tid2 = target_tid;
1296 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1299 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1300 fromName, PATH_MAX, nls_codepage,
1301 remap);
1302 name_len++; /* trailing null */
1303 name_len *= 2;
1304 pSMB->OldFileName[name_len] = 0x04; /* pad */
1305 /* protocol requires ASCII signature byte on Unicode string */
1306 pSMB->OldFileName[name_len + 1] = 0x00;
1307 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1308 toName, PATH_MAX, nls_codepage, remap);
1309 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1310 name_len2 *= 2; /* convert to bytes */
1311 } else { /* BB improve the check for buffer overruns BB */
1312 name_len = strnlen(fromName, PATH_MAX);
1313 name_len++; /* trailing null */
1314 strncpy(pSMB->OldFileName, fromName, name_len);
1315 name_len2 = strnlen(toName, PATH_MAX);
1316 name_len2++; /* trailing null */
1317 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1318 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1319 name_len2++; /* trailing null */
1320 name_len2++; /* signature byte */
1323 count = 1 /* 1st signature byte */ + name_len + name_len2;
1324 pSMB->hdr.smb_buf_length += count;
1325 pSMB->ByteCount = cpu_to_le16(count);
1327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1329 if (rc) {
1330 cFYI(1, ("Send error in copy = %d with %d files copied",
1331 rc, le16_to_cpu(pSMBr->CopyCount)));
1333 if (pSMB)
1334 cifs_buf_release(pSMB);
1336 if (rc == -EAGAIN)
1337 goto copyRetry;
1339 return rc;
1343 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1344 const char *fromName, const char *toName,
1345 const struct nls_table *nls_codepage)
1347 TRANSACTION2_SPI_REQ *pSMB = NULL;
1348 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1349 char *data_offset;
1350 int name_len;
1351 int name_len_target;
1352 int rc = 0;
1353 int bytes_returned = 0;
1354 __u16 params, param_offset, offset, byte_count;
1356 cFYI(1, ("In Symlink Unix style"));
1357 createSymLinkRetry:
1358 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1359 (void **) &pSMBr);
1360 if (rc)
1361 return rc;
1363 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1364 name_len =
1365 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1366 /* find define for this maxpathcomponent */
1367 , nls_codepage);
1368 name_len++; /* trailing null */
1369 name_len *= 2;
1371 } else { /* BB improve the check for buffer overruns BB */
1372 name_len = strnlen(fromName, PATH_MAX);
1373 name_len++; /* trailing null */
1374 strncpy(pSMB->FileName, fromName, name_len);
1376 params = 6 + name_len;
1377 pSMB->MaxSetupCount = 0;
1378 pSMB->Reserved = 0;
1379 pSMB->Flags = 0;
1380 pSMB->Timeout = 0;
1381 pSMB->Reserved2 = 0;
1382 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1383 InformationLevel) - 4;
1384 offset = param_offset + params;
1386 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1387 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1388 name_len_target =
1389 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1390 /* find define for this maxpathcomponent */
1391 , nls_codepage);
1392 name_len_target++; /* trailing null */
1393 name_len_target *= 2;
1394 } else { /* BB improve the check for buffer overruns BB */
1395 name_len_target = strnlen(toName, PATH_MAX);
1396 name_len_target++; /* trailing null */
1397 strncpy(data_offset, toName, name_len_target);
1400 pSMB->MaxParameterCount = cpu_to_le16(2);
1401 /* BB find exact max on data count below from sess */
1402 pSMB->MaxDataCount = cpu_to_le16(1000);
1403 pSMB->SetupCount = 1;
1404 pSMB->Reserved3 = 0;
1405 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1406 byte_count = 3 /* pad */ + params + name_len_target;
1407 pSMB->DataCount = cpu_to_le16(name_len_target);
1408 pSMB->ParameterCount = cpu_to_le16(params);
1409 pSMB->TotalDataCount = pSMB->DataCount;
1410 pSMB->TotalParameterCount = pSMB->ParameterCount;
1411 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1412 pSMB->DataOffset = cpu_to_le16(offset);
1413 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1414 pSMB->Reserved4 = 0;
1415 pSMB->hdr.smb_buf_length += byte_count;
1416 pSMB->ByteCount = cpu_to_le16(byte_count);
1417 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1418 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1419 if (rc) {
1420 cFYI(1,
1421 ("Send error in SetPathInfo (create symlink) = %d",
1422 rc));
1425 if (pSMB)
1426 cifs_buf_release(pSMB);
1428 if (rc == -EAGAIN)
1429 goto createSymLinkRetry;
1431 return rc;
1435 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1436 const char *fromName, const char *toName,
1437 const struct nls_table *nls_codepage, int remap)
1439 TRANSACTION2_SPI_REQ *pSMB = NULL;
1440 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1441 char *data_offset;
1442 int name_len;
1443 int name_len_target;
1444 int rc = 0;
1445 int bytes_returned = 0;
1446 __u16 params, param_offset, offset, byte_count;
1448 cFYI(1, ("In Create Hard link Unix style"));
1449 createHardLinkRetry:
1450 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1451 (void **) &pSMBr);
1452 if (rc)
1453 return rc;
1455 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1456 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1457 PATH_MAX, nls_codepage, remap);
1458 name_len++; /* trailing null */
1459 name_len *= 2;
1461 } else { /* BB improve the check for buffer overruns BB */
1462 name_len = strnlen(toName, PATH_MAX);
1463 name_len++; /* trailing null */
1464 strncpy(pSMB->FileName, toName, name_len);
1466 params = 6 + name_len;
1467 pSMB->MaxSetupCount = 0;
1468 pSMB->Reserved = 0;
1469 pSMB->Flags = 0;
1470 pSMB->Timeout = 0;
1471 pSMB->Reserved2 = 0;
1472 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1473 InformationLevel) - 4;
1474 offset = param_offset + params;
1476 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1477 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1478 name_len_target =
1479 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1480 nls_codepage, remap);
1481 name_len_target++; /* trailing null */
1482 name_len_target *= 2;
1483 } else { /* BB improve the check for buffer overruns BB */
1484 name_len_target = strnlen(fromName, PATH_MAX);
1485 name_len_target++; /* trailing null */
1486 strncpy(data_offset, fromName, name_len_target);
1489 pSMB->MaxParameterCount = cpu_to_le16(2);
1490 /* BB find exact max on data count below from sess*/
1491 pSMB->MaxDataCount = cpu_to_le16(1000);
1492 pSMB->SetupCount = 1;
1493 pSMB->Reserved3 = 0;
1494 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1495 byte_count = 3 /* pad */ + params + name_len_target;
1496 pSMB->ParameterCount = cpu_to_le16(params);
1497 pSMB->TotalParameterCount = pSMB->ParameterCount;
1498 pSMB->DataCount = cpu_to_le16(name_len_target);
1499 pSMB->TotalDataCount = pSMB->DataCount;
1500 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1501 pSMB->DataOffset = cpu_to_le16(offset);
1502 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1503 pSMB->Reserved4 = 0;
1504 pSMB->hdr.smb_buf_length += byte_count;
1505 pSMB->ByteCount = cpu_to_le16(byte_count);
1506 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1507 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1508 if (rc) {
1509 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1512 cifs_buf_release(pSMB);
1513 if (rc == -EAGAIN)
1514 goto createHardLinkRetry;
1516 return rc;
1520 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1521 const char *fromName, const char *toName,
1522 const struct nls_table *nls_codepage, int remap)
1524 int rc = 0;
1525 NT_RENAME_REQ *pSMB = NULL;
1526 RENAME_RSP *pSMBr = NULL;
1527 int bytes_returned;
1528 int name_len, name_len2;
1529 __u16 count;
1531 cFYI(1, ("In CIFSCreateHardLink"));
1532 winCreateHardLinkRetry:
1534 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1535 (void **) &pSMBr);
1536 if (rc)
1537 return rc;
1539 pSMB->SearchAttributes =
1540 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1541 ATTR_DIRECTORY);
1542 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1543 pSMB->ClusterCount = 0;
1545 pSMB->BufferFormat = 0x04;
1547 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1548 name_len =
1549 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1550 PATH_MAX, nls_codepage, remap);
1551 name_len++; /* trailing null */
1552 name_len *= 2;
1553 pSMB->OldFileName[name_len] = 0; /* pad */
1554 pSMB->OldFileName[name_len + 1] = 0x04;
1555 name_len2 =
1556 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1557 toName, PATH_MAX, nls_codepage, remap);
1558 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1559 name_len2 *= 2; /* convert to bytes */
1560 } else { /* BB improve the check for buffer overruns BB */
1561 name_len = strnlen(fromName, PATH_MAX);
1562 name_len++; /* trailing null */
1563 strncpy(pSMB->OldFileName, fromName, name_len);
1564 name_len2 = strnlen(toName, PATH_MAX);
1565 name_len2++; /* trailing null */
1566 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1567 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1568 name_len2++; /* trailing null */
1569 name_len2++; /* signature byte */
1572 count = 1 /* string type byte */ + name_len + name_len2;
1573 pSMB->hdr.smb_buf_length += count;
1574 pSMB->ByteCount = cpu_to_le16(count);
1576 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1577 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1578 if (rc) {
1579 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1581 cifs_buf_release(pSMB);
1582 if (rc == -EAGAIN)
1583 goto winCreateHardLinkRetry;
1585 return rc;
1589 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1590 const unsigned char *searchName,
1591 char *symlinkinfo, const int buflen,
1592 const struct nls_table *nls_codepage)
1594 /* SMB_QUERY_FILE_UNIX_LINK */
1595 TRANSACTION2_QPI_REQ *pSMB = NULL;
1596 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1597 int rc = 0;
1598 int bytes_returned;
1599 int name_len;
1600 __u16 params, byte_count;
1602 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1604 querySymLinkRetry:
1605 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1606 (void **) &pSMBr);
1607 if (rc)
1608 return rc;
1610 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1611 name_len =
1612 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1613 /* find define for this maxpathcomponent */
1614 , nls_codepage);
1615 name_len++; /* trailing null */
1616 name_len *= 2;
1617 } else { /* BB improve the check for buffer overruns BB */
1618 name_len = strnlen(searchName, PATH_MAX);
1619 name_len++; /* trailing null */
1620 strncpy(pSMB->FileName, searchName, name_len);
1623 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1624 pSMB->TotalDataCount = 0;
1625 pSMB->MaxParameterCount = cpu_to_le16(2);
1626 /* BB find exact max data count below from sess structure BB */
1627 pSMB->MaxDataCount = cpu_to_le16(4000);
1628 pSMB->MaxSetupCount = 0;
1629 pSMB->Reserved = 0;
1630 pSMB->Flags = 0;
1631 pSMB->Timeout = 0;
1632 pSMB->Reserved2 = 0;
1633 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1634 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1635 pSMB->DataCount = 0;
1636 pSMB->DataOffset = 0;
1637 pSMB->SetupCount = 1;
1638 pSMB->Reserved3 = 0;
1639 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1640 byte_count = params + 1 /* pad */ ;
1641 pSMB->TotalParameterCount = cpu_to_le16(params);
1642 pSMB->ParameterCount = pSMB->TotalParameterCount;
1643 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1644 pSMB->Reserved4 = 0;
1645 pSMB->hdr.smb_buf_length += byte_count;
1646 pSMB->ByteCount = cpu_to_le16(byte_count);
1648 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1649 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1650 if (rc) {
1651 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1652 } else {
1653 /* decode response */
1655 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1656 if (rc || (pSMBr->ByteCount < 2))
1657 /* BB also check enough total bytes returned */
1658 rc = -EIO; /* bad smb */
1659 else {
1660 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1661 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1663 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1664 name_len = UniStrnlen((wchar_t *) ((char *)
1665 &pSMBr->hdr.Protocol +data_offset),
1666 min_t(const int, buflen,count) / 2);
1667 /* BB FIXME investigate remapping reserved chars here */
1668 cifs_strfromUCS_le(symlinkinfo,
1669 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1670 data_offset),
1671 name_len, nls_codepage);
1672 } else {
1673 strncpy(symlinkinfo,
1674 (char *) &pSMBr->hdr.Protocol +
1675 data_offset,
1676 min_t(const int, buflen, count));
1678 symlinkinfo[buflen] = 0;
1679 /* just in case so calling code does not go off the end of buffer */
1682 cifs_buf_release(pSMB);
1683 if (rc == -EAGAIN)
1684 goto querySymLinkRetry;
1685 return rc;
1689 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1690 const unsigned char *searchName,
1691 char *symlinkinfo, const int buflen,__u16 fid,
1692 const struct nls_table *nls_codepage)
1694 int rc = 0;
1695 int bytes_returned;
1696 int name_len;
1697 struct smb_com_transaction_ioctl_req * pSMB;
1698 struct smb_com_transaction_ioctl_rsp * pSMBr;
1700 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1701 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1702 (void **) &pSMBr);
1703 if (rc)
1704 return rc;
1706 pSMB->TotalParameterCount = 0 ;
1707 pSMB->TotalDataCount = 0;
1708 pSMB->MaxParameterCount = cpu_to_le32(2);
1709 /* BB find exact data count max from sess structure BB */
1710 pSMB->MaxDataCount = cpu_to_le32(4000);
1711 pSMB->MaxSetupCount = 4;
1712 pSMB->Reserved = 0;
1713 pSMB->ParameterOffset = 0;
1714 pSMB->DataCount = 0;
1715 pSMB->DataOffset = 0;
1716 pSMB->SetupCount = 4;
1717 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1718 pSMB->ParameterCount = pSMB->TotalParameterCount;
1719 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1720 pSMB->IsFsctl = 1; /* FSCTL */
1721 pSMB->IsRootFlag = 0;
1722 pSMB->Fid = fid; /* file handle always le */
1723 pSMB->ByteCount = 0;
1725 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1726 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1727 if (rc) {
1728 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1729 } else { /* decode response */
1730 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1731 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1732 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1733 /* BB also check enough total bytes returned */
1734 rc = -EIO; /* bad smb */
1735 else {
1736 if(data_count && (data_count < 2048)) {
1737 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1739 struct reparse_data * reparse_buf = (struct reparse_data *)
1740 ((char *)&pSMBr->hdr.Protocol + data_offset);
1741 if((char*)reparse_buf >= end_of_smb) {
1742 rc = -EIO;
1743 goto qreparse_out;
1745 if((reparse_buf->LinkNamesBuf +
1746 reparse_buf->TargetNameOffset +
1747 reparse_buf->TargetNameLen) >
1748 end_of_smb) {
1749 cFYI(1,("reparse buf extended beyond SMB"));
1750 rc = -EIO;
1751 goto qreparse_out;
1754 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1755 name_len = UniStrnlen((wchar_t *)
1756 (reparse_buf->LinkNamesBuf +
1757 reparse_buf->TargetNameOffset),
1758 min(buflen/2, reparse_buf->TargetNameLen / 2));
1759 cifs_strfromUCS_le(symlinkinfo,
1760 (wchar_t *) (reparse_buf->LinkNamesBuf +
1761 reparse_buf->TargetNameOffset),
1762 name_len, nls_codepage);
1763 } else { /* ASCII names */
1764 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1765 reparse_buf->TargetNameOffset,
1766 min_t(const int, buflen, reparse_buf->TargetNameLen));
1768 } else {
1769 rc = -EIO;
1770 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1772 symlinkinfo[buflen] = 0; /* just in case so the caller
1773 does not go off the end of the buffer */
1774 cFYI(1,("readlink result - %s ",symlinkinfo));
1777 qreparse_out:
1778 if (pSMB)
1779 cifs_buf_release(pSMB);
1781 /* Note: On -EAGAIN error only caller can retry on handle based calls
1782 since file handle passed in no longer valid */
1784 return rc;
1787 #ifdef CONFIG_CIFS_POSIX
1789 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1790 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1792 /* u8 cifs fields do not need le conversion */
1793 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1794 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1795 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1796 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1798 return;
1801 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
1802 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1803 const int acl_type,const int size_of_data_area)
1805 int size = 0;
1806 int i;
1807 __u16 count;
1808 struct cifs_posix_ace * pACE;
1809 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1810 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1812 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1813 return -EOPNOTSUPP;
1815 if(acl_type & ACL_TYPE_ACCESS) {
1816 count = le16_to_cpu(cifs_acl->access_entry_count);
1817 pACE = &cifs_acl->ace_array[0];
1818 size = sizeof(struct cifs_posix_acl);
1819 size += sizeof(struct cifs_posix_ace) * count;
1820 /* check if we would go beyond end of SMB */
1821 if(size_of_data_area < size) {
1822 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1823 return -EINVAL;
1825 } else if(acl_type & ACL_TYPE_DEFAULT) {
1826 count = le16_to_cpu(cifs_acl->access_entry_count);
1827 size = sizeof(struct cifs_posix_acl);
1828 size += sizeof(struct cifs_posix_ace) * count;
1829 /* skip past access ACEs to get to default ACEs */
1830 pACE = &cifs_acl->ace_array[count];
1831 count = le16_to_cpu(cifs_acl->default_entry_count);
1832 size += sizeof(struct cifs_posix_ace) * count;
1833 /* check if we would go beyond end of SMB */
1834 if(size_of_data_area < size)
1835 return -EINVAL;
1836 } else {
1837 /* illegal type */
1838 return -EINVAL;
1841 size = posix_acl_xattr_size(count);
1842 if((buflen == 0) || (local_acl == NULL)) {
1843 /* used to query ACL EA size */
1844 } else if(size > buflen) {
1845 return -ERANGE;
1846 } else /* buffer big enough */ {
1847 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1848 for(i = 0;i < count ;i++) {
1849 cifs_convert_ace(&local_acl->a_entries[i],pACE);
1850 pACE ++;
1853 return size;
1856 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1857 const posix_acl_xattr_entry * local_ace)
1859 __u16 rc = 0; /* 0 = ACL converted ok */
1861 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1862 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
1863 /* BB is there a better way to handle the large uid? */
1864 if(local_ace->e_id == -1) {
1865 /* Probably no need to le convert -1 on any arch but can not hurt */
1866 cifs_ace->cifs_uid = cpu_to_le64(-1);
1867 } else
1868 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1869 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1870 return rc;
1873 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1874 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1875 const int acl_type)
1877 __u16 rc = 0;
1878 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1879 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1880 int count;
1881 int i;
1883 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1884 return 0;
1886 count = posix_acl_xattr_count((size_t)buflen);
1887 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1888 count,buflen,local_acl->a_version));
1889 if(local_acl->a_version != 2) {
1890 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1891 return 0;
1893 cifs_acl->version = cpu_to_le16(1);
1894 if(acl_type == ACL_TYPE_ACCESS)
1895 cifs_acl->access_entry_count = count;
1896 else if(acl_type == ACL_TYPE_DEFAULT)
1897 cifs_acl->default_entry_count = count;
1898 else {
1899 cFYI(1,("unknown ACL type %d",acl_type));
1900 return 0;
1902 for(i=0;i<count;i++) {
1903 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1904 &local_acl->a_entries[i]);
1905 if(rc != 0) {
1906 /* ACE not converted */
1907 break;
1910 if(rc == 0) {
1911 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1912 rc += sizeof(struct cifs_posix_acl);
1913 /* BB add check to make sure ACL does not overflow SMB */
1915 return rc;
1919 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1920 const unsigned char *searchName,
1921 char *acl_inf, const int buflen, const int acl_type,
1922 const struct nls_table *nls_codepage, int remap)
1924 /* SMB_QUERY_POSIX_ACL */
1925 TRANSACTION2_QPI_REQ *pSMB = NULL;
1926 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1927 int rc = 0;
1928 int bytes_returned;
1929 int name_len;
1930 __u16 params, byte_count;
1932 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1934 queryAclRetry:
1935 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1936 (void **) &pSMBr);
1937 if (rc)
1938 return rc;
1940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1941 name_len =
1942 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
1943 PATH_MAX, nls_codepage, remap);
1944 name_len++; /* trailing null */
1945 name_len *= 2;
1946 pSMB->FileName[name_len] = 0;
1947 pSMB->FileName[name_len+1] = 0;
1948 } else { /* BB improve the check for buffer overruns BB */
1949 name_len = strnlen(searchName, PATH_MAX);
1950 name_len++; /* trailing null */
1951 strncpy(pSMB->FileName, searchName, name_len);
1954 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1955 pSMB->TotalDataCount = 0;
1956 pSMB->MaxParameterCount = cpu_to_le16(2);
1957 /* BB find exact max data count below from sess structure BB */
1958 pSMB->MaxDataCount = cpu_to_le16(4000);
1959 pSMB->MaxSetupCount = 0;
1960 pSMB->Reserved = 0;
1961 pSMB->Flags = 0;
1962 pSMB->Timeout = 0;
1963 pSMB->Reserved2 = 0;
1964 pSMB->ParameterOffset = cpu_to_le16(
1965 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1966 pSMB->DataCount = 0;
1967 pSMB->DataOffset = 0;
1968 pSMB->SetupCount = 1;
1969 pSMB->Reserved3 = 0;
1970 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1971 byte_count = params + 1 /* pad */ ;
1972 pSMB->TotalParameterCount = cpu_to_le16(params);
1973 pSMB->ParameterCount = pSMB->TotalParameterCount;
1974 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1975 pSMB->Reserved4 = 0;
1976 pSMB->hdr.smb_buf_length += byte_count;
1977 pSMB->ByteCount = cpu_to_le16(byte_count);
1979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1981 if (rc) {
1982 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
1983 } else {
1984 /* decode response */
1986 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1987 if (rc || (pSMBr->ByteCount < 2))
1988 /* BB also check enough total bytes returned */
1989 rc = -EIO; /* bad smb */
1990 else {
1991 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1992 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1993 rc = cifs_copy_posix_acl(acl_inf,
1994 (char *)&pSMBr->hdr.Protocol+data_offset,
1995 buflen,acl_type,count);
1998 cifs_buf_release(pSMB);
1999 if (rc == -EAGAIN)
2000 goto queryAclRetry;
2001 return rc;
2005 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2006 const unsigned char *fileName,
2007 const char *local_acl, const int buflen,
2008 const int acl_type,
2009 const struct nls_table *nls_codepage, int remap)
2011 struct smb_com_transaction2_spi_req *pSMB = NULL;
2012 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2013 char *parm_data;
2014 int name_len;
2015 int rc = 0;
2016 int bytes_returned = 0;
2017 __u16 params, byte_count, data_count, param_offset, offset;
2019 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2020 setAclRetry:
2021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2022 (void **) &pSMBr);
2023 if (rc)
2024 return rc;
2025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2026 name_len =
2027 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2028 PATH_MAX, nls_codepage, remap);
2029 name_len++; /* trailing null */
2030 name_len *= 2;
2031 } else { /* BB improve the check for buffer overruns BB */
2032 name_len = strnlen(fileName, PATH_MAX);
2033 name_len++; /* trailing null */
2034 strncpy(pSMB->FileName, fileName, name_len);
2036 params = 6 + name_len;
2037 pSMB->MaxParameterCount = cpu_to_le16(2);
2038 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2039 pSMB->MaxSetupCount = 0;
2040 pSMB->Reserved = 0;
2041 pSMB->Flags = 0;
2042 pSMB->Timeout = 0;
2043 pSMB->Reserved2 = 0;
2044 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2045 InformationLevel) - 4;
2046 offset = param_offset + params;
2047 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2048 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2050 /* convert to on the wire format for POSIX ACL */
2051 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2053 if(data_count == 0) {
2054 rc = -EOPNOTSUPP;
2055 goto setACLerrorExit;
2057 pSMB->DataOffset = cpu_to_le16(offset);
2058 pSMB->SetupCount = 1;
2059 pSMB->Reserved3 = 0;
2060 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2061 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2062 byte_count = 3 /* pad */ + params + data_count;
2063 pSMB->DataCount = cpu_to_le16(data_count);
2064 pSMB->TotalDataCount = pSMB->DataCount;
2065 pSMB->ParameterCount = cpu_to_le16(params);
2066 pSMB->TotalParameterCount = pSMB->ParameterCount;
2067 pSMB->Reserved4 = 0;
2068 pSMB->hdr.smb_buf_length += byte_count;
2069 pSMB->ByteCount = cpu_to_le16(byte_count);
2070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2072 if (rc) {
2073 cFYI(1, ("Set POSIX ACL returned %d", rc));
2076 setACLerrorExit:
2077 cifs_buf_release(pSMB);
2078 if (rc == -EAGAIN)
2079 goto setAclRetry;
2080 return rc;
2083 /* BB fix tabs in this function FIXME BB */
2085 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2086 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2088 int rc = 0;
2089 struct smb_t2_qfi_req *pSMB = NULL;
2090 struct smb_t2_qfi_rsp *pSMBr = NULL;
2091 int bytes_returned;
2092 __u16 params, byte_count;
2094 cFYI(1,("In GetExtAttr"));
2095 if(tcon == NULL)
2096 return -ENODEV;
2098 GetExtAttrRetry:
2099 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2100 (void **) &pSMBr);
2101 if (rc)
2102 return rc;
2104 params = 2 /* level */ +2 /* fid */;
2105 pSMB->t2.TotalDataCount = 0;
2106 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2107 /* BB find exact max data count below from sess structure BB */
2108 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2109 pSMB->t2.MaxSetupCount = 0;
2110 pSMB->t2.Reserved = 0;
2111 pSMB->t2.Flags = 0;
2112 pSMB->t2.Timeout = 0;
2113 pSMB->t2.Reserved2 = 0;
2114 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2115 Fid) - 4);
2116 pSMB->t2.DataCount = 0;
2117 pSMB->t2.DataOffset = 0;
2118 pSMB->t2.SetupCount = 1;
2119 pSMB->t2.Reserved3 = 0;
2120 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2121 byte_count = params + 1 /* pad */ ;
2122 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2123 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2124 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2125 pSMB->Pad = 0;
2126 pSMB->Fid = netfid;
2127 pSMB->hdr.smb_buf_length += byte_count;
2128 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2131 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2132 if (rc) {
2133 cFYI(1, ("error %d in GetExtAttr", rc));
2134 } else {
2135 /* decode response */
2136 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2137 if (rc || (pSMBr->ByteCount < 2))
2138 /* BB also check enough total bytes returned */
2139 /* If rc should we check for EOPNOSUPP and
2140 disable the srvino flag? or in caller? */
2141 rc = -EIO; /* bad smb */
2142 else {
2143 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2144 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2145 struct file_chattr_info * pfinfo;
2146 /* BB Do we need a cast or hash here ? */
2147 if(count != 16) {
2148 cFYI(1, ("Illegal size ret in GetExtAttr"));
2149 rc = -EIO;
2150 goto GetExtAttrOut;
2152 pfinfo = (struct file_chattr_info *)
2153 (data_offset + (char *) &pSMBr->hdr.Protocol);
2154 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2155 *pMask = le64_to_cpu(pfinfo->mask);
2158 GetExtAttrOut:
2159 cifs_buf_release(pSMB);
2160 if (rc == -EAGAIN)
2161 goto GetExtAttrRetry;
2162 return rc;
2166 #endif /* CONFIG_POSIX */
2169 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2170 const unsigned char *searchName,
2171 FILE_ALL_INFO * pFindData,
2172 const struct nls_table *nls_codepage, int remap)
2174 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2175 TRANSACTION2_QPI_REQ *pSMB = NULL;
2176 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2177 int rc = 0;
2178 int bytes_returned;
2179 int name_len;
2180 __u16 params, byte_count;
2182 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2183 QPathInfoRetry:
2184 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2185 (void **) &pSMBr);
2186 if (rc)
2187 return rc;
2189 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2190 name_len =
2191 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2192 PATH_MAX, nls_codepage, remap);
2193 name_len++; /* trailing null */
2194 name_len *= 2;
2195 } else { /* BB improve the check for buffer overruns BB */
2196 name_len = strnlen(searchName, PATH_MAX);
2197 name_len++; /* trailing null */
2198 strncpy(pSMB->FileName, searchName, name_len);
2201 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2202 pSMB->TotalDataCount = 0;
2203 pSMB->MaxParameterCount = cpu_to_le16(2);
2204 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2205 pSMB->MaxSetupCount = 0;
2206 pSMB->Reserved = 0;
2207 pSMB->Flags = 0;
2208 pSMB->Timeout = 0;
2209 pSMB->Reserved2 = 0;
2210 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2211 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2212 pSMB->DataCount = 0;
2213 pSMB->DataOffset = 0;
2214 pSMB->SetupCount = 1;
2215 pSMB->Reserved3 = 0;
2216 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2217 byte_count = params + 1 /* pad */ ;
2218 pSMB->TotalParameterCount = cpu_to_le16(params);
2219 pSMB->ParameterCount = pSMB->TotalParameterCount;
2220 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2221 pSMB->Reserved4 = 0;
2222 pSMB->hdr.smb_buf_length += byte_count;
2223 pSMB->ByteCount = cpu_to_le16(byte_count);
2225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2227 if (rc) {
2228 cFYI(1, ("Send error in QPathInfo = %d", rc));
2229 } else { /* decode response */
2230 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2232 if (rc || (pSMBr->ByteCount < 40))
2233 rc = -EIO; /* bad smb */
2234 else if (pFindData){
2235 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2236 memcpy((char *) pFindData,
2237 (char *) &pSMBr->hdr.Protocol +
2238 data_offset, sizeof (FILE_ALL_INFO));
2239 } else
2240 rc = -ENOMEM;
2242 cifs_buf_release(pSMB);
2243 if (rc == -EAGAIN)
2244 goto QPathInfoRetry;
2246 return rc;
2250 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2251 const unsigned char *searchName,
2252 FILE_UNIX_BASIC_INFO * pFindData,
2253 const struct nls_table *nls_codepage, int remap)
2255 /* SMB_QUERY_FILE_UNIX_BASIC */
2256 TRANSACTION2_QPI_REQ *pSMB = NULL;
2257 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2258 int rc = 0;
2259 int bytes_returned = 0;
2260 int name_len;
2261 __u16 params, byte_count;
2263 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2264 UnixQPathInfoRetry:
2265 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2266 (void **) &pSMBr);
2267 if (rc)
2268 return rc;
2270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271 name_len =
2272 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2273 PATH_MAX, nls_codepage, remap);
2274 name_len++; /* trailing null */
2275 name_len *= 2;
2276 } else { /* BB improve the check for buffer overruns BB */
2277 name_len = strnlen(searchName, PATH_MAX);
2278 name_len++; /* trailing null */
2279 strncpy(pSMB->FileName, searchName, name_len);
2282 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2283 pSMB->TotalDataCount = 0;
2284 pSMB->MaxParameterCount = cpu_to_le16(2);
2285 /* BB find exact max SMB PDU from sess structure BB */
2286 pSMB->MaxDataCount = cpu_to_le16(4000);
2287 pSMB->MaxSetupCount = 0;
2288 pSMB->Reserved = 0;
2289 pSMB->Flags = 0;
2290 pSMB->Timeout = 0;
2291 pSMB->Reserved2 = 0;
2292 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2293 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2294 pSMB->DataCount = 0;
2295 pSMB->DataOffset = 0;
2296 pSMB->SetupCount = 1;
2297 pSMB->Reserved3 = 0;
2298 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2299 byte_count = params + 1 /* pad */ ;
2300 pSMB->TotalParameterCount = cpu_to_le16(params);
2301 pSMB->ParameterCount = pSMB->TotalParameterCount;
2302 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2303 pSMB->Reserved4 = 0;
2304 pSMB->hdr.smb_buf_length += byte_count;
2305 pSMB->ByteCount = cpu_to_le16(byte_count);
2307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2309 if (rc) {
2310 cFYI(1, ("Send error in QPathInfo = %d", rc));
2311 } else { /* decode response */
2312 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2314 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2315 rc = -EIO; /* bad smb */
2316 } else {
2317 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2318 memcpy((char *) pFindData,
2319 (char *) &pSMBr->hdr.Protocol +
2320 data_offset,
2321 sizeof (FILE_UNIX_BASIC_INFO));
2324 cifs_buf_release(pSMB);
2325 if (rc == -EAGAIN)
2326 goto UnixQPathInfoRetry;
2328 return rc;
2331 #if 0 /* function unused at present */
2332 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2333 const char *searchName, FILE_ALL_INFO * findData,
2334 const struct nls_table *nls_codepage)
2336 /* level 257 SMB_ */
2337 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2338 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2339 int rc = 0;
2340 int bytes_returned;
2341 int name_len;
2342 __u16 params, byte_count;
2344 cFYI(1, ("In FindUnique"));
2345 findUniqueRetry:
2346 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2347 (void **) &pSMBr);
2348 if (rc)
2349 return rc;
2351 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2352 name_len =
2353 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2354 /* find define for this maxpathcomponent */
2355 , nls_codepage);
2356 name_len++; /* trailing null */
2357 name_len *= 2;
2358 } else { /* BB improve the check for buffer overruns BB */
2359 name_len = strnlen(searchName, PATH_MAX);
2360 name_len++; /* trailing null */
2361 strncpy(pSMB->FileName, searchName, name_len);
2364 params = 12 + name_len /* includes null */ ;
2365 pSMB->TotalDataCount = 0; /* no EAs */
2366 pSMB->MaxParameterCount = cpu_to_le16(2);
2367 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2368 pSMB->MaxSetupCount = 0;
2369 pSMB->Reserved = 0;
2370 pSMB->Flags = 0;
2371 pSMB->Timeout = 0;
2372 pSMB->Reserved2 = 0;
2373 pSMB->ParameterOffset = cpu_to_le16(
2374 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2375 pSMB->DataCount = 0;
2376 pSMB->DataOffset = 0;
2377 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2378 pSMB->Reserved3 = 0;
2379 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2380 byte_count = params + 1 /* pad */ ;
2381 pSMB->TotalParameterCount = cpu_to_le16(params);
2382 pSMB->ParameterCount = pSMB->TotalParameterCount;
2383 pSMB->SearchAttributes =
2384 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2385 ATTR_DIRECTORY);
2386 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2387 pSMB->SearchFlags = cpu_to_le16(1);
2388 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2389 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2390 pSMB->hdr.smb_buf_length += byte_count;
2391 pSMB->ByteCount = cpu_to_le16(byte_count);
2393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2396 if (rc) {
2397 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2398 } else { /* decode response */
2400 /* BB fill in */
2403 cifs_buf_release(pSMB);
2404 if (rc == -EAGAIN)
2405 goto findUniqueRetry;
2407 return rc;
2409 #endif /* end unused (temporarily) function */
2411 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2413 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2414 const char *searchName,
2415 const struct nls_table *nls_codepage,
2416 __u16 * pnetfid,
2417 struct cifs_search_info * psrch_inf, int remap)
2419 /* level 257 SMB_ */
2420 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2421 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2422 T2_FFIRST_RSP_PARMS * parms;
2423 int rc = 0;
2424 int bytes_returned = 0;
2425 int name_len;
2426 __u16 params, byte_count;
2428 cFYI(1, ("In FindFirst for %s",searchName));
2430 findFirstRetry:
2431 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2432 (void **) &pSMBr);
2433 if (rc)
2434 return rc;
2436 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2437 name_len =
2438 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2439 PATH_MAX, nls_codepage, remap);
2440 /* We can not add the asterik earlier in case
2441 it got remapped to 0xF03A as if it were part of the
2442 directory name instead of a wildcard */
2443 name_len *= 2;
2444 pSMB->FileName[name_len] = '\\';
2445 pSMB->FileName[name_len+1] = 0;
2446 pSMB->FileName[name_len+2] = '*';
2447 pSMB->FileName[name_len+3] = 0;
2448 name_len += 4; /* now the trailing null */
2449 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2450 pSMB->FileName[name_len+1] = 0;
2451 name_len += 2;
2452 } else { /* BB add check for overrun of SMB buf BB */
2453 name_len = strnlen(searchName, PATH_MAX);
2454 /* BB fix here and in unicode clause above ie
2455 if(name_len > buffersize-header)
2456 free buffer exit; BB */
2457 strncpy(pSMB->FileName, searchName, name_len);
2458 pSMB->FileName[name_len] = '\\';
2459 pSMB->FileName[name_len+1] = '*';
2460 pSMB->FileName[name_len+2] = 0;
2461 name_len += 3;
2464 params = 12 + name_len /* includes null */ ;
2465 pSMB->TotalDataCount = 0; /* no EAs */
2466 pSMB->MaxParameterCount = cpu_to_le16(10);
2467 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2468 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2469 pSMB->MaxSetupCount = 0;
2470 pSMB->Reserved = 0;
2471 pSMB->Flags = 0;
2472 pSMB->Timeout = 0;
2473 pSMB->Reserved2 = 0;
2474 byte_count = params + 1 /* pad */ ;
2475 pSMB->TotalParameterCount = cpu_to_le16(params);
2476 pSMB->ParameterCount = pSMB->TotalParameterCount;
2477 pSMB->ParameterOffset = cpu_to_le16(
2478 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2479 pSMB->DataCount = 0;
2480 pSMB->DataOffset = 0;
2481 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2482 pSMB->Reserved3 = 0;
2483 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2484 pSMB->SearchAttributes =
2485 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2486 ATTR_DIRECTORY);
2487 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2488 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2489 CIFS_SEARCH_RETURN_RESUME);
2490 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2492 /* BB what should we set StorageType to? Does it matter? BB */
2493 pSMB->SearchStorageType = 0;
2494 pSMB->hdr.smb_buf_length += byte_count;
2495 pSMB->ByteCount = cpu_to_le16(byte_count);
2497 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2500 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2501 /* BB Add code to handle unsupported level rc */
2502 cFYI(1, ("Error in FindFirst = %d", rc));
2504 if (pSMB)
2505 cifs_buf_release(pSMB);
2507 /* BB eventually could optimize out free and realloc of buf */
2508 /* for this case */
2509 if (rc == -EAGAIN)
2510 goto findFirstRetry;
2511 } else { /* decode response */
2512 /* BB remember to free buffer if error BB */
2513 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2514 if(rc == 0) {
2515 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2516 psrch_inf->unicode = TRUE;
2517 else
2518 psrch_inf->unicode = FALSE;
2520 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2521 psrch_inf->srch_entries_start =
2522 (char *) &pSMBr->hdr.Protocol +
2523 le16_to_cpu(pSMBr->t2.DataOffset);
2524 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2525 le16_to_cpu(pSMBr->t2.ParameterOffset));
2527 if(parms->EndofSearch)
2528 psrch_inf->endOfSearch = TRUE;
2529 else
2530 psrch_inf->endOfSearch = FALSE;
2532 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2533 psrch_inf->index_of_last_entry =
2534 psrch_inf->entries_in_buffer;
2535 *pnetfid = parms->SearchHandle;
2536 } else {
2537 cifs_buf_release(pSMB);
2541 return rc;
2544 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2545 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2547 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2548 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2549 T2_FNEXT_RSP_PARMS * parms;
2550 char *response_data;
2551 int rc = 0;
2552 int bytes_returned, name_len;
2553 __u16 params, byte_count;
2555 cFYI(1, ("In FindNext"));
2557 if(psrch_inf->endOfSearch == TRUE)
2558 return -ENOENT;
2560 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2561 (void **) &pSMBr);
2562 if (rc)
2563 return rc;
2565 params = 14; /* includes 2 bytes of null string, converted to LE below */
2566 byte_count = 0;
2567 pSMB->TotalDataCount = 0; /* no EAs */
2568 pSMB->MaxParameterCount = cpu_to_le16(8);
2569 pSMB->MaxDataCount =
2570 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2571 pSMB->MaxSetupCount = 0;
2572 pSMB->Reserved = 0;
2573 pSMB->Flags = 0;
2574 pSMB->Timeout = 0;
2575 pSMB->Reserved2 = 0;
2576 pSMB->ParameterOffset = cpu_to_le16(
2577 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2578 pSMB->DataCount = 0;
2579 pSMB->DataOffset = 0;
2580 pSMB->SetupCount = 1;
2581 pSMB->Reserved3 = 0;
2582 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2583 pSMB->SearchHandle = searchHandle; /* always kept as le */
2584 pSMB->SearchCount =
2585 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2586 /* test for Unix extensions */
2587 /* if (tcon->ses->capabilities & CAP_UNIX) {
2588 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2589 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2590 } else {
2591 pSMB->InformationLevel =
2592 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2593 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2594 } */
2595 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2596 pSMB->ResumeKey = psrch_inf->resume_key;
2597 pSMB->SearchFlags =
2598 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2600 name_len = psrch_inf->resume_name_len;
2601 params += name_len;
2602 if(name_len < PATH_MAX) {
2603 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2604 byte_count += name_len;
2605 /* 14 byte parm len above enough for 2 byte null terminator */
2606 pSMB->ResumeFileName[name_len] = 0;
2607 pSMB->ResumeFileName[name_len+1] = 0;
2608 } else {
2609 rc = -EINVAL;
2610 goto FNext2_err_exit;
2612 byte_count = params + 1 /* pad */ ;
2613 pSMB->TotalParameterCount = cpu_to_le16(params);
2614 pSMB->ParameterCount = pSMB->TotalParameterCount;
2615 pSMB->hdr.smb_buf_length += byte_count;
2616 pSMB->ByteCount = cpu_to_le16(byte_count);
2618 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2619 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2621 if (rc) {
2622 if (rc == -EBADF) {
2623 psrch_inf->endOfSearch = TRUE;
2624 rc = 0; /* search probably was closed at end of search above */
2625 } else
2626 cFYI(1, ("FindNext returned = %d", rc));
2627 } else { /* decode response */
2628 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2630 if(rc == 0) {
2631 /* BB fixme add lock for file (srch_info) struct here */
2632 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2633 psrch_inf->unicode = TRUE;
2634 else
2635 psrch_inf->unicode = FALSE;
2636 response_data = (char *) &pSMBr->hdr.Protocol +
2637 le16_to_cpu(pSMBr->t2.ParameterOffset);
2638 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2639 response_data = (char *)&pSMBr->hdr.Protocol +
2640 le16_to_cpu(pSMBr->t2.DataOffset);
2641 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2642 psrch_inf->srch_entries_start = response_data;
2643 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2644 if(parms->EndofSearch)
2645 psrch_inf->endOfSearch = TRUE;
2646 else
2647 psrch_inf->endOfSearch = FALSE;
2649 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2650 psrch_inf->index_of_last_entry +=
2651 psrch_inf->entries_in_buffer;
2652 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2654 /* BB fixme add unlock here */
2659 /* BB On error, should we leave previous search buf (and count and
2660 last entry fields) intact or free the previous one? */
2662 /* Note: On -EAGAIN error only caller can retry on handle based calls
2663 since file handle passed in no longer valid */
2664 FNext2_err_exit:
2665 if (rc != 0)
2666 cifs_buf_release(pSMB);
2668 return rc;
2672 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2674 int rc = 0;
2675 FINDCLOSE_REQ *pSMB = NULL;
2676 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2677 int bytes_returned;
2679 cFYI(1, ("In CIFSSMBFindClose"));
2680 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2682 /* no sense returning error if session restarted
2683 as file handle has been closed */
2684 if(rc == -EAGAIN)
2685 return 0;
2686 if (rc)
2687 return rc;
2689 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2690 pSMB->FileID = searchHandle;
2691 pSMB->ByteCount = 0;
2692 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2693 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2694 if (rc) {
2695 cERROR(1, ("Send error in FindClose = %d", rc));
2697 cifs_small_buf_release(pSMB);
2699 /* Since session is dead, search handle closed on server already */
2700 if (rc == -EAGAIN)
2701 rc = 0;
2703 return rc;
2706 #ifdef CONFIG_CIFS_EXPERIMENTAL
2708 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2709 const unsigned char *searchName,
2710 __u64 * inode_number,
2711 const struct nls_table *nls_codepage, int remap)
2713 int rc = 0;
2714 TRANSACTION2_QPI_REQ *pSMB = NULL;
2715 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2716 int name_len, bytes_returned;
2717 __u16 params, byte_count;
2719 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2720 if(tcon == NULL)
2721 return -ENODEV;
2723 GetInodeNumberRetry:
2724 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2725 (void **) &pSMBr);
2726 if (rc)
2727 return rc;
2730 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2731 name_len =
2732 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2733 PATH_MAX,nls_codepage, remap);
2734 name_len++; /* trailing null */
2735 name_len *= 2;
2736 } else { /* BB improve the check for buffer overruns BB */
2737 name_len = strnlen(searchName, PATH_MAX);
2738 name_len++; /* trailing null */
2739 strncpy(pSMB->FileName, searchName, name_len);
2742 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2743 pSMB->TotalDataCount = 0;
2744 pSMB->MaxParameterCount = cpu_to_le16(2);
2745 /* BB find exact max data count below from sess structure BB */
2746 pSMB->MaxDataCount = cpu_to_le16(4000);
2747 pSMB->MaxSetupCount = 0;
2748 pSMB->Reserved = 0;
2749 pSMB->Flags = 0;
2750 pSMB->Timeout = 0;
2751 pSMB->Reserved2 = 0;
2752 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2753 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2754 pSMB->DataCount = 0;
2755 pSMB->DataOffset = 0;
2756 pSMB->SetupCount = 1;
2757 pSMB->Reserved3 = 0;
2758 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2759 byte_count = params + 1 /* pad */ ;
2760 pSMB->TotalParameterCount = cpu_to_le16(params);
2761 pSMB->ParameterCount = pSMB->TotalParameterCount;
2762 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2763 pSMB->Reserved4 = 0;
2764 pSMB->hdr.smb_buf_length += byte_count;
2765 pSMB->ByteCount = cpu_to_le16(byte_count);
2767 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2768 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2769 if (rc) {
2770 cFYI(1, ("error %d in QueryInternalInfo", rc));
2771 } else {
2772 /* decode response */
2773 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2774 if (rc || (pSMBr->ByteCount < 2))
2775 /* BB also check enough total bytes returned */
2776 /* If rc should we check for EOPNOSUPP and
2777 disable the srvino flag? or in caller? */
2778 rc = -EIO; /* bad smb */
2779 else {
2780 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2781 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2782 struct file_internal_info * pfinfo;
2783 /* BB Do we need a cast or hash here ? */
2784 if(count < 8) {
2785 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2786 rc = -EIO;
2787 goto GetInodeNumOut;
2789 pfinfo = (struct file_internal_info *)
2790 (data_offset + (char *) &pSMBr->hdr.Protocol);
2791 *inode_number = pfinfo->UniqueId;
2794 GetInodeNumOut:
2795 cifs_buf_release(pSMB);
2796 if (rc == -EAGAIN)
2797 goto GetInodeNumberRetry;
2798 return rc;
2800 #endif /* CIFS_EXPERIMENTAL */
2803 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2804 const unsigned char *searchName,
2805 unsigned char **targetUNCs,
2806 unsigned int *number_of_UNC_in_array,
2807 const struct nls_table *nls_codepage, int remap)
2809 /* TRANS2_GET_DFS_REFERRAL */
2810 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2811 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2812 struct dfs_referral_level_3 * referrals = NULL;
2813 int rc = 0;
2814 int bytes_returned;
2815 int name_len;
2816 unsigned int i;
2817 char * temp;
2818 __u16 params, byte_count;
2819 *number_of_UNC_in_array = 0;
2820 *targetUNCs = NULL;
2822 cFYI(1, ("In GetDFSRefer the path %s", searchName));
2823 if (ses == NULL)
2824 return -ENODEV;
2825 getDFSRetry:
2826 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2827 (void **) &pSMBr);
2828 if (rc)
2829 return rc;
2831 pSMB->hdr.Tid = ses->ipc_tid;
2832 pSMB->hdr.Uid = ses->Suid;
2833 if (ses->capabilities & CAP_STATUS32) {
2834 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2836 if (ses->capabilities & CAP_DFS) {
2837 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2840 if (ses->capabilities & CAP_UNICODE) {
2841 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2842 name_len =
2843 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
2844 searchName, PATH_MAX, nls_codepage, remap);
2845 name_len++; /* trailing null */
2846 name_len *= 2;
2847 } else { /* BB improve the check for buffer overruns BB */
2848 name_len = strnlen(searchName, PATH_MAX);
2849 name_len++; /* trailing null */
2850 strncpy(pSMB->RequestFileName, searchName, name_len);
2853 params = 2 /* level */ + name_len /*includes null */ ;
2854 pSMB->TotalDataCount = 0;
2855 pSMB->DataCount = 0;
2856 pSMB->DataOffset = 0;
2857 pSMB->MaxParameterCount = 0;
2858 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2859 pSMB->MaxSetupCount = 0;
2860 pSMB->Reserved = 0;
2861 pSMB->Flags = 0;
2862 pSMB->Timeout = 0;
2863 pSMB->Reserved2 = 0;
2864 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2865 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2866 pSMB->SetupCount = 1;
2867 pSMB->Reserved3 = 0;
2868 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2869 byte_count = params + 3 /* pad */ ;
2870 pSMB->ParameterCount = cpu_to_le16(params);
2871 pSMB->TotalParameterCount = pSMB->ParameterCount;
2872 pSMB->MaxReferralLevel = cpu_to_le16(3);
2873 pSMB->hdr.smb_buf_length += byte_count;
2874 pSMB->ByteCount = cpu_to_le16(byte_count);
2876 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2878 if (rc) {
2879 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2880 } else { /* decode response */
2881 /* BB Add logic to parse referrals here */
2882 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2884 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
2885 rc = -EIO; /* bad smb */
2886 else {
2887 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2888 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2890 cFYI(1,
2891 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
2892 pSMBr->ByteCount, data_offset));
2893 referrals =
2894 (struct dfs_referral_level_3 *)
2895 (8 /* sizeof start of data block */ +
2896 data_offset +
2897 (char *) &pSMBr->hdr.Protocol);
2898 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",
2899 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)));
2900 /* BB This field is actually two bytes in from start of
2901 data block so we could do safety check that DataBlock
2902 begins at address of pSMBr->NumberOfReferrals */
2903 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2905 /* BB Fix below so can return more than one referral */
2906 if(*number_of_UNC_in_array > 1)
2907 *number_of_UNC_in_array = 1;
2909 /* get the length of the strings describing refs */
2910 name_len = 0;
2911 for(i=0;i<*number_of_UNC_in_array;i++) {
2912 /* make sure that DfsPathOffset not past end */
2913 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2914 if (offset > data_count) {
2915 /* if invalid referral, stop here and do
2916 not try to copy any more */
2917 *number_of_UNC_in_array = i;
2918 break;
2920 temp = ((char *)referrals) + offset;
2922 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2923 name_len += UniStrnlen((wchar_t *)temp,data_count);
2924 } else {
2925 name_len += strnlen(temp,data_count);
2927 referrals++;
2928 /* BB add check that referral pointer does not fall off end PDU */
2931 /* BB add check for name_len bigger than bcc */
2932 *targetUNCs =
2933 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2934 if(*targetUNCs == NULL) {
2935 rc = -ENOMEM;
2936 goto GetDFSRefExit;
2938 /* copy the ref strings */
2939 referrals =
2940 (struct dfs_referral_level_3 *)
2941 (8 /* sizeof data hdr */ +
2942 data_offset +
2943 (char *) &pSMBr->hdr.Protocol);
2945 for(i=0;i<*number_of_UNC_in_array;i++) {
2946 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2947 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2948 cifs_strfromUCS_le(*targetUNCs,
2949 (wchar_t *) temp, name_len, nls_codepage);
2950 } else {
2951 strncpy(*targetUNCs,temp,name_len);
2953 /* BB update target_uncs pointers */
2954 referrals++;
2956 temp = *targetUNCs;
2957 temp[name_len] = 0;
2961 GetDFSRefExit:
2962 if (pSMB)
2963 cifs_buf_release(pSMB);
2965 if (rc == -EAGAIN)
2966 goto getDFSRetry;
2968 return rc;
2972 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
2974 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
2975 TRANSACTION2_QFSI_REQ *pSMB = NULL;
2976 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2977 FILE_SYSTEM_INFO *response_data;
2978 int rc = 0;
2979 int bytes_returned = 0;
2980 __u16 params, byte_count;
2982 cFYI(1, ("In QFSInfo"));
2983 QFSInfoRetry:
2984 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2985 (void **) &pSMBr);
2986 if (rc)
2987 return rc;
2989 params = 2; /* level */
2990 pSMB->TotalDataCount = 0;
2991 pSMB->MaxParameterCount = cpu_to_le16(2);
2992 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2993 pSMB->MaxSetupCount = 0;
2994 pSMB->Reserved = 0;
2995 pSMB->Flags = 0;
2996 pSMB->Timeout = 0;
2997 pSMB->Reserved2 = 0;
2998 byte_count = params + 1 /* pad */ ;
2999 pSMB->TotalParameterCount = cpu_to_le16(params);
3000 pSMB->ParameterCount = pSMB->TotalParameterCount;
3001 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3002 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3003 pSMB->DataCount = 0;
3004 pSMB->DataOffset = 0;
3005 pSMB->SetupCount = 1;
3006 pSMB->Reserved3 = 0;
3007 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3008 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3009 pSMB->hdr.smb_buf_length += byte_count;
3010 pSMB->ByteCount = cpu_to_le16(byte_count);
3012 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3013 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3014 if (rc) {
3015 cERROR(1, ("Send error in QFSInfo = %d", rc));
3016 } else { /* decode response */
3017 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3019 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3020 rc = -EIO; /* bad smb */
3021 else {
3022 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3023 cFYI(1,
3024 ("Decoding qfsinfo response. BCC: %d Offset %d",
3025 pSMBr->ByteCount, data_offset));
3027 response_data =
3028 (FILE_SYSTEM_INFO
3029 *) (((char *) &pSMBr->hdr.Protocol) +
3030 data_offset);
3031 FSData->f_bsize =
3032 le32_to_cpu(response_data->BytesPerSector) *
3033 le32_to_cpu(response_data->
3034 SectorsPerAllocationUnit);
3035 FSData->f_blocks =
3036 le64_to_cpu(response_data->TotalAllocationUnits);
3037 FSData->f_bfree = FSData->f_bavail =
3038 le64_to_cpu(response_data->FreeAllocationUnits);
3039 cFYI(1,
3040 ("Blocks: %lld Free: %lld Block size %ld",
3041 (unsigned long long)FSData->f_blocks,
3042 (unsigned long long)FSData->f_bfree,
3043 FSData->f_bsize));
3046 cifs_buf_release(pSMB);
3048 if (rc == -EAGAIN)
3049 goto QFSInfoRetry;
3051 return rc;
3055 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3057 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3058 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3059 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3060 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3061 int rc = 0;
3062 int bytes_returned = 0;
3063 __u16 params, byte_count;
3065 cFYI(1, ("In QFSAttributeInfo"));
3066 QFSAttributeRetry:
3067 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3068 (void **) &pSMBr);
3069 if (rc)
3070 return rc;
3072 params = 2; /* level */
3073 pSMB->TotalDataCount = 0;
3074 pSMB->MaxParameterCount = cpu_to_le16(2);
3075 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3076 pSMB->MaxSetupCount = 0;
3077 pSMB->Reserved = 0;
3078 pSMB->Flags = 0;
3079 pSMB->Timeout = 0;
3080 pSMB->Reserved2 = 0;
3081 byte_count = params + 1 /* pad */ ;
3082 pSMB->TotalParameterCount = cpu_to_le16(params);
3083 pSMB->ParameterCount = pSMB->TotalParameterCount;
3084 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3085 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3086 pSMB->DataCount = 0;
3087 pSMB->DataOffset = 0;
3088 pSMB->SetupCount = 1;
3089 pSMB->Reserved3 = 0;
3090 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3091 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3092 pSMB->hdr.smb_buf_length += byte_count;
3093 pSMB->ByteCount = cpu_to_le16(byte_count);
3095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3097 if (rc) {
3098 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3099 } else { /* decode response */
3100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3102 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3103 rc = -EIO; /* bad smb */
3104 } else {
3105 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3106 response_data =
3107 (FILE_SYSTEM_ATTRIBUTE_INFO
3108 *) (((char *) &pSMBr->hdr.Protocol) +
3109 data_offset);
3110 memcpy(&tcon->fsAttrInfo, response_data,
3111 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3114 cifs_buf_release(pSMB);
3116 if (rc == -EAGAIN)
3117 goto QFSAttributeRetry;
3119 return rc;
3123 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3125 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3126 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3127 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3128 FILE_SYSTEM_DEVICE_INFO *response_data;
3129 int rc = 0;
3130 int bytes_returned = 0;
3131 __u16 params, byte_count;
3133 cFYI(1, ("In QFSDeviceInfo"));
3134 QFSDeviceRetry:
3135 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3136 (void **) &pSMBr);
3137 if (rc)
3138 return rc;
3140 params = 2; /* level */
3141 pSMB->TotalDataCount = 0;
3142 pSMB->MaxParameterCount = cpu_to_le16(2);
3143 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3144 pSMB->MaxSetupCount = 0;
3145 pSMB->Reserved = 0;
3146 pSMB->Flags = 0;
3147 pSMB->Timeout = 0;
3148 pSMB->Reserved2 = 0;
3149 byte_count = params + 1 /* pad */ ;
3150 pSMB->TotalParameterCount = cpu_to_le16(params);
3151 pSMB->ParameterCount = pSMB->TotalParameterCount;
3152 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3153 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3155 pSMB->DataCount = 0;
3156 pSMB->DataOffset = 0;
3157 pSMB->SetupCount = 1;
3158 pSMB->Reserved3 = 0;
3159 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3160 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3161 pSMB->hdr.smb_buf_length += byte_count;
3162 pSMB->ByteCount = cpu_to_le16(byte_count);
3164 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3165 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3166 if (rc) {
3167 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3168 } else { /* decode response */
3169 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3171 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3172 rc = -EIO; /* bad smb */
3173 else {
3174 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3175 response_data =
3176 (FILE_SYSTEM_DEVICE_INFO *)
3177 (((char *) &pSMBr->hdr.Protocol) +
3178 data_offset);
3179 memcpy(&tcon->fsDevInfo, response_data,
3180 sizeof (FILE_SYSTEM_DEVICE_INFO));
3183 cifs_buf_release(pSMB);
3185 if (rc == -EAGAIN)
3186 goto QFSDeviceRetry;
3188 return rc;
3192 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3194 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3195 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3196 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3197 FILE_SYSTEM_UNIX_INFO *response_data;
3198 int rc = 0;
3199 int bytes_returned = 0;
3200 __u16 params, byte_count;
3202 cFYI(1, ("In QFSUnixInfo"));
3203 QFSUnixRetry:
3204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3205 (void **) &pSMBr);
3206 if (rc)
3207 return rc;
3209 params = 2; /* level */
3210 pSMB->TotalDataCount = 0;
3211 pSMB->DataCount = 0;
3212 pSMB->DataOffset = 0;
3213 pSMB->MaxParameterCount = cpu_to_le16(2);
3214 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3215 pSMB->MaxSetupCount = 0;
3216 pSMB->Reserved = 0;
3217 pSMB->Flags = 0;
3218 pSMB->Timeout = 0;
3219 pSMB->Reserved2 = 0;
3220 byte_count = params + 1 /* pad */ ;
3221 pSMB->ParameterCount = cpu_to_le16(params);
3222 pSMB->TotalParameterCount = pSMB->ParameterCount;
3223 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3224 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3225 pSMB->SetupCount = 1;
3226 pSMB->Reserved3 = 0;
3227 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3228 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3229 pSMB->hdr.smb_buf_length += byte_count;
3230 pSMB->ByteCount = cpu_to_le16(byte_count);
3232 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3233 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3234 if (rc) {
3235 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3236 } else { /* decode response */
3237 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3239 if (rc || (pSMBr->ByteCount < 13)) {
3240 rc = -EIO; /* bad smb */
3241 } else {
3242 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3243 response_data =
3244 (FILE_SYSTEM_UNIX_INFO
3245 *) (((char *) &pSMBr->hdr.Protocol) +
3246 data_offset);
3247 memcpy(&tcon->fsUnixInfo, response_data,
3248 sizeof (FILE_SYSTEM_UNIX_INFO));
3251 cifs_buf_release(pSMB);
3253 if (rc == -EAGAIN)
3254 goto QFSUnixRetry;
3257 return rc;
3262 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3263 struct kstatfs *FSData)
3265 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3266 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3267 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3268 FILE_SYSTEM_POSIX_INFO *response_data;
3269 int rc = 0;
3270 int bytes_returned = 0;
3271 __u16 params, byte_count;
3273 cFYI(1, ("In QFSPosixInfo"));
3274 QFSPosixRetry:
3275 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3276 (void **) &pSMBr);
3277 if (rc)
3278 return rc;
3280 params = 2; /* level */
3281 pSMB->TotalDataCount = 0;
3282 pSMB->DataCount = 0;
3283 pSMB->DataOffset = 0;
3284 pSMB->MaxParameterCount = cpu_to_le16(2);
3285 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3286 pSMB->MaxSetupCount = 0;
3287 pSMB->Reserved = 0;
3288 pSMB->Flags = 0;
3289 pSMB->Timeout = 0;
3290 pSMB->Reserved2 = 0;
3291 byte_count = params + 1 /* pad */ ;
3292 pSMB->ParameterCount = cpu_to_le16(params);
3293 pSMB->TotalParameterCount = pSMB->ParameterCount;
3294 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3295 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3296 pSMB->SetupCount = 1;
3297 pSMB->Reserved3 = 0;
3298 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3299 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3300 pSMB->hdr.smb_buf_length += byte_count;
3301 pSMB->ByteCount = cpu_to_le16(byte_count);
3303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3305 if (rc) {
3306 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3307 } else { /* decode response */
3308 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3310 if (rc || (pSMBr->ByteCount < 13)) {
3311 rc = -EIO; /* bad smb */
3312 } else {
3313 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3314 response_data =
3315 (FILE_SYSTEM_POSIX_INFO
3316 *) (((char *) &pSMBr->hdr.Protocol) +
3317 data_offset);
3318 FSData->f_bsize =
3319 le32_to_cpu(response_data->BlockSize);
3320 FSData->f_blocks =
3321 le64_to_cpu(response_data->TotalBlocks);
3322 FSData->f_bfree =
3323 le64_to_cpu(response_data->BlocksAvail);
3324 if(response_data->UserBlocksAvail == -1) {
3325 FSData->f_bavail = FSData->f_bfree;
3326 } else {
3327 FSData->f_bavail =
3328 le64_to_cpu(response_data->UserBlocksAvail);
3330 if(response_data->TotalFileNodes != -1)
3331 FSData->f_files =
3332 le64_to_cpu(response_data->TotalFileNodes);
3333 if(response_data->FreeFileNodes != -1)
3334 FSData->f_ffree =
3335 le64_to_cpu(response_data->FreeFileNodes);
3338 cifs_buf_release(pSMB);
3340 if (rc == -EAGAIN)
3341 goto QFSPosixRetry;
3343 return rc;
3347 /* We can not use write of zero bytes trick to
3348 set file size due to need for large file support. Also note that
3349 this SetPathInfo is preferred to SetFileInfo based method in next
3350 routine which is only needed to work around a sharing violation bug
3351 in Samba which this routine can run into */
3354 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3355 __u64 size, int SetAllocation,
3356 const struct nls_table *nls_codepage, int remap)
3358 struct smb_com_transaction2_spi_req *pSMB = NULL;
3359 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3360 struct file_end_of_file_info *parm_data;
3361 int name_len;
3362 int rc = 0;
3363 int bytes_returned = 0;
3364 __u16 params, byte_count, data_count, param_offset, offset;
3366 cFYI(1, ("In SetEOF"));
3367 SetEOFRetry:
3368 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3369 (void **) &pSMBr);
3370 if (rc)
3371 return rc;
3373 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3374 name_len =
3375 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3376 PATH_MAX, nls_codepage, remap);
3377 name_len++; /* trailing null */
3378 name_len *= 2;
3379 } else { /* BB improve the check for buffer overruns BB */
3380 name_len = strnlen(fileName, PATH_MAX);
3381 name_len++; /* trailing null */
3382 strncpy(pSMB->FileName, fileName, name_len);
3384 params = 6 + name_len;
3385 data_count = sizeof (struct file_end_of_file_info);
3386 pSMB->MaxParameterCount = cpu_to_le16(2);
3387 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3388 pSMB->MaxSetupCount = 0;
3389 pSMB->Reserved = 0;
3390 pSMB->Flags = 0;
3391 pSMB->Timeout = 0;
3392 pSMB->Reserved2 = 0;
3393 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3394 InformationLevel) - 4;
3395 offset = param_offset + params;
3396 if(SetAllocation) {
3397 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3398 pSMB->InformationLevel =
3399 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3400 else
3401 pSMB->InformationLevel =
3402 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3403 } else /* Set File Size */ {
3404 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3405 pSMB->InformationLevel =
3406 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3407 else
3408 pSMB->InformationLevel =
3409 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3412 parm_data =
3413 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3414 offset);
3415 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3416 pSMB->DataOffset = cpu_to_le16(offset);
3417 pSMB->SetupCount = 1;
3418 pSMB->Reserved3 = 0;
3419 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3420 byte_count = 3 /* pad */ + params + data_count;
3421 pSMB->DataCount = cpu_to_le16(data_count);
3422 pSMB->TotalDataCount = pSMB->DataCount;
3423 pSMB->ParameterCount = cpu_to_le16(params);
3424 pSMB->TotalParameterCount = pSMB->ParameterCount;
3425 pSMB->Reserved4 = 0;
3426 pSMB->hdr.smb_buf_length += byte_count;
3427 parm_data->FileSize = cpu_to_le64(size);
3428 pSMB->ByteCount = cpu_to_le16(byte_count);
3429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3431 if (rc) {
3432 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3435 cifs_buf_release(pSMB);
3437 if (rc == -EAGAIN)
3438 goto SetEOFRetry;
3440 return rc;
3444 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3445 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3447 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3448 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3449 char *data_offset;
3450 struct file_end_of_file_info *parm_data;
3451 int rc = 0;
3452 int bytes_returned = 0;
3453 __u16 params, param_offset, offset, byte_count, count;
3455 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3456 (long long)size));
3457 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3459 if (rc)
3460 return rc;
3462 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3464 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3465 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3467 params = 6;
3468 pSMB->MaxSetupCount = 0;
3469 pSMB->Reserved = 0;
3470 pSMB->Flags = 0;
3471 pSMB->Timeout = 0;
3472 pSMB->Reserved2 = 0;
3473 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3474 offset = param_offset + params;
3476 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3478 count = sizeof(struct file_end_of_file_info);
3479 pSMB->MaxParameterCount = cpu_to_le16(2);
3480 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3481 pSMB->SetupCount = 1;
3482 pSMB->Reserved3 = 0;
3483 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3484 byte_count = 3 /* pad */ + params + count;
3485 pSMB->DataCount = cpu_to_le16(count);
3486 pSMB->ParameterCount = cpu_to_le16(params);
3487 pSMB->TotalDataCount = pSMB->DataCount;
3488 pSMB->TotalParameterCount = pSMB->ParameterCount;
3489 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3490 parm_data =
3491 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3492 offset);
3493 pSMB->DataOffset = cpu_to_le16(offset);
3494 parm_data->FileSize = cpu_to_le64(size);
3495 pSMB->Fid = fid;
3496 if(SetAllocation) {
3497 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3498 pSMB->InformationLevel =
3499 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3500 else
3501 pSMB->InformationLevel =
3502 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3503 } else /* Set File Size */ {
3504 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3505 pSMB->InformationLevel =
3506 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3507 else
3508 pSMB->InformationLevel =
3509 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3511 pSMB->Reserved4 = 0;
3512 pSMB->hdr.smb_buf_length += byte_count;
3513 pSMB->ByteCount = cpu_to_le16(byte_count);
3514 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3515 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3516 if (rc) {
3517 cFYI(1,
3518 ("Send error in SetFileInfo (SetFileSize) = %d",
3519 rc));
3522 if (pSMB)
3523 cifs_small_buf_release(pSMB);
3525 /* Note: On -EAGAIN error only caller can retry on handle based calls
3526 since file handle passed in no longer valid */
3528 return rc;
3531 /* Some legacy servers such as NT4 require that the file times be set on
3532 an open handle, rather than by pathname - this is awkward due to
3533 potential access conflicts on the open, but it is unavoidable for these
3534 old servers since the only other choice is to go from 100 nanosecond DCE
3535 time and resort to the original setpathinfo level which takes the ancient
3536 DOS time format with 2 second granularity */
3538 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3539 __u16 fid)
3541 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3542 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3543 char *data_offset;
3544 int rc = 0;
3545 int bytes_returned = 0;
3546 __u16 params, param_offset, offset, byte_count, count;
3548 cFYI(1, ("Set Times (via SetFileInfo)"));
3549 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3551 if (rc)
3552 return rc;
3554 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3556 /* At this point there is no need to override the current pid
3557 with the pid of the opener, but that could change if we someday
3558 use an existing handle (rather than opening one on the fly) */
3559 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3560 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3562 params = 6;
3563 pSMB->MaxSetupCount = 0;
3564 pSMB->Reserved = 0;
3565 pSMB->Flags = 0;
3566 pSMB->Timeout = 0;
3567 pSMB->Reserved2 = 0;
3568 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3569 offset = param_offset + params;
3571 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3573 count = sizeof (FILE_BASIC_INFO);
3574 pSMB->MaxParameterCount = cpu_to_le16(2);
3575 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3576 pSMB->SetupCount = 1;
3577 pSMB->Reserved3 = 0;
3578 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3579 byte_count = 3 /* pad */ + params + count;
3580 pSMB->DataCount = cpu_to_le16(count);
3581 pSMB->ParameterCount = cpu_to_le16(params);
3582 pSMB->TotalDataCount = pSMB->DataCount;
3583 pSMB->TotalParameterCount = pSMB->ParameterCount;
3584 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3585 pSMB->DataOffset = cpu_to_le16(offset);
3586 pSMB->Fid = fid;
3587 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3588 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3589 else
3590 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3591 pSMB->Reserved4 = 0;
3592 pSMB->hdr.smb_buf_length += byte_count;
3593 pSMB->ByteCount = cpu_to_le16(byte_count);
3594 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3597 if (rc) {
3598 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3601 cifs_small_buf_release(pSMB);
3603 /* Note: On -EAGAIN error only caller can retry on handle based calls
3604 since file handle passed in no longer valid */
3606 return rc;
3611 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3612 const FILE_BASIC_INFO * data,
3613 const struct nls_table *nls_codepage, int remap)
3615 TRANSACTION2_SPI_REQ *pSMB = NULL;
3616 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3617 int name_len;
3618 int rc = 0;
3619 int bytes_returned = 0;
3620 char *data_offset;
3621 __u16 params, param_offset, offset, byte_count, count;
3623 cFYI(1, ("In SetTimes"));
3625 SetTimesRetry:
3626 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3627 (void **) &pSMBr);
3628 if (rc)
3629 return rc;
3631 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3632 name_len =
3633 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3634 PATH_MAX, nls_codepage, remap);
3635 name_len++; /* trailing null */
3636 name_len *= 2;
3637 } else { /* BB improve the check for buffer overruns BB */
3638 name_len = strnlen(fileName, PATH_MAX);
3639 name_len++; /* trailing null */
3640 strncpy(pSMB->FileName, fileName, name_len);
3643 params = 6 + name_len;
3644 count = sizeof (FILE_BASIC_INFO);
3645 pSMB->MaxParameterCount = cpu_to_le16(2);
3646 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3647 pSMB->MaxSetupCount = 0;
3648 pSMB->Reserved = 0;
3649 pSMB->Flags = 0;
3650 pSMB->Timeout = 0;
3651 pSMB->Reserved2 = 0;
3652 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3653 InformationLevel) - 4;
3654 offset = param_offset + params;
3655 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3656 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3657 pSMB->DataOffset = cpu_to_le16(offset);
3658 pSMB->SetupCount = 1;
3659 pSMB->Reserved3 = 0;
3660 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3661 byte_count = 3 /* pad */ + params + count;
3663 pSMB->DataCount = cpu_to_le16(count);
3664 pSMB->ParameterCount = cpu_to_le16(params);
3665 pSMB->TotalDataCount = pSMB->DataCount;
3666 pSMB->TotalParameterCount = pSMB->ParameterCount;
3667 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3668 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3669 else
3670 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3671 pSMB->Reserved4 = 0;
3672 pSMB->hdr.smb_buf_length += byte_count;
3673 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3674 pSMB->ByteCount = cpu_to_le16(byte_count);
3675 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3677 if (rc) {
3678 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3681 cifs_buf_release(pSMB);
3683 if (rc == -EAGAIN)
3684 goto SetTimesRetry;
3686 return rc;
3689 /* Can not be used to set time stamps yet (due to old DOS time format) */
3690 /* Can be used to set attributes */
3691 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
3692 handling it anyway and NT4 was what we thought it would be needed for
3693 Do not delete it until we prove whether needed for Win9x though */
3695 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3696 __u16 dos_attrs, const struct nls_table *nls_codepage)
3698 SETATTR_REQ *pSMB = NULL;
3699 SETATTR_RSP *pSMBr = NULL;
3700 int rc = 0;
3701 int bytes_returned;
3702 int name_len;
3704 cFYI(1, ("In SetAttrLegacy"));
3706 SetAttrLgcyRetry:
3707 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3708 (void **) &pSMBr);
3709 if (rc)
3710 return rc;
3712 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3713 name_len =
3714 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
3715 PATH_MAX, nls_codepage);
3716 name_len++; /* trailing null */
3717 name_len *= 2;
3718 } else { /* BB improve the check for buffer overruns BB */
3719 name_len = strnlen(fileName, PATH_MAX);
3720 name_len++; /* trailing null */
3721 strncpy(pSMB->fileName, fileName, name_len);
3723 pSMB->attr = cpu_to_le16(dos_attrs);
3724 pSMB->BufferFormat = 0x04;
3725 pSMB->hdr.smb_buf_length += name_len + 1;
3726 pSMB->ByteCount = cpu_to_le16(name_len + 1);
3727 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3728 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3729 if (rc) {
3730 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3733 cifs_buf_release(pSMB);
3735 if (rc == -EAGAIN)
3736 goto SetAttrLgcyRetry;
3738 return rc;
3740 #endif /* temporarily unneeded SetAttr legacy function */
3743 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
3744 char *fileName, __u64 mode, __u64 uid, __u64 gid,
3745 dev_t device, const struct nls_table *nls_codepage,
3746 int remap)
3748 TRANSACTION2_SPI_REQ *pSMB = NULL;
3749 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3750 int name_len;
3751 int rc = 0;
3752 int bytes_returned = 0;
3753 FILE_UNIX_BASIC_INFO *data_offset;
3754 __u16 params, param_offset, offset, count, byte_count;
3756 cFYI(1, ("In SetUID/GID/Mode"));
3757 setPermsRetry:
3758 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3759 (void **) &pSMBr);
3760 if (rc)
3761 return rc;
3763 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3764 name_len =
3765 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3766 PATH_MAX, nls_codepage, remap);
3767 name_len++; /* trailing null */
3768 name_len *= 2;
3769 } else { /* BB improve the check for buffer overruns BB */
3770 name_len = strnlen(fileName, PATH_MAX);
3771 name_len++; /* trailing null */
3772 strncpy(pSMB->FileName, fileName, name_len);
3775 params = 6 + name_len;
3776 count = sizeof (FILE_UNIX_BASIC_INFO);
3777 pSMB->MaxParameterCount = cpu_to_le16(2);
3778 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3779 pSMB->MaxSetupCount = 0;
3780 pSMB->Reserved = 0;
3781 pSMB->Flags = 0;
3782 pSMB->Timeout = 0;
3783 pSMB->Reserved2 = 0;
3784 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3785 InformationLevel) - 4;
3786 offset = param_offset + params;
3787 data_offset =
3788 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3789 offset);
3790 memset(data_offset, 0, count);
3791 pSMB->DataOffset = cpu_to_le16(offset);
3792 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3793 pSMB->SetupCount = 1;
3794 pSMB->Reserved3 = 0;
3795 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3796 byte_count = 3 /* pad */ + params + count;
3797 pSMB->ParameterCount = cpu_to_le16(params);
3798 pSMB->DataCount = cpu_to_le16(count);
3799 pSMB->TotalParameterCount = pSMB->ParameterCount;
3800 pSMB->TotalDataCount = pSMB->DataCount;
3801 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3802 pSMB->Reserved4 = 0;
3803 pSMB->hdr.smb_buf_length += byte_count;
3804 data_offset->Uid = cpu_to_le64(uid);
3805 data_offset->Gid = cpu_to_le64(gid);
3806 /* better to leave device as zero when it is */
3807 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3808 data_offset->DevMinor = cpu_to_le64(MINOR(device));
3809 data_offset->Permissions = cpu_to_le64(mode);
3811 if(S_ISREG(mode))
3812 data_offset->Type = cpu_to_le32(UNIX_FILE);
3813 else if(S_ISDIR(mode))
3814 data_offset->Type = cpu_to_le32(UNIX_DIR);
3815 else if(S_ISLNK(mode))
3816 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3817 else if(S_ISCHR(mode))
3818 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3819 else if(S_ISBLK(mode))
3820 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3821 else if(S_ISFIFO(mode))
3822 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3823 else if(S_ISSOCK(mode))
3824 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3827 pSMB->ByteCount = cpu_to_le16(byte_count);
3828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3830 if (rc) {
3831 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3834 if (pSMB)
3835 cifs_buf_release(pSMB);
3836 if (rc == -EAGAIN)
3837 goto setPermsRetry;
3838 return rc;
3841 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
3842 const int notify_subdirs, const __u16 netfid,
3843 __u32 filter, const struct nls_table *nls_codepage)
3845 int rc = 0;
3846 struct smb_com_transaction_change_notify_req * pSMB = NULL;
3847 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3848 int bytes_returned;
3850 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3851 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3852 (void **) &pSMBr);
3853 if (rc)
3854 return rc;
3856 pSMB->TotalParameterCount = 0 ;
3857 pSMB->TotalDataCount = 0;
3858 pSMB->MaxParameterCount = cpu_to_le32(2);
3859 /* BB find exact data count max from sess structure BB */
3860 pSMB->MaxDataCount = 0; /* same in little endian or be */
3861 pSMB->MaxSetupCount = 4;
3862 pSMB->Reserved = 0;
3863 pSMB->ParameterOffset = 0;
3864 pSMB->DataCount = 0;
3865 pSMB->DataOffset = 0;
3866 pSMB->SetupCount = 4; /* single byte does not need le conversion */
3867 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3868 pSMB->ParameterCount = pSMB->TotalParameterCount;
3869 if(notify_subdirs)
3870 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3871 pSMB->Reserved2 = 0;
3872 pSMB->CompletionFilter = cpu_to_le32(filter);
3873 pSMB->Fid = netfid; /* file handle always le */
3874 pSMB->ByteCount = 0;
3876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3877 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3878 if (rc) {
3879 cFYI(1, ("Error in Notify = %d", rc));
3881 cifs_buf_release(pSMB);
3882 return rc;
3884 #ifdef CONFIG_CIFS_XATTR
3885 ssize_t
3886 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3887 const unsigned char *searchName,
3888 char * EAData, size_t buf_size,
3889 const struct nls_table *nls_codepage, int remap)
3891 /* BB assumes one setup word */
3892 TRANSACTION2_QPI_REQ *pSMB = NULL;
3893 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3894 int rc = 0;
3895 int bytes_returned;
3896 int name_len;
3897 struct fea * temp_fea;
3898 char * temp_ptr;
3899 __u16 params, byte_count;
3901 cFYI(1, ("In Query All EAs path %s", searchName));
3902 QAllEAsRetry:
3903 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3904 (void **) &pSMBr);
3905 if (rc)
3906 return rc;
3908 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3909 name_len =
3910 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3911 PATH_MAX, nls_codepage, remap);
3912 name_len++; /* trailing null */
3913 name_len *= 2;
3914 } else { /* BB improve the check for buffer overruns BB */
3915 name_len = strnlen(searchName, PATH_MAX);
3916 name_len++; /* trailing null */
3917 strncpy(pSMB->FileName, searchName, name_len);
3920 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3921 pSMB->TotalDataCount = 0;
3922 pSMB->MaxParameterCount = cpu_to_le16(2);
3923 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3924 pSMB->MaxSetupCount = 0;
3925 pSMB->Reserved = 0;
3926 pSMB->Flags = 0;
3927 pSMB->Timeout = 0;
3928 pSMB->Reserved2 = 0;
3929 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3930 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3931 pSMB->DataCount = 0;
3932 pSMB->DataOffset = 0;
3933 pSMB->SetupCount = 1;
3934 pSMB->Reserved3 = 0;
3935 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3936 byte_count = params + 1 /* pad */ ;
3937 pSMB->TotalParameterCount = cpu_to_le16(params);
3938 pSMB->ParameterCount = pSMB->TotalParameterCount;
3939 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3940 pSMB->Reserved4 = 0;
3941 pSMB->hdr.smb_buf_length += byte_count;
3942 pSMB->ByteCount = cpu_to_le16(byte_count);
3944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3946 if (rc) {
3947 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3948 } else { /* decode response */
3949 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3951 /* BB also check enough total bytes returned */
3952 /* BB we need to improve the validity checking
3953 of these trans2 responses */
3954 if (rc || (pSMBr->ByteCount < 4))
3955 rc = -EIO; /* bad smb */
3956 /* else if (pFindData){
3957 memcpy((char *) pFindData,
3958 (char *) &pSMBr->hdr.Protocol +
3959 data_offset, kl);
3960 }*/ else {
3961 /* check that length of list is not more than bcc */
3962 /* check that each entry does not go beyond length
3963 of list */
3964 /* check that each element of each entry does not
3965 go beyond end of list */
3966 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3967 struct fealist * ea_response_data;
3968 rc = 0;
3969 /* validate_trans2_offsets() */
3970 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
3971 ea_response_data = (struct fealist *)
3972 (((char *) &pSMBr->hdr.Protocol) +
3973 data_offset);
3974 name_len = le32_to_cpu(ea_response_data->list_len);
3975 cFYI(1,("ea length %d", name_len));
3976 if(name_len <= 8) {
3977 /* returned EA size zeroed at top of function */
3978 cFYI(1,("empty EA list returned from server"));
3979 } else {
3980 /* account for ea list len */
3981 name_len -= 4;
3982 temp_fea = ea_response_data->list;
3983 temp_ptr = (char *)temp_fea;
3984 while(name_len > 0) {
3985 __u16 value_len;
3986 name_len -= 4;
3987 temp_ptr += 4;
3988 rc += temp_fea->name_len;
3989 /* account for prefix user. and trailing null */
3990 rc = rc + 5 + 1;
3991 if(rc<(int)buf_size) {
3992 memcpy(EAData,"user.",5);
3993 EAData+=5;
3994 memcpy(EAData,temp_ptr,temp_fea->name_len);
3995 EAData+=temp_fea->name_len;
3996 /* null terminate name */
3997 *EAData = 0;
3998 EAData = EAData + 1;
3999 } else if(buf_size == 0) {
4000 /* skip copy - calc size only */
4001 } else {
4002 /* stop before overrun buffer */
4003 rc = -ERANGE;
4004 break;
4006 name_len -= temp_fea->name_len;
4007 temp_ptr += temp_fea->name_len;
4008 /* account for trailing null */
4009 name_len--;
4010 temp_ptr++;
4011 value_len = le16_to_cpu(temp_fea->value_len);
4012 name_len -= value_len;
4013 temp_ptr += value_len;
4014 /* BB check that temp_ptr is still within smb BB*/
4015 /* no trailing null to account for in value len */
4016 /* go on to next EA */
4017 temp_fea = (struct fea *)temp_ptr;
4022 if (pSMB)
4023 cifs_buf_release(pSMB);
4024 if (rc == -EAGAIN)
4025 goto QAllEAsRetry;
4027 return (ssize_t)rc;
4030 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4031 const unsigned char * searchName,const unsigned char * ea_name,
4032 unsigned char * ea_value, size_t buf_size,
4033 const struct nls_table *nls_codepage, int remap)
4035 TRANSACTION2_QPI_REQ *pSMB = NULL;
4036 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4037 int rc = 0;
4038 int bytes_returned;
4039 int name_len;
4040 struct fea * temp_fea;
4041 char * temp_ptr;
4042 __u16 params, byte_count;
4044 cFYI(1, ("In Query EA path %s", searchName));
4045 QEARetry:
4046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4047 (void **) &pSMBr);
4048 if (rc)
4049 return rc;
4051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4052 name_len =
4053 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4054 PATH_MAX, nls_codepage, remap);
4055 name_len++; /* trailing null */
4056 name_len *= 2;
4057 } else { /* BB improve the check for buffer overruns BB */
4058 name_len = strnlen(searchName, PATH_MAX);
4059 name_len++; /* trailing null */
4060 strncpy(pSMB->FileName, searchName, name_len);
4063 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4064 pSMB->TotalDataCount = 0;
4065 pSMB->MaxParameterCount = cpu_to_le16(2);
4066 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4067 pSMB->MaxSetupCount = 0;
4068 pSMB->Reserved = 0;
4069 pSMB->Flags = 0;
4070 pSMB->Timeout = 0;
4071 pSMB->Reserved2 = 0;
4072 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4073 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4074 pSMB->DataCount = 0;
4075 pSMB->DataOffset = 0;
4076 pSMB->SetupCount = 1;
4077 pSMB->Reserved3 = 0;
4078 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4079 byte_count = params + 1 /* pad */ ;
4080 pSMB->TotalParameterCount = cpu_to_le16(params);
4081 pSMB->ParameterCount = pSMB->TotalParameterCount;
4082 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4083 pSMB->Reserved4 = 0;
4084 pSMB->hdr.smb_buf_length += byte_count;
4085 pSMB->ByteCount = cpu_to_le16(byte_count);
4087 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4088 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4089 if (rc) {
4090 cFYI(1, ("Send error in Query EA = %d", rc));
4091 } else { /* decode response */
4092 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4094 /* BB also check enough total bytes returned */
4095 /* BB we need to improve the validity checking
4096 of these trans2 responses */
4097 if (rc || (pSMBr->ByteCount < 4))
4098 rc = -EIO; /* bad smb */
4099 /* else if (pFindData){
4100 memcpy((char *) pFindData,
4101 (char *) &pSMBr->hdr.Protocol +
4102 data_offset, kl);
4103 }*/ else {
4104 /* check that length of list is not more than bcc */
4105 /* check that each entry does not go beyond length
4106 of list */
4107 /* check that each element of each entry does not
4108 go beyond end of list */
4109 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4110 struct fealist * ea_response_data;
4111 rc = -ENODATA;
4112 /* validate_trans2_offsets() */
4113 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4114 ea_response_data = (struct fealist *)
4115 (((char *) &pSMBr->hdr.Protocol) +
4116 data_offset);
4117 name_len = le32_to_cpu(ea_response_data->list_len);
4118 cFYI(1,("ea length %d", name_len));
4119 if(name_len <= 8) {
4120 /* returned EA size zeroed at top of function */
4121 cFYI(1,("empty EA list returned from server"));
4122 } else {
4123 /* account for ea list len */
4124 name_len -= 4;
4125 temp_fea = ea_response_data->list;
4126 temp_ptr = (char *)temp_fea;
4127 /* loop through checking if we have a matching
4128 name and then return the associated value */
4129 while(name_len > 0) {
4130 __u16 value_len;
4131 name_len -= 4;
4132 temp_ptr += 4;
4133 value_len = le16_to_cpu(temp_fea->value_len);
4134 /* BB validate that value_len falls within SMB,
4135 even though maximum for name_len is 255 */
4136 if(memcmp(temp_fea->name,ea_name,
4137 temp_fea->name_len) == 0) {
4138 /* found a match */
4139 rc = value_len;
4140 /* account for prefix user. and trailing null */
4141 if(rc<=(int)buf_size) {
4142 memcpy(ea_value,
4143 temp_fea->name+temp_fea->name_len+1,
4144 rc);
4145 /* ea values, unlike ea names,
4146 are not null terminated */
4147 } else if(buf_size == 0) {
4148 /* skip copy - calc size only */
4149 } else {
4150 /* stop before overrun buffer */
4151 rc = -ERANGE;
4153 break;
4155 name_len -= temp_fea->name_len;
4156 temp_ptr += temp_fea->name_len;
4157 /* account for trailing null */
4158 name_len--;
4159 temp_ptr++;
4160 name_len -= value_len;
4161 temp_ptr += value_len;
4162 /* no trailing null to account for in value len */
4163 /* go on to next EA */
4164 temp_fea = (struct fea *)temp_ptr;
4169 if (pSMB)
4170 cifs_buf_release(pSMB);
4171 if (rc == -EAGAIN)
4172 goto QEARetry;
4174 return (ssize_t)rc;
4178 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4179 const char * ea_name, const void * ea_value,
4180 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4181 int remap)
4183 struct smb_com_transaction2_spi_req *pSMB = NULL;
4184 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4185 struct fealist *parm_data;
4186 int name_len;
4187 int rc = 0;
4188 int bytes_returned = 0;
4189 __u16 params, param_offset, byte_count, offset, count;
4191 cFYI(1, ("In SetEA"));
4192 SetEARetry:
4193 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4194 (void **) &pSMBr);
4195 if (rc)
4196 return rc;
4198 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4199 name_len =
4200 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4201 PATH_MAX, nls_codepage, remap);
4202 name_len++; /* trailing null */
4203 name_len *= 2;
4204 } else { /* BB improve the check for buffer overruns BB */
4205 name_len = strnlen(fileName, PATH_MAX);
4206 name_len++; /* trailing null */
4207 strncpy(pSMB->FileName, fileName, name_len);
4210 params = 6 + name_len;
4212 /* done calculating parms using name_len of file name,
4213 now use name_len to calculate length of ea name
4214 we are going to create in the inode xattrs */
4215 if(ea_name == NULL)
4216 name_len = 0;
4217 else
4218 name_len = strnlen(ea_name,255);
4220 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4221 pSMB->MaxParameterCount = cpu_to_le16(2);
4222 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4223 pSMB->MaxSetupCount = 0;
4224 pSMB->Reserved = 0;
4225 pSMB->Flags = 0;
4226 pSMB->Timeout = 0;
4227 pSMB->Reserved2 = 0;
4228 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4229 InformationLevel) - 4;
4230 offset = param_offset + params;
4231 pSMB->InformationLevel =
4232 cpu_to_le16(SMB_SET_FILE_EA);
4234 parm_data =
4235 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4236 offset);
4237 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4238 pSMB->DataOffset = cpu_to_le16(offset);
4239 pSMB->SetupCount = 1;
4240 pSMB->Reserved3 = 0;
4241 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4242 byte_count = 3 /* pad */ + params + count;
4243 pSMB->DataCount = cpu_to_le16(count);
4244 parm_data->list_len = cpu_to_le32(count);
4245 parm_data->list[0].EA_flags = 0;
4246 /* we checked above that name len is less than 255 */
4247 parm_data->list[0].name_len = (__u8)name_len;;
4248 /* EA names are always ASCII */
4249 if(ea_name)
4250 strncpy(parm_data->list[0].name,ea_name,name_len);
4251 parm_data->list[0].name[name_len] = 0;
4252 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4253 /* caller ensures that ea_value_len is less than 64K but
4254 we need to ensure that it fits within the smb */
4256 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4257 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4258 if(ea_value_len)
4259 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4261 pSMB->TotalDataCount = pSMB->DataCount;
4262 pSMB->ParameterCount = cpu_to_le16(params);
4263 pSMB->TotalParameterCount = pSMB->ParameterCount;
4264 pSMB->Reserved4 = 0;
4265 pSMB->hdr.smb_buf_length += byte_count;
4266 pSMB->ByteCount = cpu_to_le16(byte_count);
4267 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4268 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4269 if (rc) {
4270 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4273 cifs_buf_release(pSMB);
4275 if (rc == -EAGAIN)
4276 goto SetEARetry;
4278 return rc;
4281 #endif