Linux v2.6.15-rc7
[pohmelfs.git] / fs / cifs / cifssmb.c
blob6867e556d37e51485a4e9d35fb7ea332fc971b6d
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->tidStatus == CifsExiting) {
94 /* only tree disconnect, open, and write,
95 (and ulogoff which does not have tcon)
96 are allowed as we start force umount */
97 if((smb_command != SMB_COM_WRITE_ANDX) &&
98 (smb_command != SMB_COM_OPEN_ANDX) &&
99 (smb_command != SMB_COM_TREE_DISCONNECT)) {
100 cFYI(1,("can not send cmd %d while umounting",
101 smb_command));
102 return -ENODEV;
105 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
106 (tcon->ses->server)){
107 struct nls_table *nls_codepage;
108 /* Give Demultiplex thread up to 10 seconds to
109 reconnect, should be greater than cifs socket
110 timeout which is 7 seconds */
111 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
112 wait_event_interruptible_timeout(tcon->ses->server->response_q,
113 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
114 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
115 /* on "soft" mounts we wait once */
116 if((tcon->retry == FALSE) ||
117 (tcon->ses->status == CifsExiting)) {
118 cFYI(1,("gave up waiting on reconnect in smb_init"));
119 return -EHOSTDOWN;
120 } /* else "hard" mount - keep retrying
121 until process is killed or server
122 comes back on-line */
123 } else /* TCP session is reestablished now */
124 break;
128 nls_codepage = load_nls_default();
129 /* need to prevent multiple threads trying to
130 simultaneously reconnect the same SMB session */
131 down(&tcon->ses->sesSem);
132 if(tcon->ses->status == CifsNeedReconnect)
133 rc = cifs_setup_session(0, tcon->ses,
134 nls_codepage);
135 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
136 mark_open_files_invalid(tcon);
137 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
138 , nls_codepage);
139 up(&tcon->ses->sesSem);
140 /* BB FIXME add code to check if wsize needs
141 update due to negotiated smb buffer size
142 shrinking */
143 if(rc == 0)
144 atomic_inc(&tconInfoReconnectCount);
146 cFYI(1, ("reconnect tcon rc = %d", rc));
147 /* Removed call to reopen open files here -
148 it is safer (and faster) to reopen files
149 one at a time as needed in read and write */
151 /* Check if handle based operation so we
152 know whether we can continue or not without
153 returning to caller to reset file handle */
154 switch(smb_command) {
155 case SMB_COM_READ_ANDX:
156 case SMB_COM_WRITE_ANDX:
157 case SMB_COM_CLOSE:
158 case SMB_COM_FIND_CLOSE2:
159 case SMB_COM_LOCKING_ANDX: {
160 unload_nls(nls_codepage);
161 return -EAGAIN;
164 } else {
165 up(&tcon->ses->sesSem);
167 unload_nls(nls_codepage);
169 } else {
170 return -EIO;
173 if(rc)
174 return rc;
176 *request_buf = cifs_small_buf_get();
177 if (*request_buf == NULL) {
178 /* BB should we add a retry in here if not a writepage? */
179 return -ENOMEM;
182 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
184 if(tcon != NULL)
185 cifs_stats_inc(&tcon->num_smbs_sent);
187 return rc;
190 /* If the return code is zero, this function must fill in request_buf pointer */
191 static int
192 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
193 void **request_buf /* returned */ ,
194 void **response_buf /* returned */ )
196 int rc = 0;
198 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
199 check for tcp and smb session status done differently
200 for those three - in the calling routine */
201 if(tcon) {
202 if(tcon->tidStatus == CifsExiting) {
203 /* only tree disconnect, open, and write,
204 (and ulogoff which does not have tcon)
205 are allowed as we start force umount */
206 if((smb_command != SMB_COM_WRITE_ANDX) &&
207 (smb_command != SMB_COM_OPEN_ANDX) &&
208 (smb_command != SMB_COM_TREE_DISCONNECT)) {
209 cFYI(1,("can not send cmd %d while umounting",
210 smb_command));
211 return -ENODEV;
215 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
216 (tcon->ses->server)){
217 struct nls_table *nls_codepage;
218 /* Give Demultiplex thread up to 10 seconds to
219 reconnect, should be greater than cifs socket
220 timeout which is 7 seconds */
221 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
222 wait_event_interruptible_timeout(tcon->ses->server->response_q,
223 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
224 if(tcon->ses->server->tcpStatus ==
225 CifsNeedReconnect) {
226 /* on "soft" mounts we wait once */
227 if((tcon->retry == FALSE) ||
228 (tcon->ses->status == CifsExiting)) {
229 cFYI(1,("gave up waiting on reconnect in smb_init"));
230 return -EHOSTDOWN;
231 } /* else "hard" mount - keep retrying
232 until process is killed or server
233 comes on-line */
234 } else /* TCP session is reestablished now */
235 break;
239 nls_codepage = load_nls_default();
240 /* need to prevent multiple threads trying to
241 simultaneously reconnect the same SMB session */
242 down(&tcon->ses->sesSem);
243 if(tcon->ses->status == CifsNeedReconnect)
244 rc = cifs_setup_session(0, tcon->ses,
245 nls_codepage);
246 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
247 mark_open_files_invalid(tcon);
248 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
249 tcon, nls_codepage);
250 up(&tcon->ses->sesSem);
251 /* BB FIXME add code to check if wsize needs
252 update due to negotiated smb buffer size
253 shrinking */
254 if(rc == 0)
255 atomic_inc(&tconInfoReconnectCount);
257 cFYI(1, ("reconnect tcon rc = %d", rc));
258 /* Removed call to reopen open files here -
259 it is safer (and faster) to reopen files
260 one at a time as needed in read and write */
262 /* Check if handle based operation so we
263 know whether we can continue or not without
264 returning to caller to reset file handle */
265 switch(smb_command) {
266 case SMB_COM_READ_ANDX:
267 case SMB_COM_WRITE_ANDX:
268 case SMB_COM_CLOSE:
269 case SMB_COM_FIND_CLOSE2:
270 case SMB_COM_LOCKING_ANDX: {
271 unload_nls(nls_codepage);
272 return -EAGAIN;
275 } else {
276 up(&tcon->ses->sesSem);
278 unload_nls(nls_codepage);
280 } else {
281 return -EIO;
284 if(rc)
285 return rc;
287 *request_buf = cifs_buf_get();
288 if (*request_buf == NULL) {
289 /* BB should we add a retry in here if not a writepage? */
290 return -ENOMEM;
292 /* Although the original thought was we needed the response buf for */
293 /* potential retries of smb operations it turns out we can determine */
294 /* from the mid flags when the request buffer can be resent without */
295 /* having to use a second distinct buffer for the response */
296 *response_buf = *request_buf;
298 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
299 wct /*wct */ );
301 if(tcon != NULL)
302 cifs_stats_inc(&tcon->num_smbs_sent);
304 return rc;
307 static int validate_t2(struct smb_t2_rsp * pSMB)
309 int rc = -EINVAL;
310 int total_size;
311 char * pBCC;
313 /* check for plausible wct, bcc and t2 data and parm sizes */
314 /* check for parm and data offset going beyond end of smb */
315 if(pSMB->hdr.WordCount >= 10) {
316 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
317 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
318 /* check that bcc is at least as big as parms + data */
319 /* check that bcc is less than negotiated smb buffer */
320 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
321 if(total_size < 512) {
322 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
323 /* BCC le converted in SendReceive */
324 pBCC = (pSMB->hdr.WordCount * 2) +
325 sizeof(struct smb_hdr) +
326 (char *)pSMB;
327 if((total_size <= (*(u16 *)pBCC)) &&
328 (total_size <
329 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
330 return 0;
336 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
337 sizeof(struct smb_t2_rsp) + 16);
338 return rc;
341 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
343 NEGOTIATE_REQ *pSMB;
344 NEGOTIATE_RSP *pSMBr;
345 int rc = 0;
346 int bytes_returned;
347 struct TCP_Server_Info * server;
348 u16 count;
350 if(ses->server)
351 server = ses->server;
352 else {
353 rc = -EIO;
354 return rc;
356 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
357 (void **) &pSMB, (void **) &pSMBr);
358 if (rc)
359 return rc;
360 pSMB->hdr.Mid = GetNextMid(server);
361 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
362 if (extended_security)
363 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
365 count = strlen(protocols[0].name) + 1;
366 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
367 /* null guaranteed to be at end of source and target buffers anyway */
369 pSMB->hdr.smb_buf_length += count;
370 pSMB->ByteCount = cpu_to_le16(count);
372 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
373 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
374 if (rc == 0) {
375 server->secMode = pSMBr->SecurityMode;
376 server->secType = NTLM; /* BB override default for
377 NTLMv2 or kerberos v5 */
378 /* one byte - no need to convert this or EncryptionKeyLen
379 from little endian */
380 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
381 /* probably no need to store and check maxvcs */
382 server->maxBuf =
383 min(le32_to_cpu(pSMBr->MaxBufferSize),
384 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
385 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
386 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
387 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
388 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
389 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
390 /* BB with UTC do we ever need to be using srvr timezone? */
391 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
392 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
393 CIFS_CRYPTO_KEY_SIZE);
394 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
395 && (pSMBr->EncryptionKeyLength == 0)) {
396 /* decode security blob */
397 } else
398 rc = -EIO;
400 /* BB might be helpful to save off the domain of server here */
402 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
403 (server->capabilities & CAP_EXTENDED_SECURITY)) {
404 count = pSMBr->ByteCount;
405 if (count < 16)
406 rc = -EIO;
407 else if (count == 16) {
408 server->secType = RawNTLMSSP;
409 if (server->socketUseCount.counter > 1) {
410 if (memcmp
411 (server->server_GUID,
412 pSMBr->u.extended_response.
413 GUID, 16) != 0) {
414 cFYI(1,
415 ("UID of server does not match previous connection to same ip address"));
416 memcpy(server->
417 server_GUID,
418 pSMBr->u.
419 extended_response.
420 GUID, 16);
422 } else
423 memcpy(server->server_GUID,
424 pSMBr->u.extended_response.
425 GUID, 16);
426 } else {
427 rc = decode_negTokenInit(pSMBr->u.
428 extended_response.
429 SecurityBlob,
430 count - 16,
431 &server->secType);
432 if(rc == 1) {
433 /* BB Need to fill struct for sessetup here */
434 rc = -EOPNOTSUPP;
435 } else {
436 rc = -EINVAL;
439 } else
440 server->capabilities &= ~CAP_EXTENDED_SECURITY;
441 if(sign_CIFS_PDUs == FALSE) {
442 if(server->secMode & SECMODE_SIGN_REQUIRED)
443 cERROR(1,
444 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
445 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
446 } else if(sign_CIFS_PDUs == 1) {
447 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
448 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
453 cifs_buf_release(pSMB);
454 return rc;
458 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
460 struct smb_hdr *smb_buffer;
461 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
462 int rc = 0;
463 int length;
465 cFYI(1, ("In tree disconnect"));
467 * If last user of the connection and
468 * connection alive - disconnect it
469 * If this is the last connection on the server session disconnect it
470 * (and inside session disconnect we should check if tcp socket needs
471 * to be freed and kernel thread woken up).
473 if (tcon)
474 down(&tcon->tconSem);
475 else
476 return -EIO;
478 atomic_dec(&tcon->useCount);
479 if (atomic_read(&tcon->useCount) > 0) {
480 up(&tcon->tconSem);
481 return -EBUSY;
484 /* No need to return error on this operation if tid invalidated and
485 closed on server already e.g. due to tcp session crashing */
486 if(tcon->tidStatus == CifsNeedReconnect) {
487 up(&tcon->tconSem);
488 return 0;
491 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
492 up(&tcon->tconSem);
493 return -EIO;
495 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
496 (void **)&smb_buffer);
497 if (rc) {
498 up(&tcon->tconSem);
499 return rc;
500 } else {
501 smb_buffer_response = smb_buffer; /* BB removeme BB */
503 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
504 &length, 0);
505 if (rc)
506 cFYI(1, ("Tree disconnect failed %d", rc));
508 if (smb_buffer)
509 cifs_small_buf_release(smb_buffer);
510 up(&tcon->tconSem);
512 /* No need to return error on this operation if tid invalidated and
513 closed on server already e.g. due to tcp session crashing */
514 if (rc == -EAGAIN)
515 rc = 0;
517 return rc;
521 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
523 struct smb_hdr *smb_buffer_response;
524 LOGOFF_ANDX_REQ *pSMB;
525 int rc = 0;
526 int length;
528 cFYI(1, ("In SMBLogoff for session disconnect"));
529 if (ses)
530 down(&ses->sesSem);
531 else
532 return -EIO;
534 atomic_dec(&ses->inUse);
535 if (atomic_read(&ses->inUse) > 0) {
536 up(&ses->sesSem);
537 return -EBUSY;
539 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
540 if (rc) {
541 up(&ses->sesSem);
542 return rc;
545 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
547 if(ses->server) {
548 pSMB->hdr.Mid = GetNextMid(ses->server);
550 if(ses->server->secMode &
551 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
552 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
555 pSMB->hdr.Uid = ses->Suid;
557 pSMB->AndXCommand = 0xFF;
558 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
559 smb_buffer_response, &length, 0);
560 if (ses->server) {
561 atomic_dec(&ses->server->socketUseCount);
562 if (atomic_read(&ses->server->socketUseCount) == 0) {
563 spin_lock(&GlobalMid_Lock);
564 ses->server->tcpStatus = CifsExiting;
565 spin_unlock(&GlobalMid_Lock);
566 rc = -ESHUTDOWN;
569 up(&ses->sesSem);
570 cifs_small_buf_release(pSMB);
572 /* if session dead then we do not need to do ulogoff,
573 since server closed smb session, no sense reporting
574 error */
575 if (rc == -EAGAIN)
576 rc = 0;
577 return rc;
581 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
582 const struct nls_table *nls_codepage, int remap)
584 DELETE_FILE_REQ *pSMB = NULL;
585 DELETE_FILE_RSP *pSMBr = NULL;
586 int rc = 0;
587 int bytes_returned;
588 int name_len;
590 DelFileRetry:
591 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
592 (void **) &pSMBr);
593 if (rc)
594 return rc;
596 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
597 name_len =
598 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
599 PATH_MAX, nls_codepage, remap);
600 name_len++; /* trailing null */
601 name_len *= 2;
602 } else { /* BB improve check for buffer overruns BB */
603 name_len = strnlen(fileName, PATH_MAX);
604 name_len++; /* trailing null */
605 strncpy(pSMB->fileName, fileName, name_len);
607 pSMB->SearchAttributes =
608 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
609 pSMB->BufferFormat = 0x04;
610 pSMB->hdr.smb_buf_length += name_len + 1;
611 pSMB->ByteCount = cpu_to_le16(name_len + 1);
612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
614 cifs_stats_inc(&tcon->num_deletes);
615 if (rc) {
616 cFYI(1, ("Error in RMFile = %d", rc));
619 cifs_buf_release(pSMB);
620 if (rc == -EAGAIN)
621 goto DelFileRetry;
623 return rc;
627 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
628 const struct nls_table *nls_codepage, int remap)
630 DELETE_DIRECTORY_REQ *pSMB = NULL;
631 DELETE_DIRECTORY_RSP *pSMBr = NULL;
632 int rc = 0;
633 int bytes_returned;
634 int name_len;
636 cFYI(1, ("In CIFSSMBRmDir"));
637 RmDirRetry:
638 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
639 (void **) &pSMBr);
640 if (rc)
641 return rc;
643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
644 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
645 PATH_MAX, nls_codepage, remap);
646 name_len++; /* trailing null */
647 name_len *= 2;
648 } else { /* BB improve check for buffer overruns BB */
649 name_len = strnlen(dirName, PATH_MAX);
650 name_len++; /* trailing null */
651 strncpy(pSMB->DirName, dirName, name_len);
654 pSMB->BufferFormat = 0x04;
655 pSMB->hdr.smb_buf_length += name_len + 1;
656 pSMB->ByteCount = cpu_to_le16(name_len + 1);
657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
659 cifs_stats_inc(&tcon->num_rmdirs);
660 if (rc) {
661 cFYI(1, ("Error in RMDir = %d", rc));
664 cifs_buf_release(pSMB);
665 if (rc == -EAGAIN)
666 goto RmDirRetry;
667 return rc;
671 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
672 const char *name, const struct nls_table *nls_codepage, int remap)
674 int rc = 0;
675 CREATE_DIRECTORY_REQ *pSMB = NULL;
676 CREATE_DIRECTORY_RSP *pSMBr = NULL;
677 int bytes_returned;
678 int name_len;
680 cFYI(1, ("In CIFSSMBMkDir"));
681 MkDirRetry:
682 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
683 (void **) &pSMBr);
684 if (rc)
685 return rc;
687 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
688 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
689 PATH_MAX, nls_codepage, remap);
690 name_len++; /* trailing null */
691 name_len *= 2;
692 } else { /* BB improve check for buffer overruns BB */
693 name_len = strnlen(name, PATH_MAX);
694 name_len++; /* trailing null */
695 strncpy(pSMB->DirName, name, name_len);
698 pSMB->BufferFormat = 0x04;
699 pSMB->hdr.smb_buf_length += name_len + 1;
700 pSMB->ByteCount = cpu_to_le16(name_len + 1);
701 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
703 cifs_stats_inc(&tcon->num_mkdirs);
704 if (rc) {
705 cFYI(1, ("Error in Mkdir = %d", rc));
708 cifs_buf_release(pSMB);
709 if (rc == -EAGAIN)
710 goto MkDirRetry;
711 return rc;
714 static __u16 convert_disposition(int disposition)
716 __u16 ofun = 0;
718 switch (disposition) {
719 case FILE_SUPERSEDE:
720 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
721 break;
722 case FILE_OPEN:
723 ofun = SMBOPEN_OAPPEND;
724 break;
725 case FILE_CREATE:
726 ofun = SMBOPEN_OCREATE;
727 break;
728 case FILE_OPEN_IF:
729 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
730 break;
731 case FILE_OVERWRITE:
732 ofun = SMBOPEN_OTRUNC;
733 break;
734 case FILE_OVERWRITE_IF:
735 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
736 break;
737 default:
738 cFYI(1,("unknown disposition %d",disposition));
739 ofun = SMBOPEN_OAPPEND; /* regular open */
741 return ofun;
745 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
746 const char *fileName, const int openDisposition,
747 const int access_flags, const int create_options, __u16 * netfid,
748 int *pOplock, FILE_ALL_INFO * pfile_info,
749 const struct nls_table *nls_codepage, int remap)
751 int rc = -EACCES;
752 OPENX_REQ *pSMB = NULL;
753 OPENX_RSP *pSMBr = NULL;
754 int bytes_returned;
755 int name_len;
756 __u16 count;
758 OldOpenRetry:
759 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
760 (void **) &pSMBr);
761 if (rc)
762 return rc;
764 pSMB->AndXCommand = 0xFF; /* none */
766 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
767 count = 1; /* account for one byte pad to word boundary */
768 name_len =
769 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
770 fileName, PATH_MAX, nls_codepage, remap);
771 name_len++; /* trailing null */
772 name_len *= 2;
773 } else { /* BB improve check for buffer overruns BB */
774 count = 0; /* no pad */
775 name_len = strnlen(fileName, PATH_MAX);
776 name_len++; /* trailing null */
777 strncpy(pSMB->fileName, fileName, name_len);
779 if (*pOplock & REQ_OPLOCK)
780 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
781 else if (*pOplock & REQ_BATCHOPLOCK) {
782 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
784 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
785 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
786 /* 0 = read
787 1 = write
788 2 = rw
789 3 = execute
791 pSMB->Mode = cpu_to_le16(2);
792 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
793 /* set file as system file if special file such
794 as fifo and server expecting SFU style and
795 no Unix extensions */
797 if(create_options & CREATE_OPTION_SPECIAL)
798 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
799 else
800 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
802 /* if ((omode & S_IWUGO) == 0)
803 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
804 /* Above line causes problems due to vfs splitting create into two
805 pieces - need to set mode after file created not while it is
806 being created */
808 /* BB FIXME BB */
809 /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
810 /* BB FIXME END BB */
812 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
813 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
814 count += name_len;
815 pSMB->hdr.smb_buf_length += count;
817 pSMB->ByteCount = cpu_to_le16(count);
818 /* long_op set to 1 to allow for oplock break timeouts */
819 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
820 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
821 cifs_stats_inc(&tcon->num_opens);
822 if (rc) {
823 cFYI(1, ("Error in Open = %d", rc));
824 } else {
825 /* BB verify if wct == 15 */
827 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
829 *netfid = pSMBr->Fid; /* cifs fid stays in le */
830 /* Let caller know file was created so we can set the mode. */
831 /* Do we care about the CreateAction in any other cases? */
832 /* BB FIXME BB */
833 /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
834 *pOplock |= CIFS_CREATE_ACTION; */
835 /* BB FIXME END */
837 if(pfile_info) {
838 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
839 pfile_info->LastAccessTime = 0; /* BB fixme */
840 pfile_info->LastWriteTime = 0; /* BB fixme */
841 pfile_info->ChangeTime = 0; /* BB fixme */
842 pfile_info->Attributes =
843 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
844 /* the file_info buf is endian converted by caller */
845 pfile_info->AllocationSize =
846 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
847 pfile_info->EndOfFile = pfile_info->AllocationSize;
848 pfile_info->NumberOfLinks = cpu_to_le32(1);
852 cifs_buf_release(pSMB);
853 if (rc == -EAGAIN)
854 goto OldOpenRetry;
855 return rc;
859 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
860 const char *fileName, const int openDisposition,
861 const int access_flags, const int create_options, __u16 * netfid,
862 int *pOplock, FILE_ALL_INFO * pfile_info,
863 const struct nls_table *nls_codepage, int remap)
865 int rc = -EACCES;
866 OPEN_REQ *pSMB = NULL;
867 OPEN_RSP *pSMBr = NULL;
868 int bytes_returned;
869 int name_len;
870 __u16 count;
872 openRetry:
873 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
874 (void **) &pSMBr);
875 if (rc)
876 return rc;
878 pSMB->AndXCommand = 0xFF; /* none */
880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
881 count = 1; /* account for one byte pad to word boundary */
882 name_len =
883 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
884 fileName, PATH_MAX, nls_codepage, remap);
885 name_len++; /* trailing null */
886 name_len *= 2;
887 pSMB->NameLength = cpu_to_le16(name_len);
888 } else { /* BB improve check for buffer overruns BB */
889 count = 0; /* no pad */
890 name_len = strnlen(fileName, PATH_MAX);
891 name_len++; /* trailing null */
892 pSMB->NameLength = cpu_to_le16(name_len);
893 strncpy(pSMB->fileName, fileName, name_len);
895 if (*pOplock & REQ_OPLOCK)
896 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
897 else if (*pOplock & REQ_BATCHOPLOCK) {
898 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
900 pSMB->DesiredAccess = cpu_to_le32(access_flags);
901 pSMB->AllocationSize = 0;
902 /* set file as system file if special file such
903 as fifo and server expecting SFU style and
904 no Unix extensions */
905 if(create_options & CREATE_OPTION_SPECIAL)
906 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
907 else
908 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
909 /* XP does not handle ATTR_POSIX_SEMANTICS */
910 /* but it helps speed up case sensitive checks for other
911 servers such as Samba */
912 if (tcon->ses->capabilities & CAP_UNIX)
913 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
915 /* if ((omode & S_IWUGO) == 0)
916 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
917 /* Above line causes problems due to vfs splitting create into two
918 pieces - need to set mode after file created not while it is
919 being created */
920 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
921 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
922 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
923 /* BB Expirement with various impersonation levels and verify */
924 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
925 pSMB->SecurityFlags =
926 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
928 count += name_len;
929 pSMB->hdr.smb_buf_length += count;
931 pSMB->ByteCount = cpu_to_le16(count);
932 /* long_op set to 1 to allow for oplock break timeouts */
933 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
934 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
935 cifs_stats_inc(&tcon->num_opens);
936 if (rc) {
937 cFYI(1, ("Error in Open = %d", rc));
938 } else {
939 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
940 *netfid = pSMBr->Fid; /* cifs fid stays in le */
941 /* Let caller know file was created so we can set the mode. */
942 /* Do we care about the CreateAction in any other cases? */
943 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
944 *pOplock |= CIFS_CREATE_ACTION;
945 if(pfile_info) {
946 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
947 36 /* CreationTime to Attributes */);
948 /* the file_info buf is endian converted by caller */
949 pfile_info->AllocationSize = pSMBr->AllocationSize;
950 pfile_info->EndOfFile = pSMBr->EndOfFile;
951 pfile_info->NumberOfLinks = cpu_to_le32(1);
955 cifs_buf_release(pSMB);
956 if (rc == -EAGAIN)
957 goto openRetry;
958 return rc;
961 /* If no buffer passed in, then caller wants to do the copy
962 as in the case of readpages so the SMB buffer must be
963 freed by the caller */
966 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
967 const int netfid, const unsigned int count,
968 const __u64 lseek, unsigned int *nbytes, char **buf)
970 int rc = -EACCES;
971 READ_REQ *pSMB = NULL;
972 READ_RSP *pSMBr = NULL;
973 char *pReadData = NULL;
974 int bytes_returned;
975 int wct;
977 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
978 if(tcon->ses->capabilities & CAP_LARGE_FILES)
979 wct = 12;
980 else
981 wct = 10; /* old style read */
983 *nbytes = 0;
984 rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
985 (void **) &pSMBr);
986 if (rc)
987 return rc;
989 /* tcon and ses pointer are checked in smb_init */
990 if (tcon->ses->server == NULL)
991 return -ECONNABORTED;
993 pSMB->AndXCommand = 0xFF; /* none */
994 pSMB->Fid = netfid;
995 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
996 if(wct == 12)
997 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
998 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
999 return -EIO;
1001 pSMB->Remaining = 0;
1002 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1003 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1004 if(wct == 12)
1005 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1006 else {
1007 /* old style read */
1008 struct smb_com_readx_req * pSMBW =
1009 (struct smb_com_readx_req *)pSMB;
1010 pSMBW->ByteCount = 0;
1013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1014 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1015 cifs_stats_inc(&tcon->num_reads);
1016 if (rc) {
1017 cERROR(1, ("Send error in read = %d", rc));
1018 } else {
1019 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1020 data_length = data_length << 16;
1021 data_length += le16_to_cpu(pSMBr->DataLength);
1022 *nbytes = data_length;
1024 /*check that DataLength would not go beyond end of SMB */
1025 if ((data_length > CIFSMaxBufSize)
1026 || (data_length > count)) {
1027 cFYI(1,("bad length %d for count %d",data_length,count));
1028 rc = -EIO;
1029 *nbytes = 0;
1030 } else {
1031 pReadData =
1032 (char *) (&pSMBr->hdr.Protocol) +
1033 le16_to_cpu(pSMBr->DataOffset);
1034 /* if(rc = copy_to_user(buf, pReadData, data_length)) {
1035 cERROR(1,("Faulting on read rc = %d",rc));
1036 rc = -EFAULT;
1037 }*/ /* can not use copy_to_user when using page cache*/
1038 if(*buf)
1039 memcpy(*buf,pReadData,data_length);
1042 if(*buf)
1043 cifs_buf_release(pSMB);
1044 else
1045 *buf = (char *)pSMB;
1047 /* Note: On -EAGAIN error only caller can retry on handle based calls
1048 since file handle passed in no longer valid */
1049 return rc;
1053 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1054 const int netfid, const unsigned int count,
1055 const __u64 offset, unsigned int *nbytes, const char *buf,
1056 const char __user * ubuf, const int long_op)
1058 int rc = -EACCES;
1059 WRITE_REQ *pSMB = NULL;
1060 WRITE_RSP *pSMBr = NULL;
1061 int bytes_returned, wct;
1062 __u32 bytes_sent;
1063 __u16 byte_count;
1065 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1066 if(tcon->ses == NULL)
1067 return -ECONNABORTED;
1069 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1070 wct = 14;
1071 else
1072 wct = 12;
1074 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1075 (void **) &pSMBr);
1076 if (rc)
1077 return rc;
1078 /* tcon and ses pointer are checked in smb_init */
1079 if (tcon->ses->server == NULL)
1080 return -ECONNABORTED;
1082 pSMB->AndXCommand = 0xFF; /* none */
1083 pSMB->Fid = netfid;
1084 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1085 if(wct == 14)
1086 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1087 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1088 return -EIO;
1090 pSMB->Reserved = 0xFFFFFFFF;
1091 pSMB->WriteMode = 0;
1092 pSMB->Remaining = 0;
1094 /* Can increase buffer size if buffer is big enough in some cases - ie we
1095 can send more if LARGE_WRITE_X capability returned by the server and if
1096 our buffer is big enough or if we convert to iovecs on socket writes
1097 and eliminate the copy to the CIFS buffer */
1098 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1099 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1100 } else {
1101 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1102 & ~0xFF;
1105 if (bytes_sent > count)
1106 bytes_sent = count;
1107 pSMB->DataOffset =
1108 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1109 if(buf)
1110 memcpy(pSMB->Data,buf,bytes_sent);
1111 else if(ubuf) {
1112 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1113 cifs_buf_release(pSMB);
1114 return -EFAULT;
1116 } else if (count != 0) {
1117 /* No buffer */
1118 cifs_buf_release(pSMB);
1119 return -EINVAL;
1120 } /* else setting file size with write of zero bytes */
1121 if(wct == 14)
1122 byte_count = bytes_sent + 1; /* pad */
1123 else /* wct == 12 */ {
1124 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1126 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1127 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1128 pSMB->hdr.smb_buf_length += byte_count;
1130 if(wct == 14)
1131 pSMB->ByteCount = cpu_to_le16(byte_count);
1132 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
1133 struct smb_com_writex_req * pSMBW =
1134 (struct smb_com_writex_req *)pSMB;
1135 pSMBW->ByteCount = cpu_to_le16(byte_count);
1138 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1139 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1140 cifs_stats_inc(&tcon->num_writes);
1141 if (rc) {
1142 cFYI(1, ("Send error in write = %d", rc));
1143 *nbytes = 0;
1144 } else {
1145 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1146 *nbytes = (*nbytes) << 16;
1147 *nbytes += le16_to_cpu(pSMBr->Count);
1150 cifs_buf_release(pSMB);
1152 /* Note: On -EAGAIN error only caller can retry on handle based calls
1153 since file handle passed in no longer valid */
1155 return rc;
1158 #ifdef CONFIG_CIFS_EXPERIMENTAL
1160 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1161 const int netfid, const unsigned int count,
1162 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1163 int n_vec, const int long_op)
1165 int rc = -EACCES;
1166 WRITE_REQ *pSMB = NULL;
1167 int bytes_returned, wct;
1168 int smb_hdr_len;
1170 /* BB removeme BB */
1171 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1173 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1174 wct = 14;
1175 else
1176 wct = 12;
1177 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1178 if (rc)
1179 return rc;
1180 /* tcon and ses pointer are checked in smb_init */
1181 if (tcon->ses->server == NULL)
1182 return -ECONNABORTED;
1184 pSMB->AndXCommand = 0xFF; /* none */
1185 pSMB->Fid = netfid;
1186 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1187 if(wct == 14)
1188 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1189 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1190 return -EIO;
1191 pSMB->Reserved = 0xFFFFFFFF;
1192 pSMB->WriteMode = 0;
1193 pSMB->Remaining = 0;
1195 pSMB->DataOffset =
1196 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1198 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1199 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1200 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1201 if(wct == 14)
1202 pSMB->hdr.smb_buf_length += count+1;
1203 else /* wct == 12 */
1204 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1205 if(wct == 14)
1206 pSMB->ByteCount = cpu_to_le16(count + 1);
1207 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1208 struct smb_com_writex_req * pSMBW =
1209 (struct smb_com_writex_req *)pSMB;
1210 pSMBW->ByteCount = cpu_to_le16(count + 5);
1212 iov[0].iov_base = pSMB;
1213 iov[0].iov_len = smb_hdr_len + 4;
1215 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned,
1216 long_op);
1217 cifs_stats_inc(&tcon->num_writes);
1218 if (rc) {
1219 cFYI(1, ("Send error Write2 = %d", rc));
1220 *nbytes = 0;
1221 } else {
1222 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1223 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1224 *nbytes = (*nbytes) << 16;
1225 *nbytes += le16_to_cpu(pSMBr->Count);
1228 cifs_small_buf_release(pSMB);
1230 /* Note: On -EAGAIN error only caller can retry on handle based calls
1231 since file handle passed in no longer valid */
1233 return rc;
1237 #endif /* CIFS_EXPERIMENTAL */
1240 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1241 const __u16 smb_file_id, const __u64 len,
1242 const __u64 offset, const __u32 numUnlock,
1243 const __u32 numLock, const __u8 lockType, const int waitFlag)
1245 int rc = 0;
1246 LOCK_REQ *pSMB = NULL;
1247 LOCK_RSP *pSMBr = NULL;
1248 int bytes_returned;
1249 int timeout = 0;
1250 __u16 count;
1252 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1253 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1255 if (rc)
1256 return rc;
1258 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1260 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1261 timeout = -1; /* no response expected */
1262 pSMB->Timeout = 0;
1263 } else if (waitFlag == TRUE) {
1264 timeout = 3; /* blocking operation, no timeout */
1265 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1266 } else {
1267 pSMB->Timeout = 0;
1270 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1271 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1272 pSMB->LockType = lockType;
1273 pSMB->AndXCommand = 0xFF; /* none */
1274 pSMB->Fid = smb_file_id; /* netfid stays le */
1276 if((numLock != 0) || (numUnlock != 0)) {
1277 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1278 /* BB where to store pid high? */
1279 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1280 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1281 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1282 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1283 count = sizeof(LOCKING_ANDX_RANGE);
1284 } else {
1285 /* oplock break */
1286 count = 0;
1288 pSMB->hdr.smb_buf_length += count;
1289 pSMB->ByteCount = cpu_to_le16(count);
1291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1292 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1293 cifs_stats_inc(&tcon->num_locks);
1294 if (rc) {
1295 cFYI(1, ("Send error in Lock = %d", rc));
1297 cifs_small_buf_release(pSMB);
1299 /* Note: On -EAGAIN error only caller can retry on handle based calls
1300 since file handle passed in no longer valid */
1301 return rc;
1305 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1307 int rc = 0;
1308 CLOSE_REQ *pSMB = NULL;
1309 CLOSE_RSP *pSMBr = NULL;
1310 int bytes_returned;
1311 cFYI(1, ("In CIFSSMBClose"));
1313 /* do not retry on dead session on close */
1314 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1315 if(rc == -EAGAIN)
1316 return 0;
1317 if (rc)
1318 return rc;
1320 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1322 pSMB->FileID = (__u16) smb_file_id;
1323 pSMB->LastWriteTime = 0;
1324 pSMB->ByteCount = 0;
1325 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1326 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1327 cifs_stats_inc(&tcon->num_closes);
1328 if (rc) {
1329 if(rc!=-EINTR) {
1330 /* EINTR is expected when user ctl-c to kill app */
1331 cERROR(1, ("Send error in Close = %d", rc));
1335 cifs_small_buf_release(pSMB);
1337 /* Since session is dead, file will be closed on server already */
1338 if(rc == -EAGAIN)
1339 rc = 0;
1341 return rc;
1345 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1346 const char *fromName, const char *toName,
1347 const struct nls_table *nls_codepage, int remap)
1349 int rc = 0;
1350 RENAME_REQ *pSMB = NULL;
1351 RENAME_RSP *pSMBr = NULL;
1352 int bytes_returned;
1353 int name_len, name_len2;
1354 __u16 count;
1356 cFYI(1, ("In CIFSSMBRename"));
1357 renameRetry:
1358 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1359 (void **) &pSMBr);
1360 if (rc)
1361 return rc;
1363 pSMB->BufferFormat = 0x04;
1364 pSMB->SearchAttributes =
1365 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1366 ATTR_DIRECTORY);
1368 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1369 name_len =
1370 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1371 PATH_MAX, nls_codepage, remap);
1372 name_len++; /* trailing null */
1373 name_len *= 2;
1374 pSMB->OldFileName[name_len] = 0x04; /* pad */
1375 /* protocol requires ASCII signature byte on Unicode string */
1376 pSMB->OldFileName[name_len + 1] = 0x00;
1377 name_len2 =
1378 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1379 toName, PATH_MAX, nls_codepage, remap);
1380 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1381 name_len2 *= 2; /* convert to bytes */
1382 } else { /* BB improve the check for buffer overruns BB */
1383 name_len = strnlen(fromName, PATH_MAX);
1384 name_len++; /* trailing null */
1385 strncpy(pSMB->OldFileName, fromName, name_len);
1386 name_len2 = strnlen(toName, PATH_MAX);
1387 name_len2++; /* trailing null */
1388 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1389 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1390 name_len2++; /* trailing null */
1391 name_len2++; /* signature byte */
1394 count = 1 /* 1st signature byte */ + name_len + name_len2;
1395 pSMB->hdr.smb_buf_length += count;
1396 pSMB->ByteCount = cpu_to_le16(count);
1398 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1399 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1400 cifs_stats_inc(&tcon->num_renames);
1401 if (rc) {
1402 cFYI(1, ("Send error in rename = %d", rc));
1405 cifs_buf_release(pSMB);
1407 if (rc == -EAGAIN)
1408 goto renameRetry;
1410 return rc;
1413 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1414 int netfid, char * target_name,
1415 const struct nls_table * nls_codepage, int remap)
1417 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1418 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1419 struct set_file_rename * rename_info;
1420 char *data_offset;
1421 char dummy_string[30];
1422 int rc = 0;
1423 int bytes_returned = 0;
1424 int len_of_str;
1425 __u16 params, param_offset, offset, count, byte_count;
1427 cFYI(1, ("Rename to File by handle"));
1428 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1429 (void **) &pSMBr);
1430 if (rc)
1431 return rc;
1433 params = 6;
1434 pSMB->MaxSetupCount = 0;
1435 pSMB->Reserved = 0;
1436 pSMB->Flags = 0;
1437 pSMB->Timeout = 0;
1438 pSMB->Reserved2 = 0;
1439 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1440 offset = param_offset + params;
1442 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1443 rename_info = (struct set_file_rename *) data_offset;
1444 pSMB->MaxParameterCount = cpu_to_le16(2);
1445 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1446 pSMB->SetupCount = 1;
1447 pSMB->Reserved3 = 0;
1448 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1449 byte_count = 3 /* pad */ + params;
1450 pSMB->ParameterCount = cpu_to_le16(params);
1451 pSMB->TotalParameterCount = pSMB->ParameterCount;
1452 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1453 pSMB->DataOffset = cpu_to_le16(offset);
1454 /* construct random name ".cifs_tmp<inodenum><mid>" */
1455 rename_info->overwrite = cpu_to_le32(1);
1456 rename_info->root_fid = 0;
1457 /* unicode only call */
1458 if(target_name == NULL) {
1459 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1460 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1461 dummy_string, 24, nls_codepage, remap);
1462 } else {
1463 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1464 target_name, PATH_MAX, nls_codepage, remap);
1466 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1467 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1468 byte_count += count;
1469 pSMB->DataCount = cpu_to_le16(count);
1470 pSMB->TotalDataCount = pSMB->DataCount;
1471 pSMB->Fid = netfid;
1472 pSMB->InformationLevel =
1473 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1474 pSMB->Reserved4 = 0;
1475 pSMB->hdr.smb_buf_length += byte_count;
1476 pSMB->ByteCount = cpu_to_le16(byte_count);
1477 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1478 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1479 cifs_stats_inc(&pTcon->num_t2renames);
1480 if (rc) {
1481 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1484 cifs_buf_release(pSMB);
1486 /* Note: On -EAGAIN error only caller can retry on handle based calls
1487 since file handle passed in no longer valid */
1489 return rc;
1493 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1494 const __u16 target_tid, const char *toName, const int flags,
1495 const struct nls_table *nls_codepage, int remap)
1497 int rc = 0;
1498 COPY_REQ *pSMB = NULL;
1499 COPY_RSP *pSMBr = NULL;
1500 int bytes_returned;
1501 int name_len, name_len2;
1502 __u16 count;
1504 cFYI(1, ("In CIFSSMBCopy"));
1505 copyRetry:
1506 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1507 (void **) &pSMBr);
1508 if (rc)
1509 return rc;
1511 pSMB->BufferFormat = 0x04;
1512 pSMB->Tid2 = target_tid;
1514 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1516 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1517 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1518 fromName, PATH_MAX, nls_codepage,
1519 remap);
1520 name_len++; /* trailing null */
1521 name_len *= 2;
1522 pSMB->OldFileName[name_len] = 0x04; /* pad */
1523 /* protocol requires ASCII signature byte on Unicode string */
1524 pSMB->OldFileName[name_len + 1] = 0x00;
1525 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1526 toName, PATH_MAX, nls_codepage, remap);
1527 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1528 name_len2 *= 2; /* convert to bytes */
1529 } else { /* BB improve the check for buffer overruns BB */
1530 name_len = strnlen(fromName, PATH_MAX);
1531 name_len++; /* trailing null */
1532 strncpy(pSMB->OldFileName, fromName, name_len);
1533 name_len2 = strnlen(toName, PATH_MAX);
1534 name_len2++; /* trailing null */
1535 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1536 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1537 name_len2++; /* trailing null */
1538 name_len2++; /* signature byte */
1541 count = 1 /* 1st signature byte */ + name_len + name_len2;
1542 pSMB->hdr.smb_buf_length += count;
1543 pSMB->ByteCount = cpu_to_le16(count);
1545 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1546 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1547 if (rc) {
1548 cFYI(1, ("Send error in copy = %d with %d files copied",
1549 rc, le16_to_cpu(pSMBr->CopyCount)));
1551 if (pSMB)
1552 cifs_buf_release(pSMB);
1554 if (rc == -EAGAIN)
1555 goto copyRetry;
1557 return rc;
1561 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1562 const char *fromName, const char *toName,
1563 const struct nls_table *nls_codepage)
1565 TRANSACTION2_SPI_REQ *pSMB = NULL;
1566 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1567 char *data_offset;
1568 int name_len;
1569 int name_len_target;
1570 int rc = 0;
1571 int bytes_returned = 0;
1572 __u16 params, param_offset, offset, byte_count;
1574 cFYI(1, ("In Symlink Unix style"));
1575 createSymLinkRetry:
1576 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1577 (void **) &pSMBr);
1578 if (rc)
1579 return rc;
1581 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1582 name_len =
1583 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1584 /* find define for this maxpathcomponent */
1585 , nls_codepage);
1586 name_len++; /* trailing null */
1587 name_len *= 2;
1589 } else { /* BB improve the check for buffer overruns BB */
1590 name_len = strnlen(fromName, PATH_MAX);
1591 name_len++; /* trailing null */
1592 strncpy(pSMB->FileName, fromName, name_len);
1594 params = 6 + name_len;
1595 pSMB->MaxSetupCount = 0;
1596 pSMB->Reserved = 0;
1597 pSMB->Flags = 0;
1598 pSMB->Timeout = 0;
1599 pSMB->Reserved2 = 0;
1600 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1601 InformationLevel) - 4;
1602 offset = param_offset + params;
1604 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1606 name_len_target =
1607 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1608 /* find define for this maxpathcomponent */
1609 , nls_codepage);
1610 name_len_target++; /* trailing null */
1611 name_len_target *= 2;
1612 } else { /* BB improve the check for buffer overruns BB */
1613 name_len_target = strnlen(toName, PATH_MAX);
1614 name_len_target++; /* trailing null */
1615 strncpy(data_offset, toName, name_len_target);
1618 pSMB->MaxParameterCount = cpu_to_le16(2);
1619 /* BB find exact max on data count below from sess */
1620 pSMB->MaxDataCount = cpu_to_le16(1000);
1621 pSMB->SetupCount = 1;
1622 pSMB->Reserved3 = 0;
1623 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1624 byte_count = 3 /* pad */ + params + name_len_target;
1625 pSMB->DataCount = cpu_to_le16(name_len_target);
1626 pSMB->ParameterCount = cpu_to_le16(params);
1627 pSMB->TotalDataCount = pSMB->DataCount;
1628 pSMB->TotalParameterCount = pSMB->ParameterCount;
1629 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1630 pSMB->DataOffset = cpu_to_le16(offset);
1631 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1632 pSMB->Reserved4 = 0;
1633 pSMB->hdr.smb_buf_length += byte_count;
1634 pSMB->ByteCount = cpu_to_le16(byte_count);
1635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1637 cifs_stats_inc(&tcon->num_symlinks);
1638 if (rc) {
1639 cFYI(1,
1640 ("Send error in SetPathInfo (create symlink) = %d",
1641 rc));
1644 if (pSMB)
1645 cifs_buf_release(pSMB);
1647 if (rc == -EAGAIN)
1648 goto createSymLinkRetry;
1650 return rc;
1654 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1655 const char *fromName, const char *toName,
1656 const struct nls_table *nls_codepage, int remap)
1658 TRANSACTION2_SPI_REQ *pSMB = NULL;
1659 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1660 char *data_offset;
1661 int name_len;
1662 int name_len_target;
1663 int rc = 0;
1664 int bytes_returned = 0;
1665 __u16 params, param_offset, offset, byte_count;
1667 cFYI(1, ("In Create Hard link Unix style"));
1668 createHardLinkRetry:
1669 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1670 (void **) &pSMBr);
1671 if (rc)
1672 return rc;
1674 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1675 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1676 PATH_MAX, nls_codepage, remap);
1677 name_len++; /* trailing null */
1678 name_len *= 2;
1680 } else { /* BB improve the check for buffer overruns BB */
1681 name_len = strnlen(toName, PATH_MAX);
1682 name_len++; /* trailing null */
1683 strncpy(pSMB->FileName, toName, name_len);
1685 params = 6 + name_len;
1686 pSMB->MaxSetupCount = 0;
1687 pSMB->Reserved = 0;
1688 pSMB->Flags = 0;
1689 pSMB->Timeout = 0;
1690 pSMB->Reserved2 = 0;
1691 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1692 InformationLevel) - 4;
1693 offset = param_offset + params;
1695 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1696 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1697 name_len_target =
1698 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1699 nls_codepage, remap);
1700 name_len_target++; /* trailing null */
1701 name_len_target *= 2;
1702 } else { /* BB improve the check for buffer overruns BB */
1703 name_len_target = strnlen(fromName, PATH_MAX);
1704 name_len_target++; /* trailing null */
1705 strncpy(data_offset, fromName, name_len_target);
1708 pSMB->MaxParameterCount = cpu_to_le16(2);
1709 /* BB find exact max on data count below from sess*/
1710 pSMB->MaxDataCount = cpu_to_le16(1000);
1711 pSMB->SetupCount = 1;
1712 pSMB->Reserved3 = 0;
1713 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1714 byte_count = 3 /* pad */ + params + name_len_target;
1715 pSMB->ParameterCount = cpu_to_le16(params);
1716 pSMB->TotalParameterCount = pSMB->ParameterCount;
1717 pSMB->DataCount = cpu_to_le16(name_len_target);
1718 pSMB->TotalDataCount = pSMB->DataCount;
1719 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1720 pSMB->DataOffset = cpu_to_le16(offset);
1721 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1722 pSMB->Reserved4 = 0;
1723 pSMB->hdr.smb_buf_length += byte_count;
1724 pSMB->ByteCount = cpu_to_le16(byte_count);
1725 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1726 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1727 cifs_stats_inc(&tcon->num_hardlinks);
1728 if (rc) {
1729 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1732 cifs_buf_release(pSMB);
1733 if (rc == -EAGAIN)
1734 goto createHardLinkRetry;
1736 return rc;
1740 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1741 const char *fromName, const char *toName,
1742 const struct nls_table *nls_codepage, int remap)
1744 int rc = 0;
1745 NT_RENAME_REQ *pSMB = NULL;
1746 RENAME_RSP *pSMBr = NULL;
1747 int bytes_returned;
1748 int name_len, name_len2;
1749 __u16 count;
1751 cFYI(1, ("In CIFSCreateHardLink"));
1752 winCreateHardLinkRetry:
1754 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1755 (void **) &pSMBr);
1756 if (rc)
1757 return rc;
1759 pSMB->SearchAttributes =
1760 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1761 ATTR_DIRECTORY);
1762 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1763 pSMB->ClusterCount = 0;
1765 pSMB->BufferFormat = 0x04;
1767 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1768 name_len =
1769 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1770 PATH_MAX, nls_codepage, remap);
1771 name_len++; /* trailing null */
1772 name_len *= 2;
1773 pSMB->OldFileName[name_len] = 0; /* pad */
1774 pSMB->OldFileName[name_len + 1] = 0x04;
1775 name_len2 =
1776 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1777 toName, PATH_MAX, nls_codepage, remap);
1778 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1779 name_len2 *= 2; /* convert to bytes */
1780 } else { /* BB improve the check for buffer overruns BB */
1781 name_len = strnlen(fromName, PATH_MAX);
1782 name_len++; /* trailing null */
1783 strncpy(pSMB->OldFileName, fromName, name_len);
1784 name_len2 = strnlen(toName, PATH_MAX);
1785 name_len2++; /* trailing null */
1786 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1787 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1788 name_len2++; /* trailing null */
1789 name_len2++; /* signature byte */
1792 count = 1 /* string type byte */ + name_len + name_len2;
1793 pSMB->hdr.smb_buf_length += count;
1794 pSMB->ByteCount = cpu_to_le16(count);
1796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1798 cifs_stats_inc(&tcon->num_hardlinks);
1799 if (rc) {
1800 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1802 cifs_buf_release(pSMB);
1803 if (rc == -EAGAIN)
1804 goto winCreateHardLinkRetry;
1806 return rc;
1810 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1811 const unsigned char *searchName,
1812 char *symlinkinfo, const int buflen,
1813 const struct nls_table *nls_codepage)
1815 /* SMB_QUERY_FILE_UNIX_LINK */
1816 TRANSACTION2_QPI_REQ *pSMB = NULL;
1817 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1818 int rc = 0;
1819 int bytes_returned;
1820 int name_len;
1821 __u16 params, byte_count;
1823 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1825 querySymLinkRetry:
1826 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1827 (void **) &pSMBr);
1828 if (rc)
1829 return rc;
1831 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1832 name_len =
1833 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1834 /* find define for this maxpathcomponent */
1835 , nls_codepage);
1836 name_len++; /* trailing null */
1837 name_len *= 2;
1838 } else { /* BB improve the check for buffer overruns BB */
1839 name_len = strnlen(searchName, PATH_MAX);
1840 name_len++; /* trailing null */
1841 strncpy(pSMB->FileName, searchName, name_len);
1844 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1845 pSMB->TotalDataCount = 0;
1846 pSMB->MaxParameterCount = cpu_to_le16(2);
1847 /* BB find exact max data count below from sess structure BB */
1848 pSMB->MaxDataCount = cpu_to_le16(4000);
1849 pSMB->MaxSetupCount = 0;
1850 pSMB->Reserved = 0;
1851 pSMB->Flags = 0;
1852 pSMB->Timeout = 0;
1853 pSMB->Reserved2 = 0;
1854 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1855 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1856 pSMB->DataCount = 0;
1857 pSMB->DataOffset = 0;
1858 pSMB->SetupCount = 1;
1859 pSMB->Reserved3 = 0;
1860 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1861 byte_count = params + 1 /* pad */ ;
1862 pSMB->TotalParameterCount = cpu_to_le16(params);
1863 pSMB->ParameterCount = pSMB->TotalParameterCount;
1864 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1865 pSMB->Reserved4 = 0;
1866 pSMB->hdr.smb_buf_length += byte_count;
1867 pSMB->ByteCount = cpu_to_le16(byte_count);
1869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1871 if (rc) {
1872 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1873 } else {
1874 /* decode response */
1876 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1877 if (rc || (pSMBr->ByteCount < 2))
1878 /* BB also check enough total bytes returned */
1879 rc = -EIO; /* bad smb */
1880 else {
1881 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1882 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1884 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1885 name_len = UniStrnlen((wchar_t *) ((char *)
1886 &pSMBr->hdr.Protocol +data_offset),
1887 min_t(const int, buflen,count) / 2);
1888 /* BB FIXME investigate remapping reserved chars here */
1889 cifs_strfromUCS_le(symlinkinfo,
1890 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
1891 data_offset),
1892 name_len, nls_codepage);
1893 } else {
1894 strncpy(symlinkinfo,
1895 (char *) &pSMBr->hdr.Protocol +
1896 data_offset,
1897 min_t(const int, buflen, count));
1899 symlinkinfo[buflen] = 0;
1900 /* just in case so calling code does not go off the end of buffer */
1903 cifs_buf_release(pSMB);
1904 if (rc == -EAGAIN)
1905 goto querySymLinkRetry;
1906 return rc;
1910 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1911 const unsigned char *searchName,
1912 char *symlinkinfo, const int buflen,__u16 fid,
1913 const struct nls_table *nls_codepage)
1915 int rc = 0;
1916 int bytes_returned;
1917 int name_len;
1918 struct smb_com_transaction_ioctl_req * pSMB;
1919 struct smb_com_transaction_ioctl_rsp * pSMBr;
1921 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1922 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1923 (void **) &pSMBr);
1924 if (rc)
1925 return rc;
1927 pSMB->TotalParameterCount = 0 ;
1928 pSMB->TotalDataCount = 0;
1929 pSMB->MaxParameterCount = cpu_to_le32(2);
1930 /* BB find exact data count max from sess structure BB */
1931 pSMB->MaxDataCount = cpu_to_le32(4000);
1932 pSMB->MaxSetupCount = 4;
1933 pSMB->Reserved = 0;
1934 pSMB->ParameterOffset = 0;
1935 pSMB->DataCount = 0;
1936 pSMB->DataOffset = 0;
1937 pSMB->SetupCount = 4;
1938 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1939 pSMB->ParameterCount = pSMB->TotalParameterCount;
1940 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1941 pSMB->IsFsctl = 1; /* FSCTL */
1942 pSMB->IsRootFlag = 0;
1943 pSMB->Fid = fid; /* file handle always le */
1944 pSMB->ByteCount = 0;
1946 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1948 if (rc) {
1949 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1950 } else { /* decode response */
1951 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1952 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1953 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1954 /* BB also check enough total bytes returned */
1955 rc = -EIO; /* bad smb */
1956 else {
1957 if(data_count && (data_count < 2048)) {
1958 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1960 struct reparse_data * reparse_buf = (struct reparse_data *)
1961 ((char *)&pSMBr->hdr.Protocol + data_offset);
1962 if((char*)reparse_buf >= end_of_smb) {
1963 rc = -EIO;
1964 goto qreparse_out;
1966 if((reparse_buf->LinkNamesBuf +
1967 reparse_buf->TargetNameOffset +
1968 reparse_buf->TargetNameLen) >
1969 end_of_smb) {
1970 cFYI(1,("reparse buf extended beyond SMB"));
1971 rc = -EIO;
1972 goto qreparse_out;
1975 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1976 name_len = UniStrnlen((wchar_t *)
1977 (reparse_buf->LinkNamesBuf +
1978 reparse_buf->TargetNameOffset),
1979 min(buflen/2, reparse_buf->TargetNameLen / 2));
1980 cifs_strfromUCS_le(symlinkinfo,
1981 (__le16 *) (reparse_buf->LinkNamesBuf +
1982 reparse_buf->TargetNameOffset),
1983 name_len, nls_codepage);
1984 } else { /* ASCII names */
1985 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1986 reparse_buf->TargetNameOffset,
1987 min_t(const int, buflen, reparse_buf->TargetNameLen));
1989 } else {
1990 rc = -EIO;
1991 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1993 symlinkinfo[buflen] = 0; /* just in case so the caller
1994 does not go off the end of the buffer */
1995 cFYI(1,("readlink result - %s ",symlinkinfo));
1998 qreparse_out:
1999 cifs_buf_release(pSMB);
2001 /* Note: On -EAGAIN error only caller can retry on handle based calls
2002 since file handle passed in no longer valid */
2004 return rc;
2007 #ifdef CONFIG_CIFS_POSIX
2009 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2010 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2012 /* u8 cifs fields do not need le conversion */
2013 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2014 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2015 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2016 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2018 return;
2021 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2022 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2023 const int acl_type,const int size_of_data_area)
2025 int size = 0;
2026 int i;
2027 __u16 count;
2028 struct cifs_posix_ace * pACE;
2029 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2030 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2032 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2033 return -EOPNOTSUPP;
2035 if(acl_type & ACL_TYPE_ACCESS) {
2036 count = le16_to_cpu(cifs_acl->access_entry_count);
2037 pACE = &cifs_acl->ace_array[0];
2038 size = sizeof(struct cifs_posix_acl);
2039 size += sizeof(struct cifs_posix_ace) * count;
2040 /* check if we would go beyond end of SMB */
2041 if(size_of_data_area < size) {
2042 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2043 return -EINVAL;
2045 } else if(acl_type & ACL_TYPE_DEFAULT) {
2046 count = le16_to_cpu(cifs_acl->access_entry_count);
2047 size = sizeof(struct cifs_posix_acl);
2048 size += sizeof(struct cifs_posix_ace) * count;
2049 /* skip past access ACEs to get to default ACEs */
2050 pACE = &cifs_acl->ace_array[count];
2051 count = le16_to_cpu(cifs_acl->default_entry_count);
2052 size += sizeof(struct cifs_posix_ace) * count;
2053 /* check if we would go beyond end of SMB */
2054 if(size_of_data_area < size)
2055 return -EINVAL;
2056 } else {
2057 /* illegal type */
2058 return -EINVAL;
2061 size = posix_acl_xattr_size(count);
2062 if((buflen == 0) || (local_acl == NULL)) {
2063 /* used to query ACL EA size */
2064 } else if(size > buflen) {
2065 return -ERANGE;
2066 } else /* buffer big enough */ {
2067 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2068 for(i = 0;i < count ;i++) {
2069 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2070 pACE ++;
2073 return size;
2076 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2077 const posix_acl_xattr_entry * local_ace)
2079 __u16 rc = 0; /* 0 = ACL converted ok */
2081 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2082 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2083 /* BB is there a better way to handle the large uid? */
2084 if(local_ace->e_id == cpu_to_le32(-1)) {
2085 /* Probably no need to le convert -1 on any arch but can not hurt */
2086 cifs_ace->cifs_uid = cpu_to_le64(-1);
2087 } else
2088 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2089 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2090 return rc;
2093 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2094 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2095 const int acl_type)
2097 __u16 rc = 0;
2098 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2099 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2100 int count;
2101 int i;
2103 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2104 return 0;
2106 count = posix_acl_xattr_count((size_t)buflen);
2107 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2108 count, buflen, le32_to_cpu(local_acl->a_version)));
2109 if(le32_to_cpu(local_acl->a_version) != 2) {
2110 cFYI(1,("unknown POSIX ACL version %d",
2111 le32_to_cpu(local_acl->a_version)));
2112 return 0;
2114 cifs_acl->version = cpu_to_le16(1);
2115 if(acl_type == ACL_TYPE_ACCESS)
2116 cifs_acl->access_entry_count = cpu_to_le16(count);
2117 else if(acl_type == ACL_TYPE_DEFAULT)
2118 cifs_acl->default_entry_count = cpu_to_le16(count);
2119 else {
2120 cFYI(1,("unknown ACL type %d",acl_type));
2121 return 0;
2123 for(i=0;i<count;i++) {
2124 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2125 &local_acl->a_entries[i]);
2126 if(rc != 0) {
2127 /* ACE not converted */
2128 break;
2131 if(rc == 0) {
2132 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2133 rc += sizeof(struct cifs_posix_acl);
2134 /* BB add check to make sure ACL does not overflow SMB */
2136 return rc;
2140 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2141 const unsigned char *searchName,
2142 char *acl_inf, const int buflen, const int acl_type,
2143 const struct nls_table *nls_codepage, int remap)
2145 /* SMB_QUERY_POSIX_ACL */
2146 TRANSACTION2_QPI_REQ *pSMB = NULL;
2147 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2148 int rc = 0;
2149 int bytes_returned;
2150 int name_len;
2151 __u16 params, byte_count;
2153 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2155 queryAclRetry:
2156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2157 (void **) &pSMBr);
2158 if (rc)
2159 return rc;
2161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2162 name_len =
2163 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2164 PATH_MAX, nls_codepage, remap);
2165 name_len++; /* trailing null */
2166 name_len *= 2;
2167 pSMB->FileName[name_len] = 0;
2168 pSMB->FileName[name_len+1] = 0;
2169 } else { /* BB improve the check for buffer overruns BB */
2170 name_len = strnlen(searchName, PATH_MAX);
2171 name_len++; /* trailing null */
2172 strncpy(pSMB->FileName, searchName, name_len);
2175 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2176 pSMB->TotalDataCount = 0;
2177 pSMB->MaxParameterCount = cpu_to_le16(2);
2178 /* BB find exact max data count below from sess structure BB */
2179 pSMB->MaxDataCount = cpu_to_le16(4000);
2180 pSMB->MaxSetupCount = 0;
2181 pSMB->Reserved = 0;
2182 pSMB->Flags = 0;
2183 pSMB->Timeout = 0;
2184 pSMB->Reserved2 = 0;
2185 pSMB->ParameterOffset = cpu_to_le16(
2186 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2187 pSMB->DataCount = 0;
2188 pSMB->DataOffset = 0;
2189 pSMB->SetupCount = 1;
2190 pSMB->Reserved3 = 0;
2191 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2192 byte_count = params + 1 /* pad */ ;
2193 pSMB->TotalParameterCount = cpu_to_le16(params);
2194 pSMB->ParameterCount = pSMB->TotalParameterCount;
2195 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2196 pSMB->Reserved4 = 0;
2197 pSMB->hdr.smb_buf_length += byte_count;
2198 pSMB->ByteCount = cpu_to_le16(byte_count);
2200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2202 if (rc) {
2203 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2204 } else {
2205 /* decode response */
2207 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2208 if (rc || (pSMBr->ByteCount < 2))
2209 /* BB also check enough total bytes returned */
2210 rc = -EIO; /* bad smb */
2211 else {
2212 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2213 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2214 rc = cifs_copy_posix_acl(acl_inf,
2215 (char *)&pSMBr->hdr.Protocol+data_offset,
2216 buflen,acl_type,count);
2219 cifs_buf_release(pSMB);
2220 if (rc == -EAGAIN)
2221 goto queryAclRetry;
2222 return rc;
2226 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2227 const unsigned char *fileName,
2228 const char *local_acl, const int buflen,
2229 const int acl_type,
2230 const struct nls_table *nls_codepage, int remap)
2232 struct smb_com_transaction2_spi_req *pSMB = NULL;
2233 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2234 char *parm_data;
2235 int name_len;
2236 int rc = 0;
2237 int bytes_returned = 0;
2238 __u16 params, byte_count, data_count, param_offset, offset;
2240 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2241 setAclRetry:
2242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2243 (void **) &pSMBr);
2244 if (rc)
2245 return rc;
2246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2247 name_len =
2248 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2249 PATH_MAX, nls_codepage, remap);
2250 name_len++; /* trailing null */
2251 name_len *= 2;
2252 } else { /* BB improve the check for buffer overruns BB */
2253 name_len = strnlen(fileName, PATH_MAX);
2254 name_len++; /* trailing null */
2255 strncpy(pSMB->FileName, fileName, name_len);
2257 params = 6 + name_len;
2258 pSMB->MaxParameterCount = cpu_to_le16(2);
2259 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2260 pSMB->MaxSetupCount = 0;
2261 pSMB->Reserved = 0;
2262 pSMB->Flags = 0;
2263 pSMB->Timeout = 0;
2264 pSMB->Reserved2 = 0;
2265 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2266 InformationLevel) - 4;
2267 offset = param_offset + params;
2268 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2269 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2271 /* convert to on the wire format for POSIX ACL */
2272 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2274 if(data_count == 0) {
2275 rc = -EOPNOTSUPP;
2276 goto setACLerrorExit;
2278 pSMB->DataOffset = cpu_to_le16(offset);
2279 pSMB->SetupCount = 1;
2280 pSMB->Reserved3 = 0;
2281 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2282 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2283 byte_count = 3 /* pad */ + params + data_count;
2284 pSMB->DataCount = cpu_to_le16(data_count);
2285 pSMB->TotalDataCount = pSMB->DataCount;
2286 pSMB->ParameterCount = cpu_to_le16(params);
2287 pSMB->TotalParameterCount = pSMB->ParameterCount;
2288 pSMB->Reserved4 = 0;
2289 pSMB->hdr.smb_buf_length += byte_count;
2290 pSMB->ByteCount = cpu_to_le16(byte_count);
2291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2292 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2293 if (rc) {
2294 cFYI(1, ("Set POSIX ACL returned %d", rc));
2297 setACLerrorExit:
2298 cifs_buf_release(pSMB);
2299 if (rc == -EAGAIN)
2300 goto setAclRetry;
2301 return rc;
2304 /* BB fix tabs in this function FIXME BB */
2306 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2307 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2309 int rc = 0;
2310 struct smb_t2_qfi_req *pSMB = NULL;
2311 struct smb_t2_qfi_rsp *pSMBr = NULL;
2312 int bytes_returned;
2313 __u16 params, byte_count;
2315 cFYI(1,("In GetExtAttr"));
2316 if(tcon == NULL)
2317 return -ENODEV;
2319 GetExtAttrRetry:
2320 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2321 (void **) &pSMBr);
2322 if (rc)
2323 return rc;
2325 params = 2 /* level */ +2 /* fid */;
2326 pSMB->t2.TotalDataCount = 0;
2327 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2328 /* BB find exact max data count below from sess structure BB */
2329 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2330 pSMB->t2.MaxSetupCount = 0;
2331 pSMB->t2.Reserved = 0;
2332 pSMB->t2.Flags = 0;
2333 pSMB->t2.Timeout = 0;
2334 pSMB->t2.Reserved2 = 0;
2335 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2336 Fid) - 4);
2337 pSMB->t2.DataCount = 0;
2338 pSMB->t2.DataOffset = 0;
2339 pSMB->t2.SetupCount = 1;
2340 pSMB->t2.Reserved3 = 0;
2341 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2342 byte_count = params + 1 /* pad */ ;
2343 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2344 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2346 pSMB->Pad = 0;
2347 pSMB->Fid = netfid;
2348 pSMB->hdr.smb_buf_length += byte_count;
2349 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2351 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2352 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2353 if (rc) {
2354 cFYI(1, ("error %d in GetExtAttr", rc));
2355 } else {
2356 /* decode response */
2357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2358 if (rc || (pSMBr->ByteCount < 2))
2359 /* BB also check enough total bytes returned */
2360 /* If rc should we check for EOPNOSUPP and
2361 disable the srvino flag? or in caller? */
2362 rc = -EIO; /* bad smb */
2363 else {
2364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2365 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2366 struct file_chattr_info * pfinfo;
2367 /* BB Do we need a cast or hash here ? */
2368 if(count != 16) {
2369 cFYI(1, ("Illegal size ret in GetExtAttr"));
2370 rc = -EIO;
2371 goto GetExtAttrOut;
2373 pfinfo = (struct file_chattr_info *)
2374 (data_offset + (char *) &pSMBr->hdr.Protocol);
2375 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2376 *pMask = le64_to_cpu(pfinfo->mask);
2379 GetExtAttrOut:
2380 cifs_buf_release(pSMB);
2381 if (rc == -EAGAIN)
2382 goto GetExtAttrRetry;
2383 return rc;
2387 #endif /* CONFIG_POSIX */
2389 /* Legacy Query Path Information call for lookup to old servers such
2390 as Win9x/WinME */
2391 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2392 const unsigned char *searchName,
2393 FILE_ALL_INFO * pFinfo,
2394 const struct nls_table *nls_codepage, int remap)
2396 QUERY_INFORMATION_REQ * pSMB;
2397 QUERY_INFORMATION_RSP * pSMBr;
2398 int rc = 0;
2399 int bytes_returned;
2400 int name_len;
2402 cFYI(1, ("In SMBQPath path %s", searchName));
2403 QInfRetry:
2404 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2405 (void **) &pSMBr);
2406 if (rc)
2407 return rc;
2409 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2410 name_len =
2411 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2412 PATH_MAX, nls_codepage, remap);
2413 name_len++; /* trailing null */
2414 name_len *= 2;
2415 } else {
2416 name_len = strnlen(searchName, PATH_MAX);
2417 name_len++; /* trailing null */
2418 strncpy(pSMB->FileName, searchName, name_len);
2420 pSMB->BufferFormat = 0x04;
2421 name_len++; /* account for buffer type byte */
2422 pSMB->hdr.smb_buf_length += (__u16) name_len;
2423 pSMB->ByteCount = cpu_to_le16(name_len);
2425 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2427 if (rc) {
2428 cFYI(1, ("Send error in QueryInfo = %d", rc));
2429 } else if (pFinfo) { /* decode response */
2430 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2431 pFinfo->AllocationSize =
2432 cpu_to_le64(le32_to_cpu(pSMBr->size));
2433 pFinfo->EndOfFile = pFinfo->AllocationSize;
2434 pFinfo->Attributes =
2435 cpu_to_le32(le16_to_cpu(pSMBr->attr));
2436 } else
2437 rc = -EIO; /* bad buffer passed in */
2439 cifs_buf_release(pSMB);
2441 if (rc == -EAGAIN)
2442 goto QInfRetry;
2444 return rc;
2451 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2452 const unsigned char *searchName,
2453 FILE_ALL_INFO * pFindData,
2454 const struct nls_table *nls_codepage, int remap)
2456 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2457 TRANSACTION2_QPI_REQ *pSMB = NULL;
2458 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2459 int rc = 0;
2460 int bytes_returned;
2461 int name_len;
2462 __u16 params, byte_count;
2464 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2465 QPathInfoRetry:
2466 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2467 (void **) &pSMBr);
2468 if (rc)
2469 return rc;
2471 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2472 name_len =
2473 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2474 PATH_MAX, nls_codepage, remap);
2475 name_len++; /* trailing null */
2476 name_len *= 2;
2477 } else { /* BB improve the check for buffer overruns BB */
2478 name_len = strnlen(searchName, PATH_MAX);
2479 name_len++; /* trailing null */
2480 strncpy(pSMB->FileName, searchName, name_len);
2483 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2484 pSMB->TotalDataCount = 0;
2485 pSMB->MaxParameterCount = cpu_to_le16(2);
2486 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2487 pSMB->MaxSetupCount = 0;
2488 pSMB->Reserved = 0;
2489 pSMB->Flags = 0;
2490 pSMB->Timeout = 0;
2491 pSMB->Reserved2 = 0;
2492 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2493 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2494 pSMB->DataCount = 0;
2495 pSMB->DataOffset = 0;
2496 pSMB->SetupCount = 1;
2497 pSMB->Reserved3 = 0;
2498 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2499 byte_count = params + 1 /* pad */ ;
2500 pSMB->TotalParameterCount = cpu_to_le16(params);
2501 pSMB->ParameterCount = pSMB->TotalParameterCount;
2502 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2503 pSMB->Reserved4 = 0;
2504 pSMB->hdr.smb_buf_length += byte_count;
2505 pSMB->ByteCount = cpu_to_le16(byte_count);
2507 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2508 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2509 if (rc) {
2510 cFYI(1, ("Send error in QPathInfo = %d", rc));
2511 } else { /* decode response */
2512 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2514 if (rc || (pSMBr->ByteCount < 40))
2515 rc = -EIO; /* bad smb */
2516 else if (pFindData){
2517 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2518 memcpy((char *) pFindData,
2519 (char *) &pSMBr->hdr.Protocol +
2520 data_offset, sizeof (FILE_ALL_INFO));
2521 } else
2522 rc = -ENOMEM;
2524 cifs_buf_release(pSMB);
2525 if (rc == -EAGAIN)
2526 goto QPathInfoRetry;
2528 return rc;
2532 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2533 const unsigned char *searchName,
2534 FILE_UNIX_BASIC_INFO * pFindData,
2535 const struct nls_table *nls_codepage, int remap)
2537 /* SMB_QUERY_FILE_UNIX_BASIC */
2538 TRANSACTION2_QPI_REQ *pSMB = NULL;
2539 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2540 int rc = 0;
2541 int bytes_returned = 0;
2542 int name_len;
2543 __u16 params, byte_count;
2545 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2546 UnixQPathInfoRetry:
2547 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2548 (void **) &pSMBr);
2549 if (rc)
2550 return rc;
2552 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2553 name_len =
2554 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2555 PATH_MAX, nls_codepage, remap);
2556 name_len++; /* trailing null */
2557 name_len *= 2;
2558 } else { /* BB improve the check for buffer overruns BB */
2559 name_len = strnlen(searchName, PATH_MAX);
2560 name_len++; /* trailing null */
2561 strncpy(pSMB->FileName, searchName, name_len);
2564 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2565 pSMB->TotalDataCount = 0;
2566 pSMB->MaxParameterCount = cpu_to_le16(2);
2567 /* BB find exact max SMB PDU from sess structure BB */
2568 pSMB->MaxDataCount = cpu_to_le16(4000);
2569 pSMB->MaxSetupCount = 0;
2570 pSMB->Reserved = 0;
2571 pSMB->Flags = 0;
2572 pSMB->Timeout = 0;
2573 pSMB->Reserved2 = 0;
2574 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2575 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2576 pSMB->DataCount = 0;
2577 pSMB->DataOffset = 0;
2578 pSMB->SetupCount = 1;
2579 pSMB->Reserved3 = 0;
2580 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2581 byte_count = params + 1 /* pad */ ;
2582 pSMB->TotalParameterCount = cpu_to_le16(params);
2583 pSMB->ParameterCount = pSMB->TotalParameterCount;
2584 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2585 pSMB->Reserved4 = 0;
2586 pSMB->hdr.smb_buf_length += byte_count;
2587 pSMB->ByteCount = cpu_to_le16(byte_count);
2589 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2590 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2591 if (rc) {
2592 cFYI(1, ("Send error in QPathInfo = %d", rc));
2593 } else { /* decode response */
2594 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2596 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2597 rc = -EIO; /* bad smb */
2598 } else {
2599 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2600 memcpy((char *) pFindData,
2601 (char *) &pSMBr->hdr.Protocol +
2602 data_offset,
2603 sizeof (FILE_UNIX_BASIC_INFO));
2606 cifs_buf_release(pSMB);
2607 if (rc == -EAGAIN)
2608 goto UnixQPathInfoRetry;
2610 return rc;
2613 #if 0 /* function unused at present */
2614 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2615 const char *searchName, FILE_ALL_INFO * findData,
2616 const struct nls_table *nls_codepage)
2618 /* level 257 SMB_ */
2619 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2620 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2621 int rc = 0;
2622 int bytes_returned;
2623 int name_len;
2624 __u16 params, byte_count;
2626 cFYI(1, ("In FindUnique"));
2627 findUniqueRetry:
2628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2629 (void **) &pSMBr);
2630 if (rc)
2631 return rc;
2633 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2634 name_len =
2635 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2636 /* find define for this maxpathcomponent */
2637 , nls_codepage);
2638 name_len++; /* trailing null */
2639 name_len *= 2;
2640 } else { /* BB improve the check for buffer overruns BB */
2641 name_len = strnlen(searchName, PATH_MAX);
2642 name_len++; /* trailing null */
2643 strncpy(pSMB->FileName, searchName, name_len);
2646 params = 12 + name_len /* includes null */ ;
2647 pSMB->TotalDataCount = 0; /* no EAs */
2648 pSMB->MaxParameterCount = cpu_to_le16(2);
2649 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2650 pSMB->MaxSetupCount = 0;
2651 pSMB->Reserved = 0;
2652 pSMB->Flags = 0;
2653 pSMB->Timeout = 0;
2654 pSMB->Reserved2 = 0;
2655 pSMB->ParameterOffset = cpu_to_le16(
2656 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2657 pSMB->DataCount = 0;
2658 pSMB->DataOffset = 0;
2659 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2660 pSMB->Reserved3 = 0;
2661 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2662 byte_count = params + 1 /* pad */ ;
2663 pSMB->TotalParameterCount = cpu_to_le16(params);
2664 pSMB->ParameterCount = pSMB->TotalParameterCount;
2665 pSMB->SearchAttributes =
2666 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2667 ATTR_DIRECTORY);
2668 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2669 pSMB->SearchFlags = cpu_to_le16(1);
2670 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2671 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2672 pSMB->hdr.smb_buf_length += byte_count;
2673 pSMB->ByteCount = cpu_to_le16(byte_count);
2675 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2678 if (rc) {
2679 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2680 } else { /* decode response */
2681 cifs_stats_inc(&tcon->num_ffirst);
2682 /* BB fill in */
2685 cifs_buf_release(pSMB);
2686 if (rc == -EAGAIN)
2687 goto findUniqueRetry;
2689 return rc;
2691 #endif /* end unused (temporarily) function */
2693 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2695 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2696 const char *searchName,
2697 const struct nls_table *nls_codepage,
2698 __u16 * pnetfid,
2699 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2701 /* level 257 SMB_ */
2702 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2703 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2704 T2_FFIRST_RSP_PARMS * parms;
2705 int rc = 0;
2706 int bytes_returned = 0;
2707 int name_len;
2708 __u16 params, byte_count;
2710 cFYI(1, ("In FindFirst for %s",searchName));
2712 findFirstRetry:
2713 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2714 (void **) &pSMBr);
2715 if (rc)
2716 return rc;
2718 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2719 name_len =
2720 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2721 PATH_MAX, nls_codepage, remap);
2722 /* We can not add the asterik earlier in case
2723 it got remapped to 0xF03A as if it were part of the
2724 directory name instead of a wildcard */
2725 name_len *= 2;
2726 pSMB->FileName[name_len] = dirsep;
2727 pSMB->FileName[name_len+1] = 0;
2728 pSMB->FileName[name_len+2] = '*';
2729 pSMB->FileName[name_len+3] = 0;
2730 name_len += 4; /* now the trailing null */
2731 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2732 pSMB->FileName[name_len+1] = 0;
2733 name_len += 2;
2734 } else { /* BB add check for overrun of SMB buf BB */
2735 name_len = strnlen(searchName, PATH_MAX);
2736 /* BB fix here and in unicode clause above ie
2737 if(name_len > buffersize-header)
2738 free buffer exit; BB */
2739 strncpy(pSMB->FileName, searchName, name_len);
2740 pSMB->FileName[name_len] = dirsep;
2741 pSMB->FileName[name_len+1] = '*';
2742 pSMB->FileName[name_len+2] = 0;
2743 name_len += 3;
2746 params = 12 + name_len /* includes null */ ;
2747 pSMB->TotalDataCount = 0; /* no EAs */
2748 pSMB->MaxParameterCount = cpu_to_le16(10);
2749 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2750 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2751 pSMB->MaxSetupCount = 0;
2752 pSMB->Reserved = 0;
2753 pSMB->Flags = 0;
2754 pSMB->Timeout = 0;
2755 pSMB->Reserved2 = 0;
2756 byte_count = params + 1 /* pad */ ;
2757 pSMB->TotalParameterCount = cpu_to_le16(params);
2758 pSMB->ParameterCount = pSMB->TotalParameterCount;
2759 pSMB->ParameterOffset = cpu_to_le16(
2760 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2761 pSMB->DataCount = 0;
2762 pSMB->DataOffset = 0;
2763 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2764 pSMB->Reserved3 = 0;
2765 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2766 pSMB->SearchAttributes =
2767 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2768 ATTR_DIRECTORY);
2769 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2770 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2771 CIFS_SEARCH_RETURN_RESUME);
2772 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2774 /* BB what should we set StorageType to? Does it matter? BB */
2775 pSMB->SearchStorageType = 0;
2776 pSMB->hdr.smb_buf_length += byte_count;
2777 pSMB->ByteCount = cpu_to_le16(byte_count);
2779 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2780 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2781 cifs_stats_inc(&tcon->num_ffirst);
2783 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2784 /* BB Add code to handle unsupported level rc */
2785 cFYI(1, ("Error in FindFirst = %d", rc));
2787 if (pSMB)
2788 cifs_buf_release(pSMB);
2790 /* BB eventually could optimize out free and realloc of buf */
2791 /* for this case */
2792 if (rc == -EAGAIN)
2793 goto findFirstRetry;
2794 } else { /* decode response */
2795 /* BB remember to free buffer if error BB */
2796 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2797 if(rc == 0) {
2798 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2799 psrch_inf->unicode = TRUE;
2800 else
2801 psrch_inf->unicode = FALSE;
2803 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2804 psrch_inf->srch_entries_start =
2805 (char *) &pSMBr->hdr.Protocol +
2806 le16_to_cpu(pSMBr->t2.DataOffset);
2807 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2808 le16_to_cpu(pSMBr->t2.ParameterOffset));
2810 if(parms->EndofSearch)
2811 psrch_inf->endOfSearch = TRUE;
2812 else
2813 psrch_inf->endOfSearch = FALSE;
2815 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2816 psrch_inf->index_of_last_entry =
2817 psrch_inf->entries_in_buffer;
2818 *pnetfid = parms->SearchHandle;
2819 } else {
2820 cifs_buf_release(pSMB);
2824 return rc;
2827 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2828 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2830 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2831 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2832 T2_FNEXT_RSP_PARMS * parms;
2833 char *response_data;
2834 int rc = 0;
2835 int bytes_returned, name_len;
2836 __u16 params, byte_count;
2838 cFYI(1, ("In FindNext"));
2840 if(psrch_inf->endOfSearch == TRUE)
2841 return -ENOENT;
2843 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2844 (void **) &pSMBr);
2845 if (rc)
2846 return rc;
2848 params = 14; /* includes 2 bytes of null string, converted to LE below */
2849 byte_count = 0;
2850 pSMB->TotalDataCount = 0; /* no EAs */
2851 pSMB->MaxParameterCount = cpu_to_le16(8);
2852 pSMB->MaxDataCount =
2853 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2854 pSMB->MaxSetupCount = 0;
2855 pSMB->Reserved = 0;
2856 pSMB->Flags = 0;
2857 pSMB->Timeout = 0;
2858 pSMB->Reserved2 = 0;
2859 pSMB->ParameterOffset = cpu_to_le16(
2860 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2861 pSMB->DataCount = 0;
2862 pSMB->DataOffset = 0;
2863 pSMB->SetupCount = 1;
2864 pSMB->Reserved3 = 0;
2865 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2866 pSMB->SearchHandle = searchHandle; /* always kept as le */
2867 pSMB->SearchCount =
2868 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2869 /* test for Unix extensions */
2870 /* if (tcon->ses->capabilities & CAP_UNIX) {
2871 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2872 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2873 } else {
2874 pSMB->InformationLevel =
2875 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2876 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2877 } */
2878 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2879 pSMB->ResumeKey = psrch_inf->resume_key;
2880 pSMB->SearchFlags =
2881 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2883 name_len = psrch_inf->resume_name_len;
2884 params += name_len;
2885 if(name_len < PATH_MAX) {
2886 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2887 byte_count += name_len;
2888 /* 14 byte parm len above enough for 2 byte null terminator */
2889 pSMB->ResumeFileName[name_len] = 0;
2890 pSMB->ResumeFileName[name_len+1] = 0;
2891 } else {
2892 rc = -EINVAL;
2893 goto FNext2_err_exit;
2895 byte_count = params + 1 /* pad */ ;
2896 pSMB->TotalParameterCount = cpu_to_le16(params);
2897 pSMB->ParameterCount = pSMB->TotalParameterCount;
2898 pSMB->hdr.smb_buf_length += byte_count;
2899 pSMB->ByteCount = cpu_to_le16(byte_count);
2901 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2902 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2903 cifs_stats_inc(&tcon->num_fnext);
2904 if (rc) {
2905 if (rc == -EBADF) {
2906 psrch_inf->endOfSearch = TRUE;
2907 rc = 0; /* search probably was closed at end of search above */
2908 } else
2909 cFYI(1, ("FindNext returned = %d", rc));
2910 } else { /* decode response */
2911 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2913 if(rc == 0) {
2914 /* BB fixme add lock for file (srch_info) struct here */
2915 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2916 psrch_inf->unicode = TRUE;
2917 else
2918 psrch_inf->unicode = FALSE;
2919 response_data = (char *) &pSMBr->hdr.Protocol +
2920 le16_to_cpu(pSMBr->t2.ParameterOffset);
2921 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2922 response_data = (char *)&pSMBr->hdr.Protocol +
2923 le16_to_cpu(pSMBr->t2.DataOffset);
2924 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2925 psrch_inf->srch_entries_start = response_data;
2926 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2927 if(parms->EndofSearch)
2928 psrch_inf->endOfSearch = TRUE;
2929 else
2930 psrch_inf->endOfSearch = FALSE;
2932 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2933 psrch_inf->index_of_last_entry +=
2934 psrch_inf->entries_in_buffer;
2935 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2937 /* BB fixme add unlock here */
2942 /* BB On error, should we leave previous search buf (and count and
2943 last entry fields) intact or free the previous one? */
2945 /* Note: On -EAGAIN error only caller can retry on handle based calls
2946 since file handle passed in no longer valid */
2947 FNext2_err_exit:
2948 if (rc != 0)
2949 cifs_buf_release(pSMB);
2951 return rc;
2955 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2957 int rc = 0;
2958 FINDCLOSE_REQ *pSMB = NULL;
2959 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2960 int bytes_returned;
2962 cFYI(1, ("In CIFSSMBFindClose"));
2963 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2965 /* no sense returning error if session restarted
2966 as file handle has been closed */
2967 if(rc == -EAGAIN)
2968 return 0;
2969 if (rc)
2970 return rc;
2972 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2973 pSMB->FileID = searchHandle;
2974 pSMB->ByteCount = 0;
2975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2977 if (rc) {
2978 cERROR(1, ("Send error in FindClose = %d", rc));
2980 cifs_stats_inc(&tcon->num_fclose);
2981 cifs_small_buf_release(pSMB);
2983 /* Since session is dead, search handle closed on server already */
2984 if (rc == -EAGAIN)
2985 rc = 0;
2987 return rc;
2991 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2992 const unsigned char *searchName,
2993 __u64 * inode_number,
2994 const struct nls_table *nls_codepage, int remap)
2996 int rc = 0;
2997 TRANSACTION2_QPI_REQ *pSMB = NULL;
2998 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2999 int name_len, bytes_returned;
3000 __u16 params, byte_count;
3002 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3003 if(tcon == NULL)
3004 return -ENODEV;
3006 GetInodeNumberRetry:
3007 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3008 (void **) &pSMBr);
3009 if (rc)
3010 return rc;
3013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3014 name_len =
3015 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3016 PATH_MAX,nls_codepage, remap);
3017 name_len++; /* trailing null */
3018 name_len *= 2;
3019 } else { /* BB improve the check for buffer overruns BB */
3020 name_len = strnlen(searchName, PATH_MAX);
3021 name_len++; /* trailing null */
3022 strncpy(pSMB->FileName, searchName, name_len);
3025 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3026 pSMB->TotalDataCount = 0;
3027 pSMB->MaxParameterCount = cpu_to_le16(2);
3028 /* BB find exact max data count below from sess structure BB */
3029 pSMB->MaxDataCount = cpu_to_le16(4000);
3030 pSMB->MaxSetupCount = 0;
3031 pSMB->Reserved = 0;
3032 pSMB->Flags = 0;
3033 pSMB->Timeout = 0;
3034 pSMB->Reserved2 = 0;
3035 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3036 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3037 pSMB->DataCount = 0;
3038 pSMB->DataOffset = 0;
3039 pSMB->SetupCount = 1;
3040 pSMB->Reserved3 = 0;
3041 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3042 byte_count = params + 1 /* pad */ ;
3043 pSMB->TotalParameterCount = cpu_to_le16(params);
3044 pSMB->ParameterCount = pSMB->TotalParameterCount;
3045 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3046 pSMB->Reserved4 = 0;
3047 pSMB->hdr.smb_buf_length += byte_count;
3048 pSMB->ByteCount = cpu_to_le16(byte_count);
3050 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3052 if (rc) {
3053 cFYI(1, ("error %d in QueryInternalInfo", rc));
3054 } else {
3055 /* decode response */
3056 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3057 if (rc || (pSMBr->ByteCount < 2))
3058 /* BB also check enough total bytes returned */
3059 /* If rc should we check for EOPNOSUPP and
3060 disable the srvino flag? or in caller? */
3061 rc = -EIO; /* bad smb */
3062 else {
3063 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3064 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3065 struct file_internal_info * pfinfo;
3066 /* BB Do we need a cast or hash here ? */
3067 if(count < 8) {
3068 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3069 rc = -EIO;
3070 goto GetInodeNumOut;
3072 pfinfo = (struct file_internal_info *)
3073 (data_offset + (char *) &pSMBr->hdr.Protocol);
3074 *inode_number = pfinfo->UniqueId;
3077 GetInodeNumOut:
3078 cifs_buf_release(pSMB);
3079 if (rc == -EAGAIN)
3080 goto GetInodeNumberRetry;
3081 return rc;
3085 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3086 const unsigned char *searchName,
3087 unsigned char **targetUNCs,
3088 unsigned int *number_of_UNC_in_array,
3089 const struct nls_table *nls_codepage, int remap)
3091 /* TRANS2_GET_DFS_REFERRAL */
3092 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3093 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3094 struct dfs_referral_level_3 * referrals = NULL;
3095 int rc = 0;
3096 int bytes_returned;
3097 int name_len;
3098 unsigned int i;
3099 char * temp;
3100 __u16 params, byte_count;
3101 *number_of_UNC_in_array = 0;
3102 *targetUNCs = NULL;
3104 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3105 if (ses == NULL)
3106 return -ENODEV;
3107 getDFSRetry:
3108 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3109 (void **) &pSMBr);
3110 if (rc)
3111 return rc;
3113 /* server pointer checked in called function,
3114 but should never be null here anyway */
3115 pSMB->hdr.Mid = GetNextMid(ses->server);
3116 pSMB->hdr.Tid = ses->ipc_tid;
3117 pSMB->hdr.Uid = ses->Suid;
3118 if (ses->capabilities & CAP_STATUS32) {
3119 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3121 if (ses->capabilities & CAP_DFS) {
3122 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3125 if (ses->capabilities & CAP_UNICODE) {
3126 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3127 name_len =
3128 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3129 searchName, PATH_MAX, nls_codepage, remap);
3130 name_len++; /* trailing null */
3131 name_len *= 2;
3132 } else { /* BB improve the check for buffer overruns BB */
3133 name_len = strnlen(searchName, PATH_MAX);
3134 name_len++; /* trailing null */
3135 strncpy(pSMB->RequestFileName, searchName, name_len);
3138 params = 2 /* level */ + name_len /*includes null */ ;
3139 pSMB->TotalDataCount = 0;
3140 pSMB->DataCount = 0;
3141 pSMB->DataOffset = 0;
3142 pSMB->MaxParameterCount = 0;
3143 pSMB->MaxDataCount = cpu_to_le16(4000); /* 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 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3150 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3151 pSMB->SetupCount = 1;
3152 pSMB->Reserved3 = 0;
3153 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3154 byte_count = params + 3 /* pad */ ;
3155 pSMB->ParameterCount = cpu_to_le16(params);
3156 pSMB->TotalParameterCount = pSMB->ParameterCount;
3157 pSMB->MaxReferralLevel = cpu_to_le16(3);
3158 pSMB->hdr.smb_buf_length += byte_count;
3159 pSMB->ByteCount = cpu_to_le16(byte_count);
3161 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3163 if (rc) {
3164 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3165 } else { /* decode response */
3166 /* BB Add logic to parse referrals here */
3167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3169 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3170 rc = -EIO; /* bad smb */
3171 else {
3172 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3173 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3175 cFYI(1,
3176 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3177 pSMBr->ByteCount, data_offset));
3178 referrals =
3179 (struct dfs_referral_level_3 *)
3180 (8 /* sizeof start of data block */ +
3181 data_offset +
3182 (char *) &pSMBr->hdr.Protocol);
3183 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",
3184 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)));
3185 /* BB This field is actually two bytes in from start of
3186 data block so we could do safety check that DataBlock
3187 begins at address of pSMBr->NumberOfReferrals */
3188 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3190 /* BB Fix below so can return more than one referral */
3191 if(*number_of_UNC_in_array > 1)
3192 *number_of_UNC_in_array = 1;
3194 /* get the length of the strings describing refs */
3195 name_len = 0;
3196 for(i=0;i<*number_of_UNC_in_array;i++) {
3197 /* make sure that DfsPathOffset not past end */
3198 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3199 if (offset > data_count) {
3200 /* if invalid referral, stop here and do
3201 not try to copy any more */
3202 *number_of_UNC_in_array = i;
3203 break;
3205 temp = ((char *)referrals) + offset;
3207 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3208 name_len += UniStrnlen((wchar_t *)temp,data_count);
3209 } else {
3210 name_len += strnlen(temp,data_count);
3212 referrals++;
3213 /* BB add check that referral pointer does not fall off end PDU */
3216 /* BB add check for name_len bigger than bcc */
3217 *targetUNCs =
3218 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3219 if(*targetUNCs == NULL) {
3220 rc = -ENOMEM;
3221 goto GetDFSRefExit;
3223 /* copy the ref strings */
3224 referrals =
3225 (struct dfs_referral_level_3 *)
3226 (8 /* sizeof data hdr */ +
3227 data_offset +
3228 (char *) &pSMBr->hdr.Protocol);
3230 for(i=0;i<*number_of_UNC_in_array;i++) {
3231 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3232 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3233 cifs_strfromUCS_le(*targetUNCs,
3234 (__le16 *) temp, name_len, nls_codepage);
3235 } else {
3236 strncpy(*targetUNCs,temp,name_len);
3238 /* BB update target_uncs pointers */
3239 referrals++;
3241 temp = *targetUNCs;
3242 temp[name_len] = 0;
3246 GetDFSRefExit:
3247 if (pSMB)
3248 cifs_buf_release(pSMB);
3250 if (rc == -EAGAIN)
3251 goto getDFSRetry;
3253 return rc;
3256 /* Query File System Info such as free space to old servers such as Win 9x */
3258 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3260 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3261 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3262 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3263 FILE_SYSTEM_ALLOC_INFO *response_data;
3264 int rc = 0;
3265 int bytes_returned = 0;
3266 __u16 params, byte_count;
3268 cFYI(1, ("OldQFSInfo"));
3269 oldQFSInfoRetry:
3270 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3271 (void **) &pSMBr);
3272 if (rc)
3273 return rc;
3274 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3275 (void **) &pSMBr);
3276 if (rc)
3277 return rc;
3279 params = 2; /* level */
3280 pSMB->TotalDataCount = 0;
3281 pSMB->MaxParameterCount = cpu_to_le16(2);
3282 pSMB->MaxDataCount = cpu_to_le16(1000);
3283 pSMB->MaxSetupCount = 0;
3284 pSMB->Reserved = 0;
3285 pSMB->Flags = 0;
3286 pSMB->Timeout = 0;
3287 pSMB->Reserved2 = 0;
3288 byte_count = params + 1 /* pad */ ;
3289 pSMB->TotalParameterCount = cpu_to_le16(params);
3290 pSMB->ParameterCount = pSMB->TotalParameterCount;
3291 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3292 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3293 pSMB->DataCount = 0;
3294 pSMB->DataOffset = 0;
3295 pSMB->SetupCount = 1;
3296 pSMB->Reserved3 = 0;
3297 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3298 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3299 pSMB->hdr.smb_buf_length += byte_count;
3300 pSMB->ByteCount = cpu_to_le16(byte_count);
3302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3304 if (rc) {
3305 cFYI(1, ("Send error in QFSInfo = %d", rc));
3306 } else { /* decode response */
3307 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3309 if (rc || (pSMBr->ByteCount < 18))
3310 rc = -EIO; /* bad smb */
3311 else {
3312 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3313 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3314 pSMBr->ByteCount, data_offset));
3316 response_data =
3317 (FILE_SYSTEM_ALLOC_INFO *)
3318 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3319 FSData->f_bsize =
3320 le16_to_cpu(response_data->BytesPerSector) *
3321 le32_to_cpu(response_data->
3322 SectorsPerAllocationUnit);
3323 FSData->f_blocks =
3324 le32_to_cpu(response_data->TotalAllocationUnits);
3325 FSData->f_bfree = FSData->f_bavail =
3326 le32_to_cpu(response_data->FreeAllocationUnits);
3327 cFYI(1,
3328 ("Blocks: %lld Free: %lld Block size %ld",
3329 (unsigned long long)FSData->f_blocks,
3330 (unsigned long long)FSData->f_bfree,
3331 FSData->f_bsize));
3334 cifs_buf_release(pSMB);
3336 if (rc == -EAGAIN)
3337 goto oldQFSInfoRetry;
3339 return rc;
3343 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3345 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3346 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3347 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3348 FILE_SYSTEM_INFO *response_data;
3349 int rc = 0;
3350 int bytes_returned = 0;
3351 __u16 params, byte_count;
3353 cFYI(1, ("In QFSInfo"));
3354 QFSInfoRetry:
3355 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3356 (void **) &pSMBr);
3357 if (rc)
3358 return rc;
3360 params = 2; /* level */
3361 pSMB->TotalDataCount = 0;
3362 pSMB->MaxParameterCount = cpu_to_le16(2);
3363 pSMB->MaxDataCount = cpu_to_le16(1000);
3364 pSMB->MaxSetupCount = 0;
3365 pSMB->Reserved = 0;
3366 pSMB->Flags = 0;
3367 pSMB->Timeout = 0;
3368 pSMB->Reserved2 = 0;
3369 byte_count = params + 1 /* pad */ ;
3370 pSMB->TotalParameterCount = cpu_to_le16(params);
3371 pSMB->ParameterCount = pSMB->TotalParameterCount;
3372 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3373 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3374 pSMB->DataCount = 0;
3375 pSMB->DataOffset = 0;
3376 pSMB->SetupCount = 1;
3377 pSMB->Reserved3 = 0;
3378 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3379 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3380 pSMB->hdr.smb_buf_length += byte_count;
3381 pSMB->ByteCount = cpu_to_le16(byte_count);
3383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3385 if (rc) {
3386 cFYI(1, ("Send error in QFSInfo = %d", rc));
3387 } else { /* decode response */
3388 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3390 if (rc || (pSMBr->ByteCount < 24))
3391 rc = -EIO; /* bad smb */
3392 else {
3393 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3395 response_data =
3396 (FILE_SYSTEM_INFO
3397 *) (((char *) &pSMBr->hdr.Protocol) +
3398 data_offset);
3399 FSData->f_bsize =
3400 le32_to_cpu(response_data->BytesPerSector) *
3401 le32_to_cpu(response_data->
3402 SectorsPerAllocationUnit);
3403 FSData->f_blocks =
3404 le64_to_cpu(response_data->TotalAllocationUnits);
3405 FSData->f_bfree = FSData->f_bavail =
3406 le64_to_cpu(response_data->FreeAllocationUnits);
3407 cFYI(1,
3408 ("Blocks: %lld Free: %lld Block size %ld",
3409 (unsigned long long)FSData->f_blocks,
3410 (unsigned long long)FSData->f_bfree,
3411 FSData->f_bsize));
3414 cifs_buf_release(pSMB);
3416 if (rc == -EAGAIN)
3417 goto QFSInfoRetry;
3419 return rc;
3423 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3425 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3426 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3427 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3428 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3429 int rc = 0;
3430 int bytes_returned = 0;
3431 __u16 params, byte_count;
3433 cFYI(1, ("In QFSAttributeInfo"));
3434 QFSAttributeRetry:
3435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3436 (void **) &pSMBr);
3437 if (rc)
3438 return rc;
3440 params = 2; /* level */
3441 pSMB->TotalDataCount = 0;
3442 pSMB->MaxParameterCount = cpu_to_le16(2);
3443 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3444 pSMB->MaxSetupCount = 0;
3445 pSMB->Reserved = 0;
3446 pSMB->Flags = 0;
3447 pSMB->Timeout = 0;
3448 pSMB->Reserved2 = 0;
3449 byte_count = params + 1 /* pad */ ;
3450 pSMB->TotalParameterCount = cpu_to_le16(params);
3451 pSMB->ParameterCount = pSMB->TotalParameterCount;
3452 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3453 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3454 pSMB->DataCount = 0;
3455 pSMB->DataOffset = 0;
3456 pSMB->SetupCount = 1;
3457 pSMB->Reserved3 = 0;
3458 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3459 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3460 pSMB->hdr.smb_buf_length += byte_count;
3461 pSMB->ByteCount = cpu_to_le16(byte_count);
3463 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3464 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3465 if (rc) {
3466 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3467 } else { /* decode response */
3468 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3470 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3471 rc = -EIO; /* bad smb */
3472 } else {
3473 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3474 response_data =
3475 (FILE_SYSTEM_ATTRIBUTE_INFO
3476 *) (((char *) &pSMBr->hdr.Protocol) +
3477 data_offset);
3478 memcpy(&tcon->fsAttrInfo, response_data,
3479 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3482 cifs_buf_release(pSMB);
3484 if (rc == -EAGAIN)
3485 goto QFSAttributeRetry;
3487 return rc;
3491 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3493 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3494 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3495 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3496 FILE_SYSTEM_DEVICE_INFO *response_data;
3497 int rc = 0;
3498 int bytes_returned = 0;
3499 __u16 params, byte_count;
3501 cFYI(1, ("In QFSDeviceInfo"));
3502 QFSDeviceRetry:
3503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3504 (void **) &pSMBr);
3505 if (rc)
3506 return rc;
3508 params = 2; /* level */
3509 pSMB->TotalDataCount = 0;
3510 pSMB->MaxParameterCount = cpu_to_le16(2);
3511 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3512 pSMB->MaxSetupCount = 0;
3513 pSMB->Reserved = 0;
3514 pSMB->Flags = 0;
3515 pSMB->Timeout = 0;
3516 pSMB->Reserved2 = 0;
3517 byte_count = params + 1 /* pad */ ;
3518 pSMB->TotalParameterCount = cpu_to_le16(params);
3519 pSMB->ParameterCount = pSMB->TotalParameterCount;
3520 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3521 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3523 pSMB->DataCount = 0;
3524 pSMB->DataOffset = 0;
3525 pSMB->SetupCount = 1;
3526 pSMB->Reserved3 = 0;
3527 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3528 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3529 pSMB->hdr.smb_buf_length += byte_count;
3530 pSMB->ByteCount = cpu_to_le16(byte_count);
3532 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3533 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3534 if (rc) {
3535 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3536 } else { /* decode response */
3537 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3539 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3540 rc = -EIO; /* bad smb */
3541 else {
3542 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3543 response_data =
3544 (FILE_SYSTEM_DEVICE_INFO *)
3545 (((char *) &pSMBr->hdr.Protocol) +
3546 data_offset);
3547 memcpy(&tcon->fsDevInfo, response_data,
3548 sizeof (FILE_SYSTEM_DEVICE_INFO));
3551 cifs_buf_release(pSMB);
3553 if (rc == -EAGAIN)
3554 goto QFSDeviceRetry;
3556 return rc;
3560 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3562 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3563 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3564 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3565 FILE_SYSTEM_UNIX_INFO *response_data;
3566 int rc = 0;
3567 int bytes_returned = 0;
3568 __u16 params, byte_count;
3570 cFYI(1, ("In QFSUnixInfo"));
3571 QFSUnixRetry:
3572 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3573 (void **) &pSMBr);
3574 if (rc)
3575 return rc;
3577 params = 2; /* level */
3578 pSMB->TotalDataCount = 0;
3579 pSMB->DataCount = 0;
3580 pSMB->DataOffset = 0;
3581 pSMB->MaxParameterCount = cpu_to_le16(2);
3582 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3583 pSMB->MaxSetupCount = 0;
3584 pSMB->Reserved = 0;
3585 pSMB->Flags = 0;
3586 pSMB->Timeout = 0;
3587 pSMB->Reserved2 = 0;
3588 byte_count = params + 1 /* pad */ ;
3589 pSMB->ParameterCount = cpu_to_le16(params);
3590 pSMB->TotalParameterCount = pSMB->ParameterCount;
3591 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3592 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3593 pSMB->SetupCount = 1;
3594 pSMB->Reserved3 = 0;
3595 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3596 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3597 pSMB->hdr.smb_buf_length += byte_count;
3598 pSMB->ByteCount = cpu_to_le16(byte_count);
3600 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3602 if (rc) {
3603 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3604 } else { /* decode response */
3605 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3607 if (rc || (pSMBr->ByteCount < 13)) {
3608 rc = -EIO; /* bad smb */
3609 } else {
3610 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3611 response_data =
3612 (FILE_SYSTEM_UNIX_INFO
3613 *) (((char *) &pSMBr->hdr.Protocol) +
3614 data_offset);
3615 memcpy(&tcon->fsUnixInfo, response_data,
3616 sizeof (FILE_SYSTEM_UNIX_INFO));
3619 cifs_buf_release(pSMB);
3621 if (rc == -EAGAIN)
3622 goto QFSUnixRetry;
3625 return rc;
3629 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3631 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3632 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3633 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3634 int rc = 0;
3635 int bytes_returned = 0;
3636 __u16 params, param_offset, offset, byte_count;
3638 cFYI(1, ("In SETFSUnixInfo"));
3639 SETFSUnixRetry:
3640 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3641 (void **) &pSMBr);
3642 if (rc)
3643 return rc;
3645 params = 4; /* 2 bytes zero followed by info level. */
3646 pSMB->MaxSetupCount = 0;
3647 pSMB->Reserved = 0;
3648 pSMB->Flags = 0;
3649 pSMB->Timeout = 0;
3650 pSMB->Reserved2 = 0;
3651 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3652 offset = param_offset + params;
3654 pSMB->MaxParameterCount = cpu_to_le16(4);
3655 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3656 pSMB->SetupCount = 1;
3657 pSMB->Reserved3 = 0;
3658 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3659 byte_count = 1 /* pad */ + params + 12;
3661 pSMB->DataCount = cpu_to_le16(12);
3662 pSMB->ParameterCount = cpu_to_le16(params);
3663 pSMB->TotalDataCount = pSMB->DataCount;
3664 pSMB->TotalParameterCount = pSMB->ParameterCount;
3665 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3666 pSMB->DataOffset = cpu_to_le16(offset);
3668 /* Params. */
3669 pSMB->FileNum = 0;
3670 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3672 /* Data. */
3673 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3674 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3675 pSMB->ClientUnixCap = cpu_to_le64(cap);
3677 pSMB->hdr.smb_buf_length += byte_count;
3678 pSMB->ByteCount = cpu_to_le16(byte_count);
3680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3682 if (rc) {
3683 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3684 } else { /* decode response */
3685 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3686 if (rc) {
3687 rc = -EIO; /* bad smb */
3690 cifs_buf_release(pSMB);
3692 if (rc == -EAGAIN)
3693 goto SETFSUnixRetry;
3695 return rc;
3701 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3702 struct kstatfs *FSData)
3704 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3705 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3706 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3707 FILE_SYSTEM_POSIX_INFO *response_data;
3708 int rc = 0;
3709 int bytes_returned = 0;
3710 __u16 params, byte_count;
3712 cFYI(1, ("In QFSPosixInfo"));
3713 QFSPosixRetry:
3714 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3715 (void **) &pSMBr);
3716 if (rc)
3717 return rc;
3719 params = 2; /* level */
3720 pSMB->TotalDataCount = 0;
3721 pSMB->DataCount = 0;
3722 pSMB->DataOffset = 0;
3723 pSMB->MaxParameterCount = cpu_to_le16(2);
3724 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3725 pSMB->MaxSetupCount = 0;
3726 pSMB->Reserved = 0;
3727 pSMB->Flags = 0;
3728 pSMB->Timeout = 0;
3729 pSMB->Reserved2 = 0;
3730 byte_count = params + 1 /* pad */ ;
3731 pSMB->ParameterCount = cpu_to_le16(params);
3732 pSMB->TotalParameterCount = pSMB->ParameterCount;
3733 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3734 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3735 pSMB->SetupCount = 1;
3736 pSMB->Reserved3 = 0;
3737 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3738 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3739 pSMB->hdr.smb_buf_length += byte_count;
3740 pSMB->ByteCount = cpu_to_le16(byte_count);
3742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3744 if (rc) {
3745 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3746 } else { /* decode response */
3747 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3749 if (rc || (pSMBr->ByteCount < 13)) {
3750 rc = -EIO; /* bad smb */
3751 } else {
3752 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3753 response_data =
3754 (FILE_SYSTEM_POSIX_INFO
3755 *) (((char *) &pSMBr->hdr.Protocol) +
3756 data_offset);
3757 FSData->f_bsize =
3758 le32_to_cpu(response_data->BlockSize);
3759 FSData->f_blocks =
3760 le64_to_cpu(response_data->TotalBlocks);
3761 FSData->f_bfree =
3762 le64_to_cpu(response_data->BlocksAvail);
3763 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
3764 FSData->f_bavail = FSData->f_bfree;
3765 } else {
3766 FSData->f_bavail =
3767 le64_to_cpu(response_data->UserBlocksAvail);
3769 if(response_data->TotalFileNodes != cpu_to_le64(-1))
3770 FSData->f_files =
3771 le64_to_cpu(response_data->TotalFileNodes);
3772 if(response_data->FreeFileNodes != cpu_to_le64(-1))
3773 FSData->f_ffree =
3774 le64_to_cpu(response_data->FreeFileNodes);
3777 cifs_buf_release(pSMB);
3779 if (rc == -EAGAIN)
3780 goto QFSPosixRetry;
3782 return rc;
3786 /* We can not use write of zero bytes trick to
3787 set file size due to need for large file support. Also note that
3788 this SetPathInfo is preferred to SetFileInfo based method in next
3789 routine which is only needed to work around a sharing violation bug
3790 in Samba which this routine can run into */
3793 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3794 __u64 size, int SetAllocation,
3795 const struct nls_table *nls_codepage, int remap)
3797 struct smb_com_transaction2_spi_req *pSMB = NULL;
3798 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3799 struct file_end_of_file_info *parm_data;
3800 int name_len;
3801 int rc = 0;
3802 int bytes_returned = 0;
3803 __u16 params, byte_count, data_count, param_offset, offset;
3805 cFYI(1, ("In SetEOF"));
3806 SetEOFRetry:
3807 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3808 (void **) &pSMBr);
3809 if (rc)
3810 return rc;
3812 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3813 name_len =
3814 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3815 PATH_MAX, nls_codepage, remap);
3816 name_len++; /* trailing null */
3817 name_len *= 2;
3818 } else { /* BB improve the check for buffer overruns BB */
3819 name_len = strnlen(fileName, PATH_MAX);
3820 name_len++; /* trailing null */
3821 strncpy(pSMB->FileName, fileName, name_len);
3823 params = 6 + name_len;
3824 data_count = sizeof (struct file_end_of_file_info);
3825 pSMB->MaxParameterCount = cpu_to_le16(2);
3826 pSMB->MaxDataCount = cpu_to_le16(4100);
3827 pSMB->MaxSetupCount = 0;
3828 pSMB->Reserved = 0;
3829 pSMB->Flags = 0;
3830 pSMB->Timeout = 0;
3831 pSMB->Reserved2 = 0;
3832 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3833 InformationLevel) - 4;
3834 offset = param_offset + params;
3835 if(SetAllocation) {
3836 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3837 pSMB->InformationLevel =
3838 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3839 else
3840 pSMB->InformationLevel =
3841 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3842 } else /* Set File Size */ {
3843 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3844 pSMB->InformationLevel =
3845 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3846 else
3847 pSMB->InformationLevel =
3848 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3851 parm_data =
3852 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3853 offset);
3854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3855 pSMB->DataOffset = cpu_to_le16(offset);
3856 pSMB->SetupCount = 1;
3857 pSMB->Reserved3 = 0;
3858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3859 byte_count = 3 /* pad */ + params + data_count;
3860 pSMB->DataCount = cpu_to_le16(data_count);
3861 pSMB->TotalDataCount = pSMB->DataCount;
3862 pSMB->ParameterCount = cpu_to_le16(params);
3863 pSMB->TotalParameterCount = pSMB->ParameterCount;
3864 pSMB->Reserved4 = 0;
3865 pSMB->hdr.smb_buf_length += byte_count;
3866 parm_data->FileSize = cpu_to_le64(size);
3867 pSMB->ByteCount = cpu_to_le16(byte_count);
3868 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3870 if (rc) {
3871 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3874 cifs_buf_release(pSMB);
3876 if (rc == -EAGAIN)
3877 goto SetEOFRetry;
3879 return rc;
3883 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3884 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3886 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3887 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3888 char *data_offset;
3889 struct file_end_of_file_info *parm_data;
3890 int rc = 0;
3891 int bytes_returned = 0;
3892 __u16 params, param_offset, offset, byte_count, count;
3894 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3895 (long long)size));
3896 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3898 if (rc)
3899 return rc;
3901 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3903 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3904 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3906 params = 6;
3907 pSMB->MaxSetupCount = 0;
3908 pSMB->Reserved = 0;
3909 pSMB->Flags = 0;
3910 pSMB->Timeout = 0;
3911 pSMB->Reserved2 = 0;
3912 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3913 offset = param_offset + params;
3915 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3917 count = sizeof(struct file_end_of_file_info);
3918 pSMB->MaxParameterCount = cpu_to_le16(2);
3919 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3920 pSMB->SetupCount = 1;
3921 pSMB->Reserved3 = 0;
3922 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3923 byte_count = 3 /* pad */ + params + count;
3924 pSMB->DataCount = cpu_to_le16(count);
3925 pSMB->ParameterCount = cpu_to_le16(params);
3926 pSMB->TotalDataCount = pSMB->DataCount;
3927 pSMB->TotalParameterCount = pSMB->ParameterCount;
3928 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3929 parm_data =
3930 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3931 offset);
3932 pSMB->DataOffset = cpu_to_le16(offset);
3933 parm_data->FileSize = cpu_to_le64(size);
3934 pSMB->Fid = fid;
3935 if(SetAllocation) {
3936 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3937 pSMB->InformationLevel =
3938 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3939 else
3940 pSMB->InformationLevel =
3941 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3942 } else /* Set File Size */ {
3943 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3944 pSMB->InformationLevel =
3945 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3946 else
3947 pSMB->InformationLevel =
3948 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3950 pSMB->Reserved4 = 0;
3951 pSMB->hdr.smb_buf_length += byte_count;
3952 pSMB->ByteCount = cpu_to_le16(byte_count);
3953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3955 if (rc) {
3956 cFYI(1,
3957 ("Send error in SetFileInfo (SetFileSize) = %d",
3958 rc));
3961 if (pSMB)
3962 cifs_small_buf_release(pSMB);
3964 /* Note: On -EAGAIN error only caller can retry on handle based calls
3965 since file handle passed in no longer valid */
3967 return rc;
3970 /* Some legacy servers such as NT4 require that the file times be set on
3971 an open handle, rather than by pathname - this is awkward due to
3972 potential access conflicts on the open, but it is unavoidable for these
3973 old servers since the only other choice is to go from 100 nanosecond DCE
3974 time and resort to the original setpathinfo level which takes the ancient
3975 DOS time format with 2 second granularity */
3977 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3978 __u16 fid)
3980 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3981 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3982 char *data_offset;
3983 int rc = 0;
3984 int bytes_returned = 0;
3985 __u16 params, param_offset, offset, byte_count, count;
3987 cFYI(1, ("Set Times (via SetFileInfo)"));
3988 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3990 if (rc)
3991 return rc;
3993 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3995 /* At this point there is no need to override the current pid
3996 with the pid of the opener, but that could change if we someday
3997 use an existing handle (rather than opening one on the fly) */
3998 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3999 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4001 params = 6;
4002 pSMB->MaxSetupCount = 0;
4003 pSMB->Reserved = 0;
4004 pSMB->Flags = 0;
4005 pSMB->Timeout = 0;
4006 pSMB->Reserved2 = 0;
4007 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4008 offset = param_offset + params;
4010 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4012 count = sizeof (FILE_BASIC_INFO);
4013 pSMB->MaxParameterCount = cpu_to_le16(2);
4014 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4015 pSMB->SetupCount = 1;
4016 pSMB->Reserved3 = 0;
4017 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4018 byte_count = 3 /* pad */ + params + count;
4019 pSMB->DataCount = cpu_to_le16(count);
4020 pSMB->ParameterCount = cpu_to_le16(params);
4021 pSMB->TotalDataCount = pSMB->DataCount;
4022 pSMB->TotalParameterCount = pSMB->ParameterCount;
4023 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4024 pSMB->DataOffset = cpu_to_le16(offset);
4025 pSMB->Fid = fid;
4026 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4027 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4028 else
4029 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4030 pSMB->Reserved4 = 0;
4031 pSMB->hdr.smb_buf_length += byte_count;
4032 pSMB->ByteCount = cpu_to_le16(byte_count);
4033 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4034 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4035 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4036 if (rc) {
4037 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4040 cifs_small_buf_release(pSMB);
4042 /* Note: On -EAGAIN error only caller can retry on handle based calls
4043 since file handle passed in no longer valid */
4045 return rc;
4050 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4051 const FILE_BASIC_INFO * data,
4052 const struct nls_table *nls_codepage, int remap)
4054 TRANSACTION2_SPI_REQ *pSMB = NULL;
4055 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4056 int name_len;
4057 int rc = 0;
4058 int bytes_returned = 0;
4059 char *data_offset;
4060 __u16 params, param_offset, offset, byte_count, count;
4062 cFYI(1, ("In SetTimes"));
4064 SetTimesRetry:
4065 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4066 (void **) &pSMBr);
4067 if (rc)
4068 return rc;
4070 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4071 name_len =
4072 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4073 PATH_MAX, nls_codepage, remap);
4074 name_len++; /* trailing null */
4075 name_len *= 2;
4076 } else { /* BB improve the check for buffer overruns BB */
4077 name_len = strnlen(fileName, PATH_MAX);
4078 name_len++; /* trailing null */
4079 strncpy(pSMB->FileName, fileName, name_len);
4082 params = 6 + name_len;
4083 count = sizeof (FILE_BASIC_INFO);
4084 pSMB->MaxParameterCount = cpu_to_le16(2);
4085 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4086 pSMB->MaxSetupCount = 0;
4087 pSMB->Reserved = 0;
4088 pSMB->Flags = 0;
4089 pSMB->Timeout = 0;
4090 pSMB->Reserved2 = 0;
4091 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4092 InformationLevel) - 4;
4093 offset = param_offset + params;
4094 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4095 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4096 pSMB->DataOffset = cpu_to_le16(offset);
4097 pSMB->SetupCount = 1;
4098 pSMB->Reserved3 = 0;
4099 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4100 byte_count = 3 /* pad */ + params + count;
4102 pSMB->DataCount = cpu_to_le16(count);
4103 pSMB->ParameterCount = cpu_to_le16(params);
4104 pSMB->TotalDataCount = pSMB->DataCount;
4105 pSMB->TotalParameterCount = pSMB->ParameterCount;
4106 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4107 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4108 else
4109 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4110 pSMB->Reserved4 = 0;
4111 pSMB->hdr.smb_buf_length += byte_count;
4112 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4113 pSMB->ByteCount = cpu_to_le16(byte_count);
4114 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4115 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4116 if (rc) {
4117 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4120 cifs_buf_release(pSMB);
4122 if (rc == -EAGAIN)
4123 goto SetTimesRetry;
4125 return rc;
4128 /* Can not be used to set time stamps yet (due to old DOS time format) */
4129 /* Can be used to set attributes */
4130 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4131 handling it anyway and NT4 was what we thought it would be needed for
4132 Do not delete it until we prove whether needed for Win9x though */
4134 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4135 __u16 dos_attrs, const struct nls_table *nls_codepage)
4137 SETATTR_REQ *pSMB = NULL;
4138 SETATTR_RSP *pSMBr = NULL;
4139 int rc = 0;
4140 int bytes_returned;
4141 int name_len;
4143 cFYI(1, ("In SetAttrLegacy"));
4145 SetAttrLgcyRetry:
4146 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4147 (void **) &pSMBr);
4148 if (rc)
4149 return rc;
4151 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4152 name_len =
4153 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4154 PATH_MAX, nls_codepage);
4155 name_len++; /* trailing null */
4156 name_len *= 2;
4157 } else { /* BB improve the check for buffer overruns BB */
4158 name_len = strnlen(fileName, PATH_MAX);
4159 name_len++; /* trailing null */
4160 strncpy(pSMB->fileName, fileName, name_len);
4162 pSMB->attr = cpu_to_le16(dos_attrs);
4163 pSMB->BufferFormat = 0x04;
4164 pSMB->hdr.smb_buf_length += name_len + 1;
4165 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4166 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4167 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4168 if (rc) {
4169 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4172 cifs_buf_release(pSMB);
4174 if (rc == -EAGAIN)
4175 goto SetAttrLgcyRetry;
4177 return rc;
4179 #endif /* temporarily unneeded SetAttr legacy function */
4182 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4183 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4184 dev_t device, const struct nls_table *nls_codepage,
4185 int remap)
4187 TRANSACTION2_SPI_REQ *pSMB = NULL;
4188 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4189 int name_len;
4190 int rc = 0;
4191 int bytes_returned = 0;
4192 FILE_UNIX_BASIC_INFO *data_offset;
4193 __u16 params, param_offset, offset, count, byte_count;
4195 cFYI(1, ("In SetUID/GID/Mode"));
4196 setPermsRetry:
4197 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4198 (void **) &pSMBr);
4199 if (rc)
4200 return rc;
4202 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4203 name_len =
4204 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4205 PATH_MAX, nls_codepage, remap);
4206 name_len++; /* trailing null */
4207 name_len *= 2;
4208 } else { /* BB improve the check for buffer overruns BB */
4209 name_len = strnlen(fileName, PATH_MAX);
4210 name_len++; /* trailing null */
4211 strncpy(pSMB->FileName, fileName, name_len);
4214 params = 6 + name_len;
4215 count = sizeof (FILE_UNIX_BASIC_INFO);
4216 pSMB->MaxParameterCount = cpu_to_le16(2);
4217 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4218 pSMB->MaxSetupCount = 0;
4219 pSMB->Reserved = 0;
4220 pSMB->Flags = 0;
4221 pSMB->Timeout = 0;
4222 pSMB->Reserved2 = 0;
4223 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4224 InformationLevel) - 4;
4225 offset = param_offset + params;
4226 data_offset =
4227 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4228 offset);
4229 memset(data_offset, 0, count);
4230 pSMB->DataOffset = cpu_to_le16(offset);
4231 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4232 pSMB->SetupCount = 1;
4233 pSMB->Reserved3 = 0;
4234 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4235 byte_count = 3 /* pad */ + params + count;
4236 pSMB->ParameterCount = cpu_to_le16(params);
4237 pSMB->DataCount = cpu_to_le16(count);
4238 pSMB->TotalParameterCount = pSMB->ParameterCount;
4239 pSMB->TotalDataCount = pSMB->DataCount;
4240 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4241 pSMB->Reserved4 = 0;
4242 pSMB->hdr.smb_buf_length += byte_count;
4243 data_offset->Uid = cpu_to_le64(uid);
4244 data_offset->Gid = cpu_to_le64(gid);
4245 /* better to leave device as zero when it is */
4246 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4247 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4248 data_offset->Permissions = cpu_to_le64(mode);
4250 if(S_ISREG(mode))
4251 data_offset->Type = cpu_to_le32(UNIX_FILE);
4252 else if(S_ISDIR(mode))
4253 data_offset->Type = cpu_to_le32(UNIX_DIR);
4254 else if(S_ISLNK(mode))
4255 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4256 else if(S_ISCHR(mode))
4257 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4258 else if(S_ISBLK(mode))
4259 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4260 else if(S_ISFIFO(mode))
4261 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4262 else if(S_ISSOCK(mode))
4263 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
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 (perms) returned %d", rc));
4273 if (pSMB)
4274 cifs_buf_release(pSMB);
4275 if (rc == -EAGAIN)
4276 goto setPermsRetry;
4277 return rc;
4280 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4281 const int notify_subdirs, const __u16 netfid,
4282 __u32 filter, struct file * pfile, int multishot,
4283 const struct nls_table *nls_codepage)
4285 int rc = 0;
4286 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4287 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
4288 struct dir_notify_req *dnotify_req;
4289 int bytes_returned;
4291 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4292 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4293 (void **) &pSMBr);
4294 if (rc)
4295 return rc;
4297 pSMB->TotalParameterCount = 0 ;
4298 pSMB->TotalDataCount = 0;
4299 pSMB->MaxParameterCount = cpu_to_le32(2);
4300 /* BB find exact data count max from sess structure BB */
4301 pSMB->MaxDataCount = 0; /* same in little endian or be */
4302 pSMB->MaxSetupCount = 4;
4303 pSMB->Reserved = 0;
4304 pSMB->ParameterOffset = 0;
4305 pSMB->DataCount = 0;
4306 pSMB->DataOffset = 0;
4307 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4308 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4309 pSMB->ParameterCount = pSMB->TotalParameterCount;
4310 if(notify_subdirs)
4311 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4312 pSMB->Reserved2 = 0;
4313 pSMB->CompletionFilter = cpu_to_le32(filter);
4314 pSMB->Fid = netfid; /* file handle always le */
4315 pSMB->ByteCount = 0;
4317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4318 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4319 if (rc) {
4320 cFYI(1, ("Error in Notify = %d", rc));
4321 } else {
4322 /* Add file to outstanding requests */
4323 /* BB change to kmem cache alloc */
4324 dnotify_req = (struct dir_notify_req *) kmalloc(
4325 sizeof(struct dir_notify_req),
4326 GFP_KERNEL);
4327 if(dnotify_req) {
4328 dnotify_req->Pid = pSMB->hdr.Pid;
4329 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4330 dnotify_req->Mid = pSMB->hdr.Mid;
4331 dnotify_req->Tid = pSMB->hdr.Tid;
4332 dnotify_req->Uid = pSMB->hdr.Uid;
4333 dnotify_req->netfid = netfid;
4334 dnotify_req->pfile = pfile;
4335 dnotify_req->filter = filter;
4336 dnotify_req->multishot = multishot;
4337 spin_lock(&GlobalMid_Lock);
4338 list_add_tail(&dnotify_req->lhead,
4339 &GlobalDnotifyReqList);
4340 spin_unlock(&GlobalMid_Lock);
4341 } else
4342 rc = -ENOMEM;
4344 cifs_buf_release(pSMB);
4345 return rc;
4347 #ifdef CONFIG_CIFS_XATTR
4348 ssize_t
4349 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4350 const unsigned char *searchName,
4351 char * EAData, size_t buf_size,
4352 const struct nls_table *nls_codepage, int remap)
4354 /* BB assumes one setup word */
4355 TRANSACTION2_QPI_REQ *pSMB = NULL;
4356 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4357 int rc = 0;
4358 int bytes_returned;
4359 int name_len;
4360 struct fea * temp_fea;
4361 char * temp_ptr;
4362 __u16 params, byte_count;
4364 cFYI(1, ("In Query All EAs path %s", searchName));
4365 QAllEAsRetry:
4366 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4367 (void **) &pSMBr);
4368 if (rc)
4369 return rc;
4371 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4372 name_len =
4373 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4374 PATH_MAX, nls_codepage, remap);
4375 name_len++; /* trailing null */
4376 name_len *= 2;
4377 } else { /* BB improve the check for buffer overruns BB */
4378 name_len = strnlen(searchName, PATH_MAX);
4379 name_len++; /* trailing null */
4380 strncpy(pSMB->FileName, searchName, name_len);
4383 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4384 pSMB->TotalDataCount = 0;
4385 pSMB->MaxParameterCount = cpu_to_le16(2);
4386 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4387 pSMB->MaxSetupCount = 0;
4388 pSMB->Reserved = 0;
4389 pSMB->Flags = 0;
4390 pSMB->Timeout = 0;
4391 pSMB->Reserved2 = 0;
4392 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4393 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4394 pSMB->DataCount = 0;
4395 pSMB->DataOffset = 0;
4396 pSMB->SetupCount = 1;
4397 pSMB->Reserved3 = 0;
4398 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4399 byte_count = params + 1 /* pad */ ;
4400 pSMB->TotalParameterCount = cpu_to_le16(params);
4401 pSMB->ParameterCount = pSMB->TotalParameterCount;
4402 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4403 pSMB->Reserved4 = 0;
4404 pSMB->hdr.smb_buf_length += byte_count;
4405 pSMB->ByteCount = cpu_to_le16(byte_count);
4407 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4408 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4409 if (rc) {
4410 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4411 } else { /* decode response */
4412 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4414 /* BB also check enough total bytes returned */
4415 /* BB we need to improve the validity checking
4416 of these trans2 responses */
4417 if (rc || (pSMBr->ByteCount < 4))
4418 rc = -EIO; /* bad smb */
4419 /* else if (pFindData){
4420 memcpy((char *) pFindData,
4421 (char *) &pSMBr->hdr.Protocol +
4422 data_offset, kl);
4423 }*/ else {
4424 /* check that length of list is not more than bcc */
4425 /* check that each entry does not go beyond length
4426 of list */
4427 /* check that each element of each entry does not
4428 go beyond end of list */
4429 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4430 struct fealist * ea_response_data;
4431 rc = 0;
4432 /* validate_trans2_offsets() */
4433 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4434 ea_response_data = (struct fealist *)
4435 (((char *) &pSMBr->hdr.Protocol) +
4436 data_offset);
4437 name_len = le32_to_cpu(ea_response_data->list_len);
4438 cFYI(1,("ea length %d", name_len));
4439 if(name_len <= 8) {
4440 /* returned EA size zeroed at top of function */
4441 cFYI(1,("empty EA list returned from server"));
4442 } else {
4443 /* account for ea list len */
4444 name_len -= 4;
4445 temp_fea = ea_response_data->list;
4446 temp_ptr = (char *)temp_fea;
4447 while(name_len > 0) {
4448 __u16 value_len;
4449 name_len -= 4;
4450 temp_ptr += 4;
4451 rc += temp_fea->name_len;
4452 /* account for prefix user. and trailing null */
4453 rc = rc + 5 + 1;
4454 if(rc<(int)buf_size) {
4455 memcpy(EAData,"user.",5);
4456 EAData+=5;
4457 memcpy(EAData,temp_ptr,temp_fea->name_len);
4458 EAData+=temp_fea->name_len;
4459 /* null terminate name */
4460 *EAData = 0;
4461 EAData = EAData + 1;
4462 } else if(buf_size == 0) {
4463 /* skip copy - calc size only */
4464 } else {
4465 /* stop before overrun buffer */
4466 rc = -ERANGE;
4467 break;
4469 name_len -= temp_fea->name_len;
4470 temp_ptr += temp_fea->name_len;
4471 /* account for trailing null */
4472 name_len--;
4473 temp_ptr++;
4474 value_len = le16_to_cpu(temp_fea->value_len);
4475 name_len -= value_len;
4476 temp_ptr += value_len;
4477 /* BB check that temp_ptr is still within smb BB*/
4478 /* no trailing null to account for in value len */
4479 /* go on to next EA */
4480 temp_fea = (struct fea *)temp_ptr;
4485 if (pSMB)
4486 cifs_buf_release(pSMB);
4487 if (rc == -EAGAIN)
4488 goto QAllEAsRetry;
4490 return (ssize_t)rc;
4493 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4494 const unsigned char * searchName,const unsigned char * ea_name,
4495 unsigned char * ea_value, size_t buf_size,
4496 const struct nls_table *nls_codepage, int remap)
4498 TRANSACTION2_QPI_REQ *pSMB = NULL;
4499 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4500 int rc = 0;
4501 int bytes_returned;
4502 int name_len;
4503 struct fea * temp_fea;
4504 char * temp_ptr;
4505 __u16 params, byte_count;
4507 cFYI(1, ("In Query EA path %s", searchName));
4508 QEARetry:
4509 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4510 (void **) &pSMBr);
4511 if (rc)
4512 return rc;
4514 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4515 name_len =
4516 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4517 PATH_MAX, nls_codepage, remap);
4518 name_len++; /* trailing null */
4519 name_len *= 2;
4520 } else { /* BB improve the check for buffer overruns BB */
4521 name_len = strnlen(searchName, PATH_MAX);
4522 name_len++; /* trailing null */
4523 strncpy(pSMB->FileName, searchName, name_len);
4526 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4527 pSMB->TotalDataCount = 0;
4528 pSMB->MaxParameterCount = cpu_to_le16(2);
4529 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4530 pSMB->MaxSetupCount = 0;
4531 pSMB->Reserved = 0;
4532 pSMB->Flags = 0;
4533 pSMB->Timeout = 0;
4534 pSMB->Reserved2 = 0;
4535 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4536 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4537 pSMB->DataCount = 0;
4538 pSMB->DataOffset = 0;
4539 pSMB->SetupCount = 1;
4540 pSMB->Reserved3 = 0;
4541 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4542 byte_count = params + 1 /* pad */ ;
4543 pSMB->TotalParameterCount = cpu_to_le16(params);
4544 pSMB->ParameterCount = pSMB->TotalParameterCount;
4545 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4546 pSMB->Reserved4 = 0;
4547 pSMB->hdr.smb_buf_length += byte_count;
4548 pSMB->ByteCount = cpu_to_le16(byte_count);
4550 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4551 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4552 if (rc) {
4553 cFYI(1, ("Send error in Query EA = %d", rc));
4554 } else { /* decode response */
4555 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4557 /* BB also check enough total bytes returned */
4558 /* BB we need to improve the validity checking
4559 of these trans2 responses */
4560 if (rc || (pSMBr->ByteCount < 4))
4561 rc = -EIO; /* bad smb */
4562 /* else if (pFindData){
4563 memcpy((char *) pFindData,
4564 (char *) &pSMBr->hdr.Protocol +
4565 data_offset, kl);
4566 }*/ else {
4567 /* check that length of list is not more than bcc */
4568 /* check that each entry does not go beyond length
4569 of list */
4570 /* check that each element of each entry does not
4571 go beyond end of list */
4572 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4573 struct fealist * ea_response_data;
4574 rc = -ENODATA;
4575 /* validate_trans2_offsets() */
4576 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4577 ea_response_data = (struct fealist *)
4578 (((char *) &pSMBr->hdr.Protocol) +
4579 data_offset);
4580 name_len = le32_to_cpu(ea_response_data->list_len);
4581 cFYI(1,("ea length %d", name_len));
4582 if(name_len <= 8) {
4583 /* returned EA size zeroed at top of function */
4584 cFYI(1,("empty EA list returned from server"));
4585 } else {
4586 /* account for ea list len */
4587 name_len -= 4;
4588 temp_fea = ea_response_data->list;
4589 temp_ptr = (char *)temp_fea;
4590 /* loop through checking if we have a matching
4591 name and then return the associated value */
4592 while(name_len > 0) {
4593 __u16 value_len;
4594 name_len -= 4;
4595 temp_ptr += 4;
4596 value_len = le16_to_cpu(temp_fea->value_len);
4597 /* BB validate that value_len falls within SMB,
4598 even though maximum for name_len is 255 */
4599 if(memcmp(temp_fea->name,ea_name,
4600 temp_fea->name_len) == 0) {
4601 /* found a match */
4602 rc = value_len;
4603 /* account for prefix user. and trailing null */
4604 if(rc<=(int)buf_size) {
4605 memcpy(ea_value,
4606 temp_fea->name+temp_fea->name_len+1,
4607 rc);
4608 /* ea values, unlike ea names,
4609 are not null terminated */
4610 } else if(buf_size == 0) {
4611 /* skip copy - calc size only */
4612 } else {
4613 /* stop before overrun buffer */
4614 rc = -ERANGE;
4616 break;
4618 name_len -= temp_fea->name_len;
4619 temp_ptr += temp_fea->name_len;
4620 /* account for trailing null */
4621 name_len--;
4622 temp_ptr++;
4623 name_len -= value_len;
4624 temp_ptr += value_len;
4625 /* no trailing null to account for in value len */
4626 /* go on to next EA */
4627 temp_fea = (struct fea *)temp_ptr;
4632 if (pSMB)
4633 cifs_buf_release(pSMB);
4634 if (rc == -EAGAIN)
4635 goto QEARetry;
4637 return (ssize_t)rc;
4641 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4642 const char * ea_name, const void * ea_value,
4643 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4644 int remap)
4646 struct smb_com_transaction2_spi_req *pSMB = NULL;
4647 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4648 struct fealist *parm_data;
4649 int name_len;
4650 int rc = 0;
4651 int bytes_returned = 0;
4652 __u16 params, param_offset, byte_count, offset, count;
4654 cFYI(1, ("In SetEA"));
4655 SetEARetry:
4656 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4657 (void **) &pSMBr);
4658 if (rc)
4659 return rc;
4661 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4662 name_len =
4663 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4664 PATH_MAX, nls_codepage, remap);
4665 name_len++; /* trailing null */
4666 name_len *= 2;
4667 } else { /* BB improve the check for buffer overruns BB */
4668 name_len = strnlen(fileName, PATH_MAX);
4669 name_len++; /* trailing null */
4670 strncpy(pSMB->FileName, fileName, name_len);
4673 params = 6 + name_len;
4675 /* done calculating parms using name_len of file name,
4676 now use name_len to calculate length of ea name
4677 we are going to create in the inode xattrs */
4678 if(ea_name == NULL)
4679 name_len = 0;
4680 else
4681 name_len = strnlen(ea_name,255);
4683 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4684 pSMB->MaxParameterCount = cpu_to_le16(2);
4685 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4686 pSMB->MaxSetupCount = 0;
4687 pSMB->Reserved = 0;
4688 pSMB->Flags = 0;
4689 pSMB->Timeout = 0;
4690 pSMB->Reserved2 = 0;
4691 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4692 InformationLevel) - 4;
4693 offset = param_offset + params;
4694 pSMB->InformationLevel =
4695 cpu_to_le16(SMB_SET_FILE_EA);
4697 parm_data =
4698 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4699 offset);
4700 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4701 pSMB->DataOffset = cpu_to_le16(offset);
4702 pSMB->SetupCount = 1;
4703 pSMB->Reserved3 = 0;
4704 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4705 byte_count = 3 /* pad */ + params + count;
4706 pSMB->DataCount = cpu_to_le16(count);
4707 parm_data->list_len = cpu_to_le32(count);
4708 parm_data->list[0].EA_flags = 0;
4709 /* we checked above that name len is less than 255 */
4710 parm_data->list[0].name_len = (__u8)name_len;;
4711 /* EA names are always ASCII */
4712 if(ea_name)
4713 strncpy(parm_data->list[0].name,ea_name,name_len);
4714 parm_data->list[0].name[name_len] = 0;
4715 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4716 /* caller ensures that ea_value_len is less than 64K but
4717 we need to ensure that it fits within the smb */
4719 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4720 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4721 if(ea_value_len)
4722 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4724 pSMB->TotalDataCount = pSMB->DataCount;
4725 pSMB->ParameterCount = cpu_to_le16(params);
4726 pSMB->TotalParameterCount = pSMB->ParameterCount;
4727 pSMB->Reserved4 = 0;
4728 pSMB->hdr.smb_buf_length += byte_count;
4729 pSMB->ByteCount = cpu_to_le16(byte_count);
4730 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4731 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4732 if (rc) {
4733 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4736 cifs_buf_release(pSMB);
4738 if (rc == -EAGAIN)
4739 goto SetEARetry;
4741 return rc;
4744 #endif