[CIFS] CIFS readdir perf optimizations part 1
[linux-2.6.22.y-op.git] / fs / cifs / cifssmb.c
blob0ddd97b1d87d43e6f5409158a2d1c3e2c0e1f4ca
1 /*
2 * fs/cifs/cifssmb.c
4 * Copyright (C) International Business Machines Corp., 2002,2006
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * Contains the routines for constructing the SMB PDUs themselves
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly different for reconnection purposes since we never want */
28 /* to reuse a stale file handle and the caller knows the file handle */
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40 #include "cifsacl.h"
42 #ifdef CONFIG_CIFS_POSIX
43 static struct {
44 int index;
45 char *name;
46 } protocols[] = {
47 {CIFS_PROT, "\2NT LM 0.12"},
48 {CIFS_PROT, "\2POSIX 2"},
49 {BAD_PROT, "\2"}
51 #else
52 static struct {
53 int index;
54 char *name;
55 } protocols[] = {
56 {CIFS_PROT, "\2NT LM 0.12"},
57 {BAD_PROT, "\2"}
59 #endif
62 /* Mark as invalid, all open files on tree connections since they
63 were closed when session to server was lost */
64 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
66 struct cifsFileInfo *open_file = NULL;
67 struct list_head * tmp;
68 struct list_head * tmp1;
70 /* list all files open on tree connection and mark them invalid */
71 write_lock(&GlobalSMBSeslock);
72 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
73 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
74 if(open_file) {
75 open_file->invalidHandle = TRUE;
78 write_unlock(&GlobalSMBSeslock);
79 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
80 to this tcon */
83 /* If the return code is zero, this function must fill in request_buf pointer */
84 static int
85 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
86 void **request_buf /* returned */)
88 int rc = 0;
90 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
91 check for tcp and smb session status done differently
92 for those three - in the calling routine */
93 if(tcon) {
94 if(tcon->tidStatus == CifsExiting) {
95 /* only tree disconnect, open, and write,
96 (and ulogoff which does not have tcon)
97 are allowed as we start force umount */
98 if((smb_command != SMB_COM_WRITE_ANDX) &&
99 (smb_command != SMB_COM_OPEN_ANDX) &&
100 (smb_command != SMB_COM_TREE_DISCONNECT)) {
101 cFYI(1,("can not send cmd %d while umounting",
102 smb_command));
103 return -ENODEV;
106 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
107 (tcon->ses->server)){
108 struct nls_table *nls_codepage;
109 /* Give Demultiplex thread up to 10 seconds to
110 reconnect, should be greater than cifs socket
111 timeout which is 7 seconds */
112 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
113 wait_event_interruptible_timeout(tcon->ses->server->response_q,
114 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
115 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
116 /* on "soft" mounts we wait once */
117 if((tcon->retry == FALSE) ||
118 (tcon->ses->status == CifsExiting)) {
119 cFYI(1,("gave up waiting on reconnect in smb_init"));
120 return -EHOSTDOWN;
121 } /* else "hard" mount - keep retrying
122 until process is killed or server
123 comes back on-line */
124 } else /* TCP session is reestablished now */
125 break;
129 nls_codepage = load_nls_default();
130 /* need to prevent multiple threads trying to
131 simultaneously reconnect the same SMB session */
132 down(&tcon->ses->sesSem);
133 if(tcon->ses->status == CifsNeedReconnect)
134 rc = cifs_setup_session(0, tcon->ses,
135 nls_codepage);
136 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
137 mark_open_files_invalid(tcon);
138 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
139 , nls_codepage);
140 up(&tcon->ses->sesSem);
141 /* BB FIXME add code to check if wsize needs
142 update due to negotiated smb buffer size
143 shrinking */
144 if(rc == 0)
145 atomic_inc(&tconInfoReconnectCount);
147 cFYI(1, ("reconnect tcon rc = %d", rc));
148 /* Removed call to reopen open files here -
149 it is safer (and faster) to reopen files
150 one at a time as needed in read and write */
152 /* Check if handle based operation so we
153 know whether we can continue or not without
154 returning to caller to reset file handle */
155 switch(smb_command) {
156 case SMB_COM_READ_ANDX:
157 case SMB_COM_WRITE_ANDX:
158 case SMB_COM_CLOSE:
159 case SMB_COM_FIND_CLOSE2:
160 case SMB_COM_LOCKING_ANDX: {
161 unload_nls(nls_codepage);
162 return -EAGAIN;
165 } else {
166 up(&tcon->ses->sesSem);
168 unload_nls(nls_codepage);
170 } else {
171 return -EIO;
174 if(rc)
175 return rc;
177 *request_buf = cifs_small_buf_get();
178 if (*request_buf == NULL) {
179 /* BB should we add a retry in here if not a writepage? */
180 return -ENOMEM;
183 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
185 if(tcon != NULL)
186 cifs_stats_inc(&tcon->num_smbs_sent);
188 return rc;
191 #ifdef CONFIG_CIFS_EXPERIMENTAL
193 small_smb_init_no_tc(const int smb_command, const int wct,
194 struct cifsSesInfo *ses, void **request_buf)
196 int rc;
197 struct smb_hdr * buffer;
199 rc = small_smb_init(smb_command, wct, NULL, request_buf);
200 if(rc)
201 return rc;
203 buffer = (struct smb_hdr *)*request_buf;
204 buffer->Mid = GetNextMid(ses->server);
205 if (ses->capabilities & CAP_UNICODE)
206 buffer->Flags2 |= SMBFLG2_UNICODE;
207 if (ses->capabilities & CAP_STATUS32)
208 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
210 /* uid, tid can stay at zero as set in header assemble */
212 /* BB add support for turning on the signing when
213 this function is used after 1st of session setup requests */
215 return rc;
217 #endif /* CONFIG_CIFS_EXPERIMENTAL */
219 /* If the return code is zero, this function must fill in request_buf pointer */
220 static int
221 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
222 void **request_buf /* returned */ ,
223 void **response_buf /* returned */ )
225 int rc = 0;
227 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
228 check for tcp and smb session status done differently
229 for those three - in the calling routine */
230 if(tcon) {
231 if(tcon->tidStatus == CifsExiting) {
232 /* only tree disconnect, open, and write,
233 (and ulogoff which does not have tcon)
234 are allowed as we start force umount */
235 if((smb_command != SMB_COM_WRITE_ANDX) &&
236 (smb_command != SMB_COM_OPEN_ANDX) &&
237 (smb_command != SMB_COM_TREE_DISCONNECT)) {
238 cFYI(1,("can not send cmd %d while umounting",
239 smb_command));
240 return -ENODEV;
244 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
245 (tcon->ses->server)){
246 struct nls_table *nls_codepage;
247 /* Give Demultiplex thread up to 10 seconds to
248 reconnect, should be greater than cifs socket
249 timeout which is 7 seconds */
250 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
251 wait_event_interruptible_timeout(tcon->ses->server->response_q,
252 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
253 if(tcon->ses->server->tcpStatus ==
254 CifsNeedReconnect) {
255 /* on "soft" mounts we wait once */
256 if((tcon->retry == FALSE) ||
257 (tcon->ses->status == CifsExiting)) {
258 cFYI(1,("gave up waiting on reconnect in smb_init"));
259 return -EHOSTDOWN;
260 } /* else "hard" mount - keep retrying
261 until process is killed or server
262 comes on-line */
263 } else /* TCP session is reestablished now */
264 break;
268 nls_codepage = load_nls_default();
269 /* need to prevent multiple threads trying to
270 simultaneously reconnect the same SMB session */
271 down(&tcon->ses->sesSem);
272 if(tcon->ses->status == CifsNeedReconnect)
273 rc = cifs_setup_session(0, tcon->ses,
274 nls_codepage);
275 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
276 mark_open_files_invalid(tcon);
277 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
278 tcon, nls_codepage);
279 up(&tcon->ses->sesSem);
280 /* BB FIXME add code to check if wsize needs
281 update due to negotiated smb buffer size
282 shrinking */
283 if(rc == 0)
284 atomic_inc(&tconInfoReconnectCount);
286 cFYI(1, ("reconnect tcon rc = %d", rc));
287 /* Removed call to reopen open files here -
288 it is safer (and faster) to reopen files
289 one at a time as needed in read and write */
291 /* Check if handle based operation so we
292 know whether we can continue or not without
293 returning to caller to reset file handle */
294 switch(smb_command) {
295 case SMB_COM_READ_ANDX:
296 case SMB_COM_WRITE_ANDX:
297 case SMB_COM_CLOSE:
298 case SMB_COM_FIND_CLOSE2:
299 case SMB_COM_LOCKING_ANDX: {
300 unload_nls(nls_codepage);
301 return -EAGAIN;
304 } else {
305 up(&tcon->ses->sesSem);
307 unload_nls(nls_codepage);
309 } else {
310 return -EIO;
313 if(rc)
314 return rc;
316 *request_buf = cifs_buf_get();
317 if (*request_buf == NULL) {
318 /* BB should we add a retry in here if not a writepage? */
319 return -ENOMEM;
321 /* Although the original thought was we needed the response buf for */
322 /* potential retries of smb operations it turns out we can determine */
323 /* from the mid flags when the request buffer can be resent without */
324 /* having to use a second distinct buffer for the response */
325 *response_buf = *request_buf;
327 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
328 wct /*wct */ );
330 if(tcon != NULL)
331 cifs_stats_inc(&tcon->num_smbs_sent);
333 return rc;
336 static int validate_t2(struct smb_t2_rsp * pSMB)
338 int rc = -EINVAL;
339 int total_size;
340 char * pBCC;
342 /* check for plausible wct, bcc and t2 data and parm sizes */
343 /* check for parm and data offset going beyond end of smb */
344 if(pSMB->hdr.WordCount >= 10) {
345 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
346 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
347 /* check that bcc is at least as big as parms + data */
348 /* check that bcc is less than negotiated smb buffer */
349 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
350 if(total_size < 512) {
351 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
352 /* BCC le converted in SendReceive */
353 pBCC = (pSMB->hdr.WordCount * 2) +
354 sizeof(struct smb_hdr) +
355 (char *)pSMB;
356 if((total_size <= (*(u16 *)pBCC)) &&
357 (total_size <
358 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
359 return 0;
365 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
366 sizeof(struct smb_t2_rsp) + 16);
367 return rc;
370 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
372 NEGOTIATE_REQ *pSMB;
373 NEGOTIATE_RSP *pSMBr;
374 int rc = 0;
375 int bytes_returned;
376 struct TCP_Server_Info * server;
377 u16 count;
379 if(ses->server)
380 server = ses->server;
381 else {
382 rc = -EIO;
383 return rc;
385 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
386 (void **) &pSMB, (void **) &pSMBr);
387 if (rc)
388 return rc;
389 pSMB->hdr.Mid = GetNextMid(server);
390 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
391 if (extended_security)
392 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
394 count = strlen(protocols[0].name) + 1;
395 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
396 /* null guaranteed to be at end of source and target buffers anyway */
398 pSMB->hdr.smb_buf_length += count;
399 pSMB->ByteCount = cpu_to_le16(count);
401 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
402 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
403 if (rc == 0) {
404 server->secMode = pSMBr->SecurityMode;
405 if((server->secMode & SECMODE_USER) == 0)
406 cFYI(1,("share mode security"));
407 server->secType = NTLM; /* BB override default for
408 NTLMv2 or kerberos v5 */
409 /* one byte - no need to convert this or EncryptionKeyLen
410 from little endian */
411 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
412 /* probably no need to store and check maxvcs */
413 server->maxBuf =
414 min(le32_to_cpu(pSMBr->MaxBufferSize),
415 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
416 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
417 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
418 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
419 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
420 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
421 /* BB with UTC do we ever need to be using srvr timezone? */
422 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
423 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
424 CIFS_CRYPTO_KEY_SIZE);
425 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
426 && (pSMBr->EncryptionKeyLength == 0)) {
427 /* decode security blob */
428 } else
429 rc = -EIO;
431 /* BB might be helpful to save off the domain of server here */
433 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
434 (server->capabilities & CAP_EXTENDED_SECURITY)) {
435 count = pSMBr->ByteCount;
436 if (count < 16)
437 rc = -EIO;
438 else if (count == 16) {
439 server->secType = RawNTLMSSP;
440 if (server->socketUseCount.counter > 1) {
441 if (memcmp
442 (server->server_GUID,
443 pSMBr->u.extended_response.
444 GUID, 16) != 0) {
445 cFYI(1, ("server UID changed"));
446 memcpy(server->
447 server_GUID,
448 pSMBr->u.
449 extended_response.
450 GUID, 16);
452 } else
453 memcpy(server->server_GUID,
454 pSMBr->u.extended_response.
455 GUID, 16);
456 } else {
457 rc = decode_negTokenInit(pSMBr->u.
458 extended_response.
459 SecurityBlob,
460 count - 16,
461 &server->secType);
462 if(rc == 1) {
463 /* BB Need to fill struct for sessetup here */
464 rc = -EOPNOTSUPP;
465 } else {
466 rc = -EINVAL;
469 } else
470 server->capabilities &= ~CAP_EXTENDED_SECURITY;
471 if(sign_CIFS_PDUs == FALSE) {
472 if(server->secMode & SECMODE_SIGN_REQUIRED)
473 cERROR(1,
474 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
475 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
476 } else if(sign_CIFS_PDUs == 1) {
477 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
478 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
483 cifs_buf_release(pSMB);
484 return rc;
488 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
490 struct smb_hdr *smb_buffer;
491 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
492 int rc = 0;
493 int length;
495 cFYI(1, ("In tree disconnect"));
497 * If last user of the connection and
498 * connection alive - disconnect it
499 * If this is the last connection on the server session disconnect it
500 * (and inside session disconnect we should check if tcp socket needs
501 * to be freed and kernel thread woken up).
503 if (tcon)
504 down(&tcon->tconSem);
505 else
506 return -EIO;
508 atomic_dec(&tcon->useCount);
509 if (atomic_read(&tcon->useCount) > 0) {
510 up(&tcon->tconSem);
511 return -EBUSY;
514 /* No need to return error on this operation if tid invalidated and
515 closed on server already e.g. due to tcp session crashing */
516 if(tcon->tidStatus == CifsNeedReconnect) {
517 up(&tcon->tconSem);
518 return 0;
521 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
522 up(&tcon->tconSem);
523 return -EIO;
525 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
526 (void **)&smb_buffer);
527 if (rc) {
528 up(&tcon->tconSem);
529 return rc;
530 } else {
531 smb_buffer_response = smb_buffer; /* BB removeme BB */
533 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
534 &length, 0);
535 if (rc)
536 cFYI(1, ("Tree disconnect failed %d", rc));
538 if (smb_buffer)
539 cifs_small_buf_release(smb_buffer);
540 up(&tcon->tconSem);
542 /* No need to return error on this operation if tid invalidated and
543 closed on server already e.g. due to tcp session crashing */
544 if (rc == -EAGAIN)
545 rc = 0;
547 return rc;
551 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
553 struct smb_hdr *smb_buffer_response;
554 LOGOFF_ANDX_REQ *pSMB;
555 int rc = 0;
556 int length;
558 cFYI(1, ("In SMBLogoff for session disconnect"));
559 if (ses)
560 down(&ses->sesSem);
561 else
562 return -EIO;
564 atomic_dec(&ses->inUse);
565 if (atomic_read(&ses->inUse) > 0) {
566 up(&ses->sesSem);
567 return -EBUSY;
569 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
570 if (rc) {
571 up(&ses->sesSem);
572 return rc;
575 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
577 if(ses->server) {
578 pSMB->hdr.Mid = GetNextMid(ses->server);
580 if(ses->server->secMode &
581 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
582 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
585 pSMB->hdr.Uid = ses->Suid;
587 pSMB->AndXCommand = 0xFF;
588 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
589 smb_buffer_response, &length, 0);
590 if (ses->server) {
591 atomic_dec(&ses->server->socketUseCount);
592 if (atomic_read(&ses->server->socketUseCount) == 0) {
593 spin_lock(&GlobalMid_Lock);
594 ses->server->tcpStatus = CifsExiting;
595 spin_unlock(&GlobalMid_Lock);
596 rc = -ESHUTDOWN;
599 up(&ses->sesSem);
600 cifs_small_buf_release(pSMB);
602 /* if session dead then we do not need to do ulogoff,
603 since server closed smb session, no sense reporting
604 error */
605 if (rc == -EAGAIN)
606 rc = 0;
607 return rc;
611 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
612 const struct nls_table *nls_codepage, int remap)
614 DELETE_FILE_REQ *pSMB = NULL;
615 DELETE_FILE_RSP *pSMBr = NULL;
616 int rc = 0;
617 int bytes_returned;
618 int name_len;
620 DelFileRetry:
621 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
622 (void **) &pSMBr);
623 if (rc)
624 return rc;
626 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
627 name_len =
628 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
629 PATH_MAX, nls_codepage, remap);
630 name_len++; /* trailing null */
631 name_len *= 2;
632 } else { /* BB improve check for buffer overruns BB */
633 name_len = strnlen(fileName, PATH_MAX);
634 name_len++; /* trailing null */
635 strncpy(pSMB->fileName, fileName, name_len);
637 pSMB->SearchAttributes =
638 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
639 pSMB->BufferFormat = 0x04;
640 pSMB->hdr.smb_buf_length += name_len + 1;
641 pSMB->ByteCount = cpu_to_le16(name_len + 1);
642 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
643 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
644 cifs_stats_inc(&tcon->num_deletes);
645 if (rc) {
646 cFYI(1, ("Error in RMFile = %d", rc));
649 cifs_buf_release(pSMB);
650 if (rc == -EAGAIN)
651 goto DelFileRetry;
653 return rc;
657 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
658 const struct nls_table *nls_codepage, int remap)
660 DELETE_DIRECTORY_REQ *pSMB = NULL;
661 DELETE_DIRECTORY_RSP *pSMBr = NULL;
662 int rc = 0;
663 int bytes_returned;
664 int name_len;
666 cFYI(1, ("In CIFSSMBRmDir"));
667 RmDirRetry:
668 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
669 (void **) &pSMBr);
670 if (rc)
671 return rc;
673 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
674 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
675 PATH_MAX, nls_codepage, remap);
676 name_len++; /* trailing null */
677 name_len *= 2;
678 } else { /* BB improve check for buffer overruns BB */
679 name_len = strnlen(dirName, PATH_MAX);
680 name_len++; /* trailing null */
681 strncpy(pSMB->DirName, dirName, name_len);
684 pSMB->BufferFormat = 0x04;
685 pSMB->hdr.smb_buf_length += name_len + 1;
686 pSMB->ByteCount = cpu_to_le16(name_len + 1);
687 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
688 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
689 cifs_stats_inc(&tcon->num_rmdirs);
690 if (rc) {
691 cFYI(1, ("Error in RMDir = %d", rc));
694 cifs_buf_release(pSMB);
695 if (rc == -EAGAIN)
696 goto RmDirRetry;
697 return rc;
701 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
702 const char *name, const struct nls_table *nls_codepage, int remap)
704 int rc = 0;
705 CREATE_DIRECTORY_REQ *pSMB = NULL;
706 CREATE_DIRECTORY_RSP *pSMBr = NULL;
707 int bytes_returned;
708 int name_len;
710 cFYI(1, ("In CIFSSMBMkDir"));
711 MkDirRetry:
712 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
713 (void **) &pSMBr);
714 if (rc)
715 return rc;
717 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
718 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
719 PATH_MAX, nls_codepage, remap);
720 name_len++; /* trailing null */
721 name_len *= 2;
722 } else { /* BB improve check for buffer overruns BB */
723 name_len = strnlen(name, PATH_MAX);
724 name_len++; /* trailing null */
725 strncpy(pSMB->DirName, name, name_len);
728 pSMB->BufferFormat = 0x04;
729 pSMB->hdr.smb_buf_length += name_len + 1;
730 pSMB->ByteCount = cpu_to_le16(name_len + 1);
731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
732 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
733 cifs_stats_inc(&tcon->num_mkdirs);
734 if (rc) {
735 cFYI(1, ("Error in Mkdir = %d", rc));
738 cifs_buf_release(pSMB);
739 if (rc == -EAGAIN)
740 goto MkDirRetry;
741 return rc;
744 static __u16 convert_disposition(int disposition)
746 __u16 ofun = 0;
748 switch (disposition) {
749 case FILE_SUPERSEDE:
750 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
751 break;
752 case FILE_OPEN:
753 ofun = SMBOPEN_OAPPEND;
754 break;
755 case FILE_CREATE:
756 ofun = SMBOPEN_OCREATE;
757 break;
758 case FILE_OPEN_IF:
759 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
760 break;
761 case FILE_OVERWRITE:
762 ofun = SMBOPEN_OTRUNC;
763 break;
764 case FILE_OVERWRITE_IF:
765 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
766 break;
767 default:
768 cFYI(1,("unknown disposition %d",disposition));
769 ofun = SMBOPEN_OAPPEND; /* regular open */
771 return ofun;
775 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
776 const char *fileName, const int openDisposition,
777 const int access_flags, const int create_options, __u16 * netfid,
778 int *pOplock, FILE_ALL_INFO * pfile_info,
779 const struct nls_table *nls_codepage, int remap)
781 int rc = -EACCES;
782 OPENX_REQ *pSMB = NULL;
783 OPENX_RSP *pSMBr = NULL;
784 int bytes_returned;
785 int name_len;
786 __u16 count;
788 OldOpenRetry:
789 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
790 (void **) &pSMBr);
791 if (rc)
792 return rc;
794 pSMB->AndXCommand = 0xFF; /* none */
796 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
797 count = 1; /* account for one byte pad to word boundary */
798 name_len =
799 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
800 fileName, PATH_MAX, nls_codepage, remap);
801 name_len++; /* trailing null */
802 name_len *= 2;
803 } else { /* BB improve check for buffer overruns BB */
804 count = 0; /* no pad */
805 name_len = strnlen(fileName, PATH_MAX);
806 name_len++; /* trailing null */
807 strncpy(pSMB->fileName, fileName, name_len);
809 if (*pOplock & REQ_OPLOCK)
810 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
811 else if (*pOplock & REQ_BATCHOPLOCK) {
812 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
814 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
815 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
816 /* 0 = read
817 1 = write
818 2 = rw
819 3 = execute
821 pSMB->Mode = cpu_to_le16(2);
822 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
823 /* set file as system file if special file such
824 as fifo and server expecting SFU style and
825 no Unix extensions */
827 if(create_options & CREATE_OPTION_SPECIAL)
828 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
829 else
830 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
832 /* if ((omode & S_IWUGO) == 0)
833 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
834 /* Above line causes problems due to vfs splitting create into two
835 pieces - need to set mode after file created not while it is
836 being created */
838 /* BB FIXME BB */
839 /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
840 /* BB FIXME END BB */
842 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
843 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
844 count += name_len;
845 pSMB->hdr.smb_buf_length += count;
847 pSMB->ByteCount = cpu_to_le16(count);
848 /* long_op set to 1 to allow for oplock break timeouts */
849 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
850 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
851 cifs_stats_inc(&tcon->num_opens);
852 if (rc) {
853 cFYI(1, ("Error in Open = %d", rc));
854 } else {
855 /* BB verify if wct == 15 */
857 /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
859 *netfid = pSMBr->Fid; /* cifs fid stays in le */
860 /* Let caller know file was created so we can set the mode. */
861 /* Do we care about the CreateAction in any other cases? */
862 /* BB FIXME BB */
863 /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
864 *pOplock |= CIFS_CREATE_ACTION; */
865 /* BB FIXME END */
867 if(pfile_info) {
868 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
869 pfile_info->LastAccessTime = 0; /* BB fixme */
870 pfile_info->LastWriteTime = 0; /* BB fixme */
871 pfile_info->ChangeTime = 0; /* BB fixme */
872 pfile_info->Attributes =
873 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
874 /* the file_info buf is endian converted by caller */
875 pfile_info->AllocationSize =
876 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
877 pfile_info->EndOfFile = pfile_info->AllocationSize;
878 pfile_info->NumberOfLinks = cpu_to_le32(1);
882 cifs_buf_release(pSMB);
883 if (rc == -EAGAIN)
884 goto OldOpenRetry;
885 return rc;
889 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
890 const char *fileName, const int openDisposition,
891 const int access_flags, const int create_options, __u16 * netfid,
892 int *pOplock, FILE_ALL_INFO * pfile_info,
893 const struct nls_table *nls_codepage, int remap)
895 int rc = -EACCES;
896 OPEN_REQ *pSMB = NULL;
897 OPEN_RSP *pSMBr = NULL;
898 int bytes_returned;
899 int name_len;
900 __u16 count;
902 openRetry:
903 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
904 (void **) &pSMBr);
905 if (rc)
906 return rc;
908 pSMB->AndXCommand = 0xFF; /* none */
910 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
911 count = 1; /* account for one byte pad to word boundary */
912 name_len =
913 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
914 fileName, PATH_MAX, nls_codepage, remap);
915 name_len++; /* trailing null */
916 name_len *= 2;
917 pSMB->NameLength = cpu_to_le16(name_len);
918 } else { /* BB improve check for buffer overruns BB */
919 count = 0; /* no pad */
920 name_len = strnlen(fileName, PATH_MAX);
921 name_len++; /* trailing null */
922 pSMB->NameLength = cpu_to_le16(name_len);
923 strncpy(pSMB->fileName, fileName, name_len);
925 if (*pOplock & REQ_OPLOCK)
926 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
927 else if (*pOplock & REQ_BATCHOPLOCK) {
928 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
930 pSMB->DesiredAccess = cpu_to_le32(access_flags);
931 pSMB->AllocationSize = 0;
932 /* set file as system file if special file such
933 as fifo and server expecting SFU style and
934 no Unix extensions */
935 if(create_options & CREATE_OPTION_SPECIAL)
936 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
937 else
938 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
939 /* XP does not handle ATTR_POSIX_SEMANTICS */
940 /* but it helps speed up case sensitive checks for other
941 servers such as Samba */
942 if (tcon->ses->capabilities & CAP_UNIX)
943 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
945 /* if ((omode & S_IWUGO) == 0)
946 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
947 /* Above line causes problems due to vfs splitting create into two
948 pieces - need to set mode after file created not while it is
949 being created */
950 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
951 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
952 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
953 /* BB Expirement with various impersonation levels and verify */
954 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
955 pSMB->SecurityFlags =
956 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
958 count += name_len;
959 pSMB->hdr.smb_buf_length += count;
961 pSMB->ByteCount = cpu_to_le16(count);
962 /* long_op set to 1 to allow for oplock break timeouts */
963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
964 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
965 cifs_stats_inc(&tcon->num_opens);
966 if (rc) {
967 cFYI(1, ("Error in Open = %d", rc));
968 } else {
969 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
970 *netfid = pSMBr->Fid; /* cifs fid stays in le */
971 /* Let caller know file was created so we can set the mode. */
972 /* Do we care about the CreateAction in any other cases? */
973 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
974 *pOplock |= CIFS_CREATE_ACTION;
975 if(pfile_info) {
976 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
977 36 /* CreationTime to Attributes */);
978 /* the file_info buf is endian converted by caller */
979 pfile_info->AllocationSize = pSMBr->AllocationSize;
980 pfile_info->EndOfFile = pSMBr->EndOfFile;
981 pfile_info->NumberOfLinks = cpu_to_le32(1);
985 cifs_buf_release(pSMB);
986 if (rc == -EAGAIN)
987 goto openRetry;
988 return rc;
992 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
993 const int netfid, const unsigned int count,
994 const __u64 lseek, unsigned int *nbytes, char **buf,
995 int * pbuf_type)
997 int rc = -EACCES;
998 READ_REQ *pSMB = NULL;
999 READ_RSP *pSMBr = NULL;
1000 char *pReadData = NULL;
1001 int wct;
1002 int resp_buf_type = 0;
1003 struct kvec iov[1];
1005 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
1006 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1007 wct = 12;
1008 else
1009 wct = 10; /* old style read */
1011 *nbytes = 0;
1012 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1013 if (rc)
1014 return rc;
1016 /* tcon and ses pointer are checked in smb_init */
1017 if (tcon->ses->server == NULL)
1018 return -ECONNABORTED;
1020 pSMB->AndXCommand = 0xFF; /* none */
1021 pSMB->Fid = netfid;
1022 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1023 if(wct == 12)
1024 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1025 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1026 return -EIO;
1028 pSMB->Remaining = 0;
1029 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1030 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1031 if(wct == 12)
1032 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1033 else {
1034 /* old style read */
1035 struct smb_com_readx_req * pSMBW =
1036 (struct smb_com_readx_req *)pSMB;
1037 pSMBW->ByteCount = 0;
1040 iov[0].iov_base = (char *)pSMB;
1041 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1042 rc = SendReceive2(xid, tcon->ses, iov,
1043 1 /* num iovecs */,
1044 &resp_buf_type, 0);
1045 cifs_stats_inc(&tcon->num_reads);
1046 pSMBr = (READ_RSP *)iov[0].iov_base;
1047 if (rc) {
1048 cERROR(1, ("Send error in read = %d", rc));
1049 } else {
1050 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1051 data_length = data_length << 16;
1052 data_length += le16_to_cpu(pSMBr->DataLength);
1053 *nbytes = data_length;
1055 /*check that DataLength would not go beyond end of SMB */
1056 if ((data_length > CIFSMaxBufSize)
1057 || (data_length > count)) {
1058 cFYI(1,("bad length %d for count %d",data_length,count));
1059 rc = -EIO;
1060 *nbytes = 0;
1061 } else {
1062 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1063 le16_to_cpu(pSMBr->DataOffset);
1064 /* if(rc = copy_to_user(buf, pReadData, data_length)) {
1065 cERROR(1,("Faulting on read rc = %d",rc));
1066 rc = -EFAULT;
1067 }*/ /* can not use copy_to_user when using page cache*/
1068 if(*buf)
1069 memcpy(*buf,pReadData,data_length);
1073 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1074 if(*buf) {
1075 if(resp_buf_type == CIFS_SMALL_BUFFER)
1076 cifs_small_buf_release(iov[0].iov_base);
1077 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1078 cifs_buf_release(iov[0].iov_base);
1079 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1080 /* return buffer to caller to free */
1081 *buf = iov[0].iov_base;
1082 if(resp_buf_type == CIFS_SMALL_BUFFER)
1083 *pbuf_type = CIFS_SMALL_BUFFER;
1084 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1085 *pbuf_type = CIFS_LARGE_BUFFER;
1086 } /* else no valid buffer on return - leave as null */
1088 /* Note: On -EAGAIN error only caller can retry on handle based calls
1089 since file handle passed in no longer valid */
1090 return rc;
1095 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1096 const int netfid, const unsigned int count,
1097 const __u64 offset, unsigned int *nbytes, const char *buf,
1098 const char __user * ubuf, const int long_op)
1100 int rc = -EACCES;
1101 WRITE_REQ *pSMB = NULL;
1102 WRITE_RSP *pSMBr = NULL;
1103 int bytes_returned, wct;
1104 __u32 bytes_sent;
1105 __u16 byte_count;
1107 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1108 if(tcon->ses == NULL)
1109 return -ECONNABORTED;
1111 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1112 wct = 14;
1113 else
1114 wct = 12;
1116 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1117 (void **) &pSMBr);
1118 if (rc)
1119 return rc;
1120 /* tcon and ses pointer are checked in smb_init */
1121 if (tcon->ses->server == NULL)
1122 return -ECONNABORTED;
1124 pSMB->AndXCommand = 0xFF; /* none */
1125 pSMB->Fid = netfid;
1126 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1127 if(wct == 14)
1128 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1129 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1130 return -EIO;
1132 pSMB->Reserved = 0xFFFFFFFF;
1133 pSMB->WriteMode = 0;
1134 pSMB->Remaining = 0;
1136 /* Can increase buffer size if buffer is big enough in some cases - ie we
1137 can send more if LARGE_WRITE_X capability returned by the server and if
1138 our buffer is big enough or if we convert to iovecs on socket writes
1139 and eliminate the copy to the CIFS buffer */
1140 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1141 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1142 } else {
1143 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1144 & ~0xFF;
1147 if (bytes_sent > count)
1148 bytes_sent = count;
1149 pSMB->DataOffset =
1150 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1151 if(buf)
1152 memcpy(pSMB->Data,buf,bytes_sent);
1153 else if(ubuf) {
1154 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1155 cifs_buf_release(pSMB);
1156 return -EFAULT;
1158 } else if (count != 0) {
1159 /* No buffer */
1160 cifs_buf_release(pSMB);
1161 return -EINVAL;
1162 } /* else setting file size with write of zero bytes */
1163 if(wct == 14)
1164 byte_count = bytes_sent + 1; /* pad */
1165 else /* wct == 12 */ {
1166 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1168 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1169 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1170 pSMB->hdr.smb_buf_length += byte_count;
1172 if(wct == 14)
1173 pSMB->ByteCount = cpu_to_le16(byte_count);
1174 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
1175 struct smb_com_writex_req * pSMBW =
1176 (struct smb_com_writex_req *)pSMB;
1177 pSMBW->ByteCount = cpu_to_le16(byte_count);
1180 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1181 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1182 cifs_stats_inc(&tcon->num_writes);
1183 if (rc) {
1184 cFYI(1, ("Send error in write = %d", rc));
1185 *nbytes = 0;
1186 } else {
1187 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1188 *nbytes = (*nbytes) << 16;
1189 *nbytes += le16_to_cpu(pSMBr->Count);
1192 cifs_buf_release(pSMB);
1194 /* Note: On -EAGAIN error only caller can retry on handle based calls
1195 since file handle passed in no longer valid */
1197 return rc;
1201 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1202 const int netfid, const unsigned int count,
1203 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1204 int n_vec, const int long_op)
1206 int rc = -EACCES;
1207 WRITE_REQ *pSMB = NULL;
1208 int wct;
1209 int smb_hdr_len;
1210 int resp_buf_type = 0;
1212 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1214 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1215 wct = 14;
1216 else
1217 wct = 12;
1218 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1219 if (rc)
1220 return rc;
1221 /* tcon and ses pointer are checked in smb_init */
1222 if (tcon->ses->server == NULL)
1223 return -ECONNABORTED;
1225 pSMB->AndXCommand = 0xFF; /* none */
1226 pSMB->Fid = netfid;
1227 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1228 if(wct == 14)
1229 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1230 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1231 return -EIO;
1232 pSMB->Reserved = 0xFFFFFFFF;
1233 pSMB->WriteMode = 0;
1234 pSMB->Remaining = 0;
1236 pSMB->DataOffset =
1237 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1239 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1240 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1241 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1242 if(wct == 14)
1243 pSMB->hdr.smb_buf_length += count+1;
1244 else /* wct == 12 */
1245 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1246 if(wct == 14)
1247 pSMB->ByteCount = cpu_to_le16(count + 1);
1248 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1249 struct smb_com_writex_req * pSMBW =
1250 (struct smb_com_writex_req *)pSMB;
1251 pSMBW->ByteCount = cpu_to_le16(count + 5);
1253 iov[0].iov_base = pSMB;
1254 if(wct == 14)
1255 iov[0].iov_len = smb_hdr_len + 4;
1256 else /* wct == 12 pad bigger by four bytes */
1257 iov[0].iov_len = smb_hdr_len + 8;
1260 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1261 long_op);
1262 cifs_stats_inc(&tcon->num_writes);
1263 if (rc) {
1264 cFYI(1, ("Send error Write2 = %d", rc));
1265 *nbytes = 0;
1266 } else if(resp_buf_type == 0) {
1267 /* presumably this can not happen, but best to be safe */
1268 rc = -EIO;
1269 *nbytes = 0;
1270 } else {
1271 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1272 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1273 *nbytes = (*nbytes) << 16;
1274 *nbytes += le16_to_cpu(pSMBr->Count);
1277 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1278 if(resp_buf_type == CIFS_SMALL_BUFFER)
1279 cifs_small_buf_release(iov[0].iov_base);
1280 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1281 cifs_buf_release(iov[0].iov_base);
1283 /* Note: On -EAGAIN error only caller can retry on handle based calls
1284 since file handle passed in no longer valid */
1286 return rc;
1291 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1292 const __u16 smb_file_id, const __u64 len,
1293 const __u64 offset, const __u32 numUnlock,
1294 const __u32 numLock, const __u8 lockType, const int waitFlag)
1296 int rc = 0;
1297 LOCK_REQ *pSMB = NULL;
1298 LOCK_RSP *pSMBr = NULL;
1299 int bytes_returned;
1300 int timeout = 0;
1301 __u16 count;
1303 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1304 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1306 if (rc)
1307 return rc;
1309 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1311 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1312 timeout = -1; /* no response expected */
1313 pSMB->Timeout = 0;
1314 } else if (waitFlag == TRUE) {
1315 timeout = 3; /* blocking operation, no timeout */
1316 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1317 } else {
1318 pSMB->Timeout = 0;
1321 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1322 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1323 pSMB->LockType = lockType;
1324 pSMB->AndXCommand = 0xFF; /* none */
1325 pSMB->Fid = smb_file_id; /* netfid stays le */
1327 if((numLock != 0) || (numUnlock != 0)) {
1328 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1329 /* BB where to store pid high? */
1330 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1331 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1332 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1333 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1334 count = sizeof(LOCKING_ANDX_RANGE);
1335 } else {
1336 /* oplock break */
1337 count = 0;
1339 pSMB->hdr.smb_buf_length += count;
1340 pSMB->ByteCount = cpu_to_le16(count);
1342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1344 cifs_stats_inc(&tcon->num_locks);
1345 if (rc) {
1346 cFYI(1, ("Send error in Lock = %d", rc));
1348 cifs_small_buf_release(pSMB);
1350 /* Note: On -EAGAIN error only caller can retry on handle based calls
1351 since file handle passed in no longer valid */
1352 return rc;
1356 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1358 int rc = 0;
1359 CLOSE_REQ *pSMB = NULL;
1360 CLOSE_RSP *pSMBr = NULL;
1361 int bytes_returned;
1362 cFYI(1, ("In CIFSSMBClose"));
1364 /* do not retry on dead session on close */
1365 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1366 if(rc == -EAGAIN)
1367 return 0;
1368 if (rc)
1369 return rc;
1371 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1373 pSMB->FileID = (__u16) smb_file_id;
1374 pSMB->LastWriteTime = 0;
1375 pSMB->ByteCount = 0;
1376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1378 cifs_stats_inc(&tcon->num_closes);
1379 if (rc) {
1380 if(rc!=-EINTR) {
1381 /* EINTR is expected when user ctl-c to kill app */
1382 cERROR(1, ("Send error in Close = %d", rc));
1386 cifs_small_buf_release(pSMB);
1388 /* Since session is dead, file will be closed on server already */
1389 if(rc == -EAGAIN)
1390 rc = 0;
1392 return rc;
1396 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1397 const char *fromName, const char *toName,
1398 const struct nls_table *nls_codepage, int remap)
1400 int rc = 0;
1401 RENAME_REQ *pSMB = NULL;
1402 RENAME_RSP *pSMBr = NULL;
1403 int bytes_returned;
1404 int name_len, name_len2;
1405 __u16 count;
1407 cFYI(1, ("In CIFSSMBRename"));
1408 renameRetry:
1409 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1410 (void **) &pSMBr);
1411 if (rc)
1412 return rc;
1414 pSMB->BufferFormat = 0x04;
1415 pSMB->SearchAttributes =
1416 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1417 ATTR_DIRECTORY);
1419 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1420 name_len =
1421 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1422 PATH_MAX, nls_codepage, remap);
1423 name_len++; /* trailing null */
1424 name_len *= 2;
1425 pSMB->OldFileName[name_len] = 0x04; /* pad */
1426 /* protocol requires ASCII signature byte on Unicode string */
1427 pSMB->OldFileName[name_len + 1] = 0x00;
1428 name_len2 =
1429 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1430 toName, PATH_MAX, nls_codepage, remap);
1431 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1432 name_len2 *= 2; /* convert to bytes */
1433 } else { /* BB improve the check for buffer overruns BB */
1434 name_len = strnlen(fromName, PATH_MAX);
1435 name_len++; /* trailing null */
1436 strncpy(pSMB->OldFileName, fromName, name_len);
1437 name_len2 = strnlen(toName, PATH_MAX);
1438 name_len2++; /* trailing null */
1439 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1440 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1441 name_len2++; /* trailing null */
1442 name_len2++; /* signature byte */
1445 count = 1 /* 1st signature byte */ + name_len + name_len2;
1446 pSMB->hdr.smb_buf_length += count;
1447 pSMB->ByteCount = cpu_to_le16(count);
1449 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1451 cifs_stats_inc(&tcon->num_renames);
1452 if (rc) {
1453 cFYI(1, ("Send error in rename = %d", rc));
1456 cifs_buf_release(pSMB);
1458 if (rc == -EAGAIN)
1459 goto renameRetry;
1461 return rc;
1464 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1465 int netfid, char * target_name,
1466 const struct nls_table * nls_codepage, int remap)
1468 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1469 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1470 struct set_file_rename * rename_info;
1471 char *data_offset;
1472 char dummy_string[30];
1473 int rc = 0;
1474 int bytes_returned = 0;
1475 int len_of_str;
1476 __u16 params, param_offset, offset, count, byte_count;
1478 cFYI(1, ("Rename to File by handle"));
1479 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1480 (void **) &pSMBr);
1481 if (rc)
1482 return rc;
1484 params = 6;
1485 pSMB->MaxSetupCount = 0;
1486 pSMB->Reserved = 0;
1487 pSMB->Flags = 0;
1488 pSMB->Timeout = 0;
1489 pSMB->Reserved2 = 0;
1490 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1491 offset = param_offset + params;
1493 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1494 rename_info = (struct set_file_rename *) data_offset;
1495 pSMB->MaxParameterCount = cpu_to_le16(2);
1496 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1497 pSMB->SetupCount = 1;
1498 pSMB->Reserved3 = 0;
1499 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1500 byte_count = 3 /* pad */ + params;
1501 pSMB->ParameterCount = cpu_to_le16(params);
1502 pSMB->TotalParameterCount = pSMB->ParameterCount;
1503 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1504 pSMB->DataOffset = cpu_to_le16(offset);
1505 /* construct random name ".cifs_tmp<inodenum><mid>" */
1506 rename_info->overwrite = cpu_to_le32(1);
1507 rename_info->root_fid = 0;
1508 /* unicode only call */
1509 if(target_name == NULL) {
1510 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1511 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1512 dummy_string, 24, nls_codepage, remap);
1513 } else {
1514 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1515 target_name, PATH_MAX, nls_codepage, remap);
1517 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1518 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1519 byte_count += count;
1520 pSMB->DataCount = cpu_to_le16(count);
1521 pSMB->TotalDataCount = pSMB->DataCount;
1522 pSMB->Fid = netfid;
1523 pSMB->InformationLevel =
1524 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1525 pSMB->Reserved4 = 0;
1526 pSMB->hdr.smb_buf_length += byte_count;
1527 pSMB->ByteCount = cpu_to_le16(byte_count);
1528 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1529 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1530 cifs_stats_inc(&pTcon->num_t2renames);
1531 if (rc) {
1532 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1535 cifs_buf_release(pSMB);
1537 /* Note: On -EAGAIN error only caller can retry on handle based calls
1538 since file handle passed in no longer valid */
1540 return rc;
1544 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1545 const __u16 target_tid, const char *toName, const int flags,
1546 const struct nls_table *nls_codepage, int remap)
1548 int rc = 0;
1549 COPY_REQ *pSMB = NULL;
1550 COPY_RSP *pSMBr = NULL;
1551 int bytes_returned;
1552 int name_len, name_len2;
1553 __u16 count;
1555 cFYI(1, ("In CIFSSMBCopy"));
1556 copyRetry:
1557 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1558 (void **) &pSMBr);
1559 if (rc)
1560 return rc;
1562 pSMB->BufferFormat = 0x04;
1563 pSMB->Tid2 = target_tid;
1565 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1567 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1568 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1569 fromName, PATH_MAX, nls_codepage,
1570 remap);
1571 name_len++; /* trailing null */
1572 name_len *= 2;
1573 pSMB->OldFileName[name_len] = 0x04; /* pad */
1574 /* protocol requires ASCII signature byte on Unicode string */
1575 pSMB->OldFileName[name_len + 1] = 0x00;
1576 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1577 toName, PATH_MAX, nls_codepage, remap);
1578 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1579 name_len2 *= 2; /* convert to bytes */
1580 } else { /* BB improve the check for buffer overruns BB */
1581 name_len = strnlen(fromName, PATH_MAX);
1582 name_len++; /* trailing null */
1583 strncpy(pSMB->OldFileName, fromName, name_len);
1584 name_len2 = strnlen(toName, PATH_MAX);
1585 name_len2++; /* trailing null */
1586 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1587 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1588 name_len2++; /* trailing null */
1589 name_len2++; /* signature byte */
1592 count = 1 /* 1st signature byte */ + name_len + name_len2;
1593 pSMB->hdr.smb_buf_length += count;
1594 pSMB->ByteCount = cpu_to_le16(count);
1596 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1597 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1598 if (rc) {
1599 cFYI(1, ("Send error in copy = %d with %d files copied",
1600 rc, le16_to_cpu(pSMBr->CopyCount)));
1602 if (pSMB)
1603 cifs_buf_release(pSMB);
1605 if (rc == -EAGAIN)
1606 goto copyRetry;
1608 return rc;
1612 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1613 const char *fromName, const char *toName,
1614 const struct nls_table *nls_codepage)
1616 TRANSACTION2_SPI_REQ *pSMB = NULL;
1617 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1618 char *data_offset;
1619 int name_len;
1620 int name_len_target;
1621 int rc = 0;
1622 int bytes_returned = 0;
1623 __u16 params, param_offset, offset, byte_count;
1625 cFYI(1, ("In Symlink Unix style"));
1626 createSymLinkRetry:
1627 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1628 (void **) &pSMBr);
1629 if (rc)
1630 return rc;
1632 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1633 name_len =
1634 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1635 /* find define for this maxpathcomponent */
1636 , nls_codepage);
1637 name_len++; /* trailing null */
1638 name_len *= 2;
1640 } else { /* BB improve the check for buffer overruns BB */
1641 name_len = strnlen(fromName, PATH_MAX);
1642 name_len++; /* trailing null */
1643 strncpy(pSMB->FileName, fromName, name_len);
1645 params = 6 + name_len;
1646 pSMB->MaxSetupCount = 0;
1647 pSMB->Reserved = 0;
1648 pSMB->Flags = 0;
1649 pSMB->Timeout = 0;
1650 pSMB->Reserved2 = 0;
1651 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1652 InformationLevel) - 4;
1653 offset = param_offset + params;
1655 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1656 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1657 name_len_target =
1658 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1659 /* find define for this maxpathcomponent */
1660 , nls_codepage);
1661 name_len_target++; /* trailing null */
1662 name_len_target *= 2;
1663 } else { /* BB improve the check for buffer overruns BB */
1664 name_len_target = strnlen(toName, PATH_MAX);
1665 name_len_target++; /* trailing null */
1666 strncpy(data_offset, toName, name_len_target);
1669 pSMB->MaxParameterCount = cpu_to_le16(2);
1670 /* BB find exact max on data count below from sess */
1671 pSMB->MaxDataCount = cpu_to_le16(1000);
1672 pSMB->SetupCount = 1;
1673 pSMB->Reserved3 = 0;
1674 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1675 byte_count = 3 /* pad */ + params + name_len_target;
1676 pSMB->DataCount = cpu_to_le16(name_len_target);
1677 pSMB->ParameterCount = cpu_to_le16(params);
1678 pSMB->TotalDataCount = pSMB->DataCount;
1679 pSMB->TotalParameterCount = pSMB->ParameterCount;
1680 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1681 pSMB->DataOffset = cpu_to_le16(offset);
1682 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1683 pSMB->Reserved4 = 0;
1684 pSMB->hdr.smb_buf_length += byte_count;
1685 pSMB->ByteCount = cpu_to_le16(byte_count);
1686 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1687 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1688 cifs_stats_inc(&tcon->num_symlinks);
1689 if (rc) {
1690 cFYI(1,
1691 ("Send error in SetPathInfo (create symlink) = %d",
1692 rc));
1695 if (pSMB)
1696 cifs_buf_release(pSMB);
1698 if (rc == -EAGAIN)
1699 goto createSymLinkRetry;
1701 return rc;
1705 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1706 const char *fromName, const char *toName,
1707 const struct nls_table *nls_codepage, int remap)
1709 TRANSACTION2_SPI_REQ *pSMB = NULL;
1710 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1711 char *data_offset;
1712 int name_len;
1713 int name_len_target;
1714 int rc = 0;
1715 int bytes_returned = 0;
1716 __u16 params, param_offset, offset, byte_count;
1718 cFYI(1, ("In Create Hard link Unix style"));
1719 createHardLinkRetry:
1720 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1721 (void **) &pSMBr);
1722 if (rc)
1723 return rc;
1725 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1726 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1727 PATH_MAX, nls_codepage, remap);
1728 name_len++; /* trailing null */
1729 name_len *= 2;
1731 } else { /* BB improve the check for buffer overruns BB */
1732 name_len = strnlen(toName, PATH_MAX);
1733 name_len++; /* trailing null */
1734 strncpy(pSMB->FileName, toName, name_len);
1736 params = 6 + name_len;
1737 pSMB->MaxSetupCount = 0;
1738 pSMB->Reserved = 0;
1739 pSMB->Flags = 0;
1740 pSMB->Timeout = 0;
1741 pSMB->Reserved2 = 0;
1742 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1743 InformationLevel) - 4;
1744 offset = param_offset + params;
1746 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1747 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1748 name_len_target =
1749 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1750 nls_codepage, remap);
1751 name_len_target++; /* trailing null */
1752 name_len_target *= 2;
1753 } else { /* BB improve the check for buffer overruns BB */
1754 name_len_target = strnlen(fromName, PATH_MAX);
1755 name_len_target++; /* trailing null */
1756 strncpy(data_offset, fromName, name_len_target);
1759 pSMB->MaxParameterCount = cpu_to_le16(2);
1760 /* BB find exact max on data count below from sess*/
1761 pSMB->MaxDataCount = cpu_to_le16(1000);
1762 pSMB->SetupCount = 1;
1763 pSMB->Reserved3 = 0;
1764 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1765 byte_count = 3 /* pad */ + params + name_len_target;
1766 pSMB->ParameterCount = cpu_to_le16(params);
1767 pSMB->TotalParameterCount = pSMB->ParameterCount;
1768 pSMB->DataCount = cpu_to_le16(name_len_target);
1769 pSMB->TotalDataCount = pSMB->DataCount;
1770 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1771 pSMB->DataOffset = cpu_to_le16(offset);
1772 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1773 pSMB->Reserved4 = 0;
1774 pSMB->hdr.smb_buf_length += byte_count;
1775 pSMB->ByteCount = cpu_to_le16(byte_count);
1776 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1777 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1778 cifs_stats_inc(&tcon->num_hardlinks);
1779 if (rc) {
1780 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1783 cifs_buf_release(pSMB);
1784 if (rc == -EAGAIN)
1785 goto createHardLinkRetry;
1787 return rc;
1791 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1792 const char *fromName, const char *toName,
1793 const struct nls_table *nls_codepage, int remap)
1795 int rc = 0;
1796 NT_RENAME_REQ *pSMB = NULL;
1797 RENAME_RSP *pSMBr = NULL;
1798 int bytes_returned;
1799 int name_len, name_len2;
1800 __u16 count;
1802 cFYI(1, ("In CIFSCreateHardLink"));
1803 winCreateHardLinkRetry:
1805 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1806 (void **) &pSMBr);
1807 if (rc)
1808 return rc;
1810 pSMB->SearchAttributes =
1811 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1812 ATTR_DIRECTORY);
1813 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1814 pSMB->ClusterCount = 0;
1816 pSMB->BufferFormat = 0x04;
1818 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1819 name_len =
1820 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1821 PATH_MAX, nls_codepage, remap);
1822 name_len++; /* trailing null */
1823 name_len *= 2;
1824 pSMB->OldFileName[name_len] = 0; /* pad */
1825 pSMB->OldFileName[name_len + 1] = 0x04;
1826 name_len2 =
1827 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1828 toName, PATH_MAX, nls_codepage, remap);
1829 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1830 name_len2 *= 2; /* convert to bytes */
1831 } else { /* BB improve the check for buffer overruns BB */
1832 name_len = strnlen(fromName, PATH_MAX);
1833 name_len++; /* trailing null */
1834 strncpy(pSMB->OldFileName, fromName, name_len);
1835 name_len2 = strnlen(toName, PATH_MAX);
1836 name_len2++; /* trailing null */
1837 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1838 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1839 name_len2++; /* trailing null */
1840 name_len2++; /* signature byte */
1843 count = 1 /* string type byte */ + name_len + name_len2;
1844 pSMB->hdr.smb_buf_length += count;
1845 pSMB->ByteCount = cpu_to_le16(count);
1847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1849 cifs_stats_inc(&tcon->num_hardlinks);
1850 if (rc) {
1851 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1853 cifs_buf_release(pSMB);
1854 if (rc == -EAGAIN)
1855 goto winCreateHardLinkRetry;
1857 return rc;
1861 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1862 const unsigned char *searchName,
1863 char *symlinkinfo, const int buflen,
1864 const struct nls_table *nls_codepage)
1866 /* SMB_QUERY_FILE_UNIX_LINK */
1867 TRANSACTION2_QPI_REQ *pSMB = NULL;
1868 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1869 int rc = 0;
1870 int bytes_returned;
1871 int name_len;
1872 __u16 params, byte_count;
1874 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1876 querySymLinkRetry:
1877 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1878 (void **) &pSMBr);
1879 if (rc)
1880 return rc;
1882 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1883 name_len =
1884 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1885 /* find define for this maxpathcomponent */
1886 , nls_codepage);
1887 name_len++; /* trailing null */
1888 name_len *= 2;
1889 } else { /* BB improve the check for buffer overruns BB */
1890 name_len = strnlen(searchName, PATH_MAX);
1891 name_len++; /* trailing null */
1892 strncpy(pSMB->FileName, searchName, name_len);
1895 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1896 pSMB->TotalDataCount = 0;
1897 pSMB->MaxParameterCount = cpu_to_le16(2);
1898 /* BB find exact max data count below from sess structure BB */
1899 pSMB->MaxDataCount = cpu_to_le16(4000);
1900 pSMB->MaxSetupCount = 0;
1901 pSMB->Reserved = 0;
1902 pSMB->Flags = 0;
1903 pSMB->Timeout = 0;
1904 pSMB->Reserved2 = 0;
1905 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1906 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1907 pSMB->DataCount = 0;
1908 pSMB->DataOffset = 0;
1909 pSMB->SetupCount = 1;
1910 pSMB->Reserved3 = 0;
1911 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1912 byte_count = params + 1 /* pad */ ;
1913 pSMB->TotalParameterCount = cpu_to_le16(params);
1914 pSMB->ParameterCount = pSMB->TotalParameterCount;
1915 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1916 pSMB->Reserved4 = 0;
1917 pSMB->hdr.smb_buf_length += byte_count;
1918 pSMB->ByteCount = cpu_to_le16(byte_count);
1920 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1921 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1922 if (rc) {
1923 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1924 } else {
1925 /* decode response */
1927 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1928 if (rc || (pSMBr->ByteCount < 2))
1929 /* BB also check enough total bytes returned */
1930 rc = -EIO; /* bad smb */
1931 else {
1932 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1933 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1935 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1936 name_len = UniStrnlen((wchar_t *) ((char *)
1937 &pSMBr->hdr.Protocol +data_offset),
1938 min_t(const int, buflen,count) / 2);
1939 /* BB FIXME investigate remapping reserved chars here */
1940 cifs_strfromUCS_le(symlinkinfo,
1941 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
1942 data_offset),
1943 name_len, nls_codepage);
1944 } else {
1945 strncpy(symlinkinfo,
1946 (char *) &pSMBr->hdr.Protocol +
1947 data_offset,
1948 min_t(const int, buflen, count));
1950 symlinkinfo[buflen] = 0;
1951 /* just in case so calling code does not go off the end of buffer */
1954 cifs_buf_release(pSMB);
1955 if (rc == -EAGAIN)
1956 goto querySymLinkRetry;
1957 return rc;
1960 /* Initialize NT TRANSACT SMB into small smb request buffer.
1961 This assumes that all NT TRANSACTS that we init here have
1962 total parm and data under about 400 bytes (to fit in small cifs
1963 buffer size), which is the case so far, it easily fits. NB:
1964 Setup words themselves and ByteCount
1965 MaxSetupCount (size of returned setup area) and
1966 MaxParameterCount (returned parms size) must be set by caller */
1967 static int
1968 smb_init_ntransact(const __u16 sub_command, const int setup_count,
1969 const int parm_len, struct cifsTconInfo *tcon,
1970 void ** ret_buf)
1972 int rc;
1973 __u32 temp_offset;
1974 struct smb_com_ntransact_req * pSMB;
1976 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1977 (void **)&pSMB);
1978 if (rc)
1979 return rc;
1980 *ret_buf = (void *)pSMB;
1981 pSMB->Reserved = 0;
1982 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1983 pSMB->TotalDataCount = 0;
1984 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1985 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1986 pSMB->ParameterCount = pSMB->TotalParameterCount;
1987 pSMB->DataCount = pSMB->TotalDataCount;
1988 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1989 (setup_count * 2) - 4 /* for rfc1001 length itself */;
1990 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1991 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1992 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1993 pSMB->SubCommand = cpu_to_le16(sub_command);
1994 return 0;
1997 static int
1998 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1999 int * pdatalen, int * pparmlen)
2001 char * end_of_smb;
2002 __u32 data_count, data_offset, parm_count, parm_offset;
2003 struct smb_com_ntransact_rsp * pSMBr;
2005 if(buf == NULL)
2006 return -EINVAL;
2008 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2010 /* ByteCount was converted from little endian in SendReceive */
2011 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2012 (char *)&pSMBr->ByteCount;
2015 data_offset = le32_to_cpu(pSMBr->DataOffset);
2016 data_count = le32_to_cpu(pSMBr->DataCount);
2017 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2018 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2020 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2021 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2023 /* should we also check that parm and data areas do not overlap? */
2024 if(*ppparm > end_of_smb) {
2025 cFYI(1,("parms start after end of smb"));
2026 return -EINVAL;
2027 } else if(parm_count + *ppparm > end_of_smb) {
2028 cFYI(1,("parm end after end of smb"));
2029 return -EINVAL;
2030 } else if(*ppdata > end_of_smb) {
2031 cFYI(1,("data starts after end of smb"));
2032 return -EINVAL;
2033 } else if(data_count + *ppdata > end_of_smb) {
2034 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2035 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2036 return -EINVAL;
2037 } else if(parm_count + data_count > pSMBr->ByteCount) {
2038 cFYI(1,("parm count and data count larger than SMB"));
2039 return -EINVAL;
2041 return 0;
2045 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2046 const unsigned char *searchName,
2047 char *symlinkinfo, const int buflen,__u16 fid,
2048 const struct nls_table *nls_codepage)
2050 int rc = 0;
2051 int bytes_returned;
2052 int name_len;
2053 struct smb_com_transaction_ioctl_req * pSMB;
2054 struct smb_com_transaction_ioctl_rsp * pSMBr;
2056 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2057 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2058 (void **) &pSMBr);
2059 if (rc)
2060 return rc;
2062 pSMB->TotalParameterCount = 0 ;
2063 pSMB->TotalDataCount = 0;
2064 pSMB->MaxParameterCount = cpu_to_le32(2);
2065 /* BB find exact data count max from sess structure BB */
2066 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2067 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2068 pSMB->MaxSetupCount = 4;
2069 pSMB->Reserved = 0;
2070 pSMB->ParameterOffset = 0;
2071 pSMB->DataCount = 0;
2072 pSMB->DataOffset = 0;
2073 pSMB->SetupCount = 4;
2074 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2075 pSMB->ParameterCount = pSMB->TotalParameterCount;
2076 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2077 pSMB->IsFsctl = 1; /* FSCTL */
2078 pSMB->IsRootFlag = 0;
2079 pSMB->Fid = fid; /* file handle always le */
2080 pSMB->ByteCount = 0;
2082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2084 if (rc) {
2085 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2086 } else { /* decode response */
2087 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2088 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2089 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2090 /* BB also check enough total bytes returned */
2091 rc = -EIO; /* bad smb */
2092 else {
2093 if(data_count && (data_count < 2048)) {
2094 char * end_of_smb = 2 /* sizeof byte count */ +
2095 pSMBr->ByteCount +
2096 (char *)&pSMBr->ByteCount;
2098 struct reparse_data * reparse_buf = (struct reparse_data *)
2099 ((char *)&pSMBr->hdr.Protocol + data_offset);
2100 if((char*)reparse_buf >= end_of_smb) {
2101 rc = -EIO;
2102 goto qreparse_out;
2104 if((reparse_buf->LinkNamesBuf +
2105 reparse_buf->TargetNameOffset +
2106 reparse_buf->TargetNameLen) >
2107 end_of_smb) {
2108 cFYI(1,("reparse buf extended beyond SMB"));
2109 rc = -EIO;
2110 goto qreparse_out;
2113 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2114 name_len = UniStrnlen((wchar_t *)
2115 (reparse_buf->LinkNamesBuf +
2116 reparse_buf->TargetNameOffset),
2117 min(buflen/2, reparse_buf->TargetNameLen / 2));
2118 cifs_strfromUCS_le(symlinkinfo,
2119 (__le16 *) (reparse_buf->LinkNamesBuf +
2120 reparse_buf->TargetNameOffset),
2121 name_len, nls_codepage);
2122 } else { /* ASCII names */
2123 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2124 reparse_buf->TargetNameOffset,
2125 min_t(const int, buflen, reparse_buf->TargetNameLen));
2127 } else {
2128 rc = -EIO;
2129 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2131 symlinkinfo[buflen] = 0; /* just in case so the caller
2132 does not go off the end of the buffer */
2133 cFYI(1,("readlink result - %s ",symlinkinfo));
2136 qreparse_out:
2137 cifs_buf_release(pSMB);
2139 /* Note: On -EAGAIN error only caller can retry on handle based calls
2140 since file handle passed in no longer valid */
2142 return rc;
2145 #ifdef CONFIG_CIFS_POSIX
2147 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2148 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2150 /* u8 cifs fields do not need le conversion */
2151 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2152 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2153 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2154 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2156 return;
2159 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2160 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2161 const int acl_type,const int size_of_data_area)
2163 int size = 0;
2164 int i;
2165 __u16 count;
2166 struct cifs_posix_ace * pACE;
2167 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2168 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2170 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2171 return -EOPNOTSUPP;
2173 if(acl_type & ACL_TYPE_ACCESS) {
2174 count = le16_to_cpu(cifs_acl->access_entry_count);
2175 pACE = &cifs_acl->ace_array[0];
2176 size = sizeof(struct cifs_posix_acl);
2177 size += sizeof(struct cifs_posix_ace) * count;
2178 /* check if we would go beyond end of SMB */
2179 if(size_of_data_area < size) {
2180 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2181 return -EINVAL;
2183 } else if(acl_type & ACL_TYPE_DEFAULT) {
2184 count = le16_to_cpu(cifs_acl->access_entry_count);
2185 size = sizeof(struct cifs_posix_acl);
2186 size += sizeof(struct cifs_posix_ace) * count;
2187 /* skip past access ACEs to get to default ACEs */
2188 pACE = &cifs_acl->ace_array[count];
2189 count = le16_to_cpu(cifs_acl->default_entry_count);
2190 size += sizeof(struct cifs_posix_ace) * count;
2191 /* check if we would go beyond end of SMB */
2192 if(size_of_data_area < size)
2193 return -EINVAL;
2194 } else {
2195 /* illegal type */
2196 return -EINVAL;
2199 size = posix_acl_xattr_size(count);
2200 if((buflen == 0) || (local_acl == NULL)) {
2201 /* used to query ACL EA size */
2202 } else if(size > buflen) {
2203 return -ERANGE;
2204 } else /* buffer big enough */ {
2205 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2206 for(i = 0;i < count ;i++) {
2207 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2208 pACE ++;
2211 return size;
2214 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2215 const posix_acl_xattr_entry * local_ace)
2217 __u16 rc = 0; /* 0 = ACL converted ok */
2219 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2220 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2221 /* BB is there a better way to handle the large uid? */
2222 if(local_ace->e_id == cpu_to_le32(-1)) {
2223 /* Probably no need to le convert -1 on any arch but can not hurt */
2224 cifs_ace->cifs_uid = cpu_to_le64(-1);
2225 } else
2226 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2227 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2228 return rc;
2231 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2232 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2233 const int acl_type)
2235 __u16 rc = 0;
2236 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2237 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2238 int count;
2239 int i;
2241 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2242 return 0;
2244 count = posix_acl_xattr_count((size_t)buflen);
2245 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2246 count, buflen, le32_to_cpu(local_acl->a_version)));
2247 if(le32_to_cpu(local_acl->a_version) != 2) {
2248 cFYI(1,("unknown POSIX ACL version %d",
2249 le32_to_cpu(local_acl->a_version)));
2250 return 0;
2252 cifs_acl->version = cpu_to_le16(1);
2253 if(acl_type == ACL_TYPE_ACCESS)
2254 cifs_acl->access_entry_count = cpu_to_le16(count);
2255 else if(acl_type == ACL_TYPE_DEFAULT)
2256 cifs_acl->default_entry_count = cpu_to_le16(count);
2257 else {
2258 cFYI(1,("unknown ACL type %d",acl_type));
2259 return 0;
2261 for(i=0;i<count;i++) {
2262 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2263 &local_acl->a_entries[i]);
2264 if(rc != 0) {
2265 /* ACE not converted */
2266 break;
2269 if(rc == 0) {
2270 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2271 rc += sizeof(struct cifs_posix_acl);
2272 /* BB add check to make sure ACL does not overflow SMB */
2274 return rc;
2278 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2279 const unsigned char *searchName,
2280 char *acl_inf, const int buflen, const int acl_type,
2281 const struct nls_table *nls_codepage, int remap)
2283 /* SMB_QUERY_POSIX_ACL */
2284 TRANSACTION2_QPI_REQ *pSMB = NULL;
2285 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2286 int rc = 0;
2287 int bytes_returned;
2288 int name_len;
2289 __u16 params, byte_count;
2291 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2293 queryAclRetry:
2294 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2295 (void **) &pSMBr);
2296 if (rc)
2297 return rc;
2299 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2300 name_len =
2301 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2302 PATH_MAX, nls_codepage, remap);
2303 name_len++; /* trailing null */
2304 name_len *= 2;
2305 pSMB->FileName[name_len] = 0;
2306 pSMB->FileName[name_len+1] = 0;
2307 } else { /* BB improve the check for buffer overruns BB */
2308 name_len = strnlen(searchName, PATH_MAX);
2309 name_len++; /* trailing null */
2310 strncpy(pSMB->FileName, searchName, name_len);
2313 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2314 pSMB->TotalDataCount = 0;
2315 pSMB->MaxParameterCount = cpu_to_le16(2);
2316 /* BB find exact max data count below from sess structure BB */
2317 pSMB->MaxDataCount = cpu_to_le16(4000);
2318 pSMB->MaxSetupCount = 0;
2319 pSMB->Reserved = 0;
2320 pSMB->Flags = 0;
2321 pSMB->Timeout = 0;
2322 pSMB->Reserved2 = 0;
2323 pSMB->ParameterOffset = cpu_to_le16(
2324 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2325 pSMB->DataCount = 0;
2326 pSMB->DataOffset = 0;
2327 pSMB->SetupCount = 1;
2328 pSMB->Reserved3 = 0;
2329 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2330 byte_count = params + 1 /* pad */ ;
2331 pSMB->TotalParameterCount = cpu_to_le16(params);
2332 pSMB->ParameterCount = pSMB->TotalParameterCount;
2333 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2334 pSMB->Reserved4 = 0;
2335 pSMB->hdr.smb_buf_length += byte_count;
2336 pSMB->ByteCount = cpu_to_le16(byte_count);
2338 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2339 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2340 cifs_stats_inc(&tcon->num_acl_get);
2341 if (rc) {
2342 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2343 } else {
2344 /* decode response */
2346 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2347 if (rc || (pSMBr->ByteCount < 2))
2348 /* BB also check enough total bytes returned */
2349 rc = -EIO; /* bad smb */
2350 else {
2351 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2352 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2353 rc = cifs_copy_posix_acl(acl_inf,
2354 (char *)&pSMBr->hdr.Protocol+data_offset,
2355 buflen,acl_type,count);
2358 cifs_buf_release(pSMB);
2359 if (rc == -EAGAIN)
2360 goto queryAclRetry;
2361 return rc;
2365 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2366 const unsigned char *fileName,
2367 const char *local_acl, const int buflen,
2368 const int acl_type,
2369 const struct nls_table *nls_codepage, int remap)
2371 struct smb_com_transaction2_spi_req *pSMB = NULL;
2372 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2373 char *parm_data;
2374 int name_len;
2375 int rc = 0;
2376 int bytes_returned = 0;
2377 __u16 params, byte_count, data_count, param_offset, offset;
2379 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2380 setAclRetry:
2381 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2382 (void **) &pSMBr);
2383 if (rc)
2384 return rc;
2385 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2386 name_len =
2387 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2388 PATH_MAX, nls_codepage, remap);
2389 name_len++; /* trailing null */
2390 name_len *= 2;
2391 } else { /* BB improve the check for buffer overruns BB */
2392 name_len = strnlen(fileName, PATH_MAX);
2393 name_len++; /* trailing null */
2394 strncpy(pSMB->FileName, fileName, name_len);
2396 params = 6 + name_len;
2397 pSMB->MaxParameterCount = cpu_to_le16(2);
2398 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2399 pSMB->MaxSetupCount = 0;
2400 pSMB->Reserved = 0;
2401 pSMB->Flags = 0;
2402 pSMB->Timeout = 0;
2403 pSMB->Reserved2 = 0;
2404 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2405 InformationLevel) - 4;
2406 offset = param_offset + params;
2407 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2408 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2410 /* convert to on the wire format for POSIX ACL */
2411 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2413 if(data_count == 0) {
2414 rc = -EOPNOTSUPP;
2415 goto setACLerrorExit;
2417 pSMB->DataOffset = cpu_to_le16(offset);
2418 pSMB->SetupCount = 1;
2419 pSMB->Reserved3 = 0;
2420 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2421 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2422 byte_count = 3 /* pad */ + params + data_count;
2423 pSMB->DataCount = cpu_to_le16(data_count);
2424 pSMB->TotalDataCount = pSMB->DataCount;
2425 pSMB->ParameterCount = cpu_to_le16(params);
2426 pSMB->TotalParameterCount = pSMB->ParameterCount;
2427 pSMB->Reserved4 = 0;
2428 pSMB->hdr.smb_buf_length += byte_count;
2429 pSMB->ByteCount = cpu_to_le16(byte_count);
2430 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2431 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2432 if (rc) {
2433 cFYI(1, ("Set POSIX ACL returned %d", rc));
2436 setACLerrorExit:
2437 cifs_buf_release(pSMB);
2438 if (rc == -EAGAIN)
2439 goto setAclRetry;
2440 return rc;
2443 /* BB fix tabs in this function FIXME BB */
2445 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2446 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2448 int rc = 0;
2449 struct smb_t2_qfi_req *pSMB = NULL;
2450 struct smb_t2_qfi_rsp *pSMBr = NULL;
2451 int bytes_returned;
2452 __u16 params, byte_count;
2454 cFYI(1,("In GetExtAttr"));
2455 if(tcon == NULL)
2456 return -ENODEV;
2458 GetExtAttrRetry:
2459 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2460 (void **) &pSMBr);
2461 if (rc)
2462 return rc;
2464 params = 2 /* level */ +2 /* fid */;
2465 pSMB->t2.TotalDataCount = 0;
2466 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2467 /* BB find exact max data count below from sess structure BB */
2468 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2469 pSMB->t2.MaxSetupCount = 0;
2470 pSMB->t2.Reserved = 0;
2471 pSMB->t2.Flags = 0;
2472 pSMB->t2.Timeout = 0;
2473 pSMB->t2.Reserved2 = 0;
2474 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2475 Fid) - 4);
2476 pSMB->t2.DataCount = 0;
2477 pSMB->t2.DataOffset = 0;
2478 pSMB->t2.SetupCount = 1;
2479 pSMB->t2.Reserved3 = 0;
2480 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2481 byte_count = params + 1 /* pad */ ;
2482 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2483 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2484 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2485 pSMB->Pad = 0;
2486 pSMB->Fid = netfid;
2487 pSMB->hdr.smb_buf_length += byte_count;
2488 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2492 if (rc) {
2493 cFYI(1, ("error %d in GetExtAttr", rc));
2494 } else {
2495 /* decode response */
2496 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2497 if (rc || (pSMBr->ByteCount < 2))
2498 /* BB also check enough total bytes returned */
2499 /* If rc should we check for EOPNOSUPP and
2500 disable the srvino flag? or in caller? */
2501 rc = -EIO; /* bad smb */
2502 else {
2503 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2504 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2505 struct file_chattr_info * pfinfo;
2506 /* BB Do we need a cast or hash here ? */
2507 if(count != 16) {
2508 cFYI(1, ("Illegal size ret in GetExtAttr"));
2509 rc = -EIO;
2510 goto GetExtAttrOut;
2512 pfinfo = (struct file_chattr_info *)
2513 (data_offset + (char *) &pSMBr->hdr.Protocol);
2514 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2515 *pMask = le64_to_cpu(pfinfo->mask);
2518 GetExtAttrOut:
2519 cifs_buf_release(pSMB);
2520 if (rc == -EAGAIN)
2521 goto GetExtAttrRetry;
2522 return rc;
2526 #endif /* CONFIG_POSIX */
2529 /* security id for everyone */
2530 const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2531 /* group users */
2532 const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2534 /* Convert CIFS ACL to POSIX form */
2535 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2537 return 0;
2540 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2542 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2543 /* BB fix up return info */ char *acl_inf, const int buflen,
2544 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2546 int rc = 0;
2547 int buf_type = 0;
2548 QUERY_SEC_DESC_REQ * pSMB;
2549 struct kvec iov[1];
2551 cFYI(1, ("GetCifsACL"));
2553 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2554 8 /* parm len */, tcon, (void **) &pSMB);
2555 if (rc)
2556 return rc;
2558 pSMB->MaxParameterCount = cpu_to_le32(4);
2559 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2560 pSMB->MaxSetupCount = 0;
2561 pSMB->Fid = fid; /* file handle always le */
2562 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2563 CIFS_ACL_DACL);
2564 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2565 pSMB->hdr.smb_buf_length += 11;
2566 iov[0].iov_base = (char *)pSMB;
2567 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2569 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2570 cifs_stats_inc(&tcon->num_acl_get);
2571 if (rc) {
2572 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2573 } else { /* decode response */
2574 struct cifs_sid * psec_desc;
2575 __le32 * parm;
2576 int parm_len;
2577 int data_len;
2578 int acl_len;
2579 struct smb_com_ntransact_rsp * pSMBr;
2581 /* validate_nttransact */
2582 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2583 (char **)&psec_desc,
2584 &parm_len, &data_len);
2586 if(rc)
2587 goto qsec_out;
2588 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2590 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2592 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2593 rc = -EIO; /* bad smb */
2594 goto qsec_out;
2597 /* BB check that data area is minimum length and as big as acl_len */
2599 acl_len = le32_to_cpu(*(__le32 *)parm);
2600 /* BB check if(acl_len > bufsize) */
2602 parse_sec_desc(psec_desc, acl_len);
2604 qsec_out:
2605 if(buf_type == CIFS_SMALL_BUFFER)
2606 cifs_small_buf_release(iov[0].iov_base);
2607 else if(buf_type == CIFS_LARGE_BUFFER)
2608 cifs_buf_release(iov[0].iov_base);
2609 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2610 return rc;
2614 /* Legacy Query Path Information call for lookup to old servers such
2615 as Win9x/WinME */
2616 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2617 const unsigned char *searchName,
2618 FILE_ALL_INFO * pFinfo,
2619 const struct nls_table *nls_codepage, int remap)
2621 QUERY_INFORMATION_REQ * pSMB;
2622 QUERY_INFORMATION_RSP * pSMBr;
2623 int rc = 0;
2624 int bytes_returned;
2625 int name_len;
2627 cFYI(1, ("In SMBQPath path %s", searchName));
2628 QInfRetry:
2629 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2630 (void **) &pSMBr);
2631 if (rc)
2632 return rc;
2634 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2635 name_len =
2636 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2637 PATH_MAX, nls_codepage, remap);
2638 name_len++; /* trailing null */
2639 name_len *= 2;
2640 } else {
2641 name_len = strnlen(searchName, PATH_MAX);
2642 name_len++; /* trailing null */
2643 strncpy(pSMB->FileName, searchName, name_len);
2645 pSMB->BufferFormat = 0x04;
2646 name_len++; /* account for buffer type byte */
2647 pSMB->hdr.smb_buf_length += (__u16) name_len;
2648 pSMB->ByteCount = cpu_to_le16(name_len);
2650 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2651 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2652 if (rc) {
2653 cFYI(1, ("Send error in QueryInfo = %d", rc));
2654 } else if (pFinfo) { /* decode response */
2655 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2656 pFinfo->AllocationSize =
2657 cpu_to_le64(le32_to_cpu(pSMBr->size));
2658 pFinfo->EndOfFile = pFinfo->AllocationSize;
2659 pFinfo->Attributes =
2660 cpu_to_le32(le16_to_cpu(pSMBr->attr));
2661 } else
2662 rc = -EIO; /* bad buffer passed in */
2664 cifs_buf_release(pSMB);
2666 if (rc == -EAGAIN)
2667 goto QInfRetry;
2669 return rc;
2676 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2677 const unsigned char *searchName,
2678 FILE_ALL_INFO * pFindData,
2679 const struct nls_table *nls_codepage, int remap)
2681 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2682 TRANSACTION2_QPI_REQ *pSMB = NULL;
2683 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2684 int rc = 0;
2685 int bytes_returned;
2686 int name_len;
2687 __u16 params, byte_count;
2689 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2690 QPathInfoRetry:
2691 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2692 (void **) &pSMBr);
2693 if (rc)
2694 return rc;
2696 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2697 name_len =
2698 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2699 PATH_MAX, nls_codepage, remap);
2700 name_len++; /* trailing null */
2701 name_len *= 2;
2702 } else { /* BB improve the check for buffer overruns BB */
2703 name_len = strnlen(searchName, PATH_MAX);
2704 name_len++; /* trailing null */
2705 strncpy(pSMB->FileName, searchName, name_len);
2708 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2709 pSMB->TotalDataCount = 0;
2710 pSMB->MaxParameterCount = cpu_to_le16(2);
2711 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2712 pSMB->MaxSetupCount = 0;
2713 pSMB->Reserved = 0;
2714 pSMB->Flags = 0;
2715 pSMB->Timeout = 0;
2716 pSMB->Reserved2 = 0;
2717 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2718 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2719 pSMB->DataCount = 0;
2720 pSMB->DataOffset = 0;
2721 pSMB->SetupCount = 1;
2722 pSMB->Reserved3 = 0;
2723 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2724 byte_count = params + 1 /* pad */ ;
2725 pSMB->TotalParameterCount = cpu_to_le16(params);
2726 pSMB->ParameterCount = pSMB->TotalParameterCount;
2727 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2728 pSMB->Reserved4 = 0;
2729 pSMB->hdr.smb_buf_length += byte_count;
2730 pSMB->ByteCount = cpu_to_le16(byte_count);
2732 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2733 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2734 if (rc) {
2735 cFYI(1, ("Send error in QPathInfo = %d", rc));
2736 } else { /* decode response */
2737 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2739 if (rc || (pSMBr->ByteCount < 40))
2740 rc = -EIO; /* bad smb */
2741 else if (pFindData){
2742 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2743 memcpy((char *) pFindData,
2744 (char *) &pSMBr->hdr.Protocol +
2745 data_offset, sizeof (FILE_ALL_INFO));
2746 } else
2747 rc = -ENOMEM;
2749 cifs_buf_release(pSMB);
2750 if (rc == -EAGAIN)
2751 goto QPathInfoRetry;
2753 return rc;
2757 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2758 const unsigned char *searchName,
2759 FILE_UNIX_BASIC_INFO * pFindData,
2760 const struct nls_table *nls_codepage, int remap)
2762 /* SMB_QUERY_FILE_UNIX_BASIC */
2763 TRANSACTION2_QPI_REQ *pSMB = NULL;
2764 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2765 int rc = 0;
2766 int bytes_returned = 0;
2767 int name_len;
2768 __u16 params, byte_count;
2770 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2771 UnixQPathInfoRetry:
2772 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2773 (void **) &pSMBr);
2774 if (rc)
2775 return rc;
2777 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2778 name_len =
2779 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2780 PATH_MAX, nls_codepage, remap);
2781 name_len++; /* trailing null */
2782 name_len *= 2;
2783 } else { /* BB improve the check for buffer overruns BB */
2784 name_len = strnlen(searchName, PATH_MAX);
2785 name_len++; /* trailing null */
2786 strncpy(pSMB->FileName, searchName, name_len);
2789 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2790 pSMB->TotalDataCount = 0;
2791 pSMB->MaxParameterCount = cpu_to_le16(2);
2792 /* BB find exact max SMB PDU from sess structure BB */
2793 pSMB->MaxDataCount = cpu_to_le16(4000);
2794 pSMB->MaxSetupCount = 0;
2795 pSMB->Reserved = 0;
2796 pSMB->Flags = 0;
2797 pSMB->Timeout = 0;
2798 pSMB->Reserved2 = 0;
2799 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2800 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2801 pSMB->DataCount = 0;
2802 pSMB->DataOffset = 0;
2803 pSMB->SetupCount = 1;
2804 pSMB->Reserved3 = 0;
2805 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2806 byte_count = params + 1 /* pad */ ;
2807 pSMB->TotalParameterCount = cpu_to_le16(params);
2808 pSMB->ParameterCount = pSMB->TotalParameterCount;
2809 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2810 pSMB->Reserved4 = 0;
2811 pSMB->hdr.smb_buf_length += byte_count;
2812 pSMB->ByteCount = cpu_to_le16(byte_count);
2814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2816 if (rc) {
2817 cFYI(1, ("Send error in QPathInfo = %d", rc));
2818 } else { /* decode response */
2819 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2821 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2822 rc = -EIO; /* bad smb */
2823 } else {
2824 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2825 memcpy((char *) pFindData,
2826 (char *) &pSMBr->hdr.Protocol +
2827 data_offset,
2828 sizeof (FILE_UNIX_BASIC_INFO));
2831 cifs_buf_release(pSMB);
2832 if (rc == -EAGAIN)
2833 goto UnixQPathInfoRetry;
2835 return rc;
2838 #if 0 /* function unused at present */
2839 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2840 const char *searchName, FILE_ALL_INFO * findData,
2841 const struct nls_table *nls_codepage)
2843 /* level 257 SMB_ */
2844 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2845 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2846 int rc = 0;
2847 int bytes_returned;
2848 int name_len;
2849 __u16 params, byte_count;
2851 cFYI(1, ("In FindUnique"));
2852 findUniqueRetry:
2853 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2854 (void **) &pSMBr);
2855 if (rc)
2856 return rc;
2858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2859 name_len =
2860 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2861 /* find define for this maxpathcomponent */
2862 , nls_codepage);
2863 name_len++; /* trailing null */
2864 name_len *= 2;
2865 } else { /* BB improve the check for buffer overruns BB */
2866 name_len = strnlen(searchName, PATH_MAX);
2867 name_len++; /* trailing null */
2868 strncpy(pSMB->FileName, searchName, name_len);
2871 params = 12 + name_len /* includes null */ ;
2872 pSMB->TotalDataCount = 0; /* no EAs */
2873 pSMB->MaxParameterCount = cpu_to_le16(2);
2874 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2875 pSMB->MaxSetupCount = 0;
2876 pSMB->Reserved = 0;
2877 pSMB->Flags = 0;
2878 pSMB->Timeout = 0;
2879 pSMB->Reserved2 = 0;
2880 pSMB->ParameterOffset = cpu_to_le16(
2881 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2882 pSMB->DataCount = 0;
2883 pSMB->DataOffset = 0;
2884 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2885 pSMB->Reserved3 = 0;
2886 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2887 byte_count = params + 1 /* pad */ ;
2888 pSMB->TotalParameterCount = cpu_to_le16(params);
2889 pSMB->ParameterCount = pSMB->TotalParameterCount;
2890 pSMB->SearchAttributes =
2891 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2892 ATTR_DIRECTORY);
2893 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2894 pSMB->SearchFlags = cpu_to_le16(1);
2895 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2896 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2897 pSMB->hdr.smb_buf_length += byte_count;
2898 pSMB->ByteCount = cpu_to_le16(byte_count);
2900 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2901 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2903 if (rc) {
2904 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2905 } else { /* decode response */
2906 cifs_stats_inc(&tcon->num_ffirst);
2907 /* BB fill in */
2910 cifs_buf_release(pSMB);
2911 if (rc == -EAGAIN)
2912 goto findUniqueRetry;
2914 return rc;
2916 #endif /* end unused (temporarily) function */
2918 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2920 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2921 const char *searchName,
2922 const struct nls_table *nls_codepage,
2923 __u16 * pnetfid,
2924 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2926 /* level 257 SMB_ */
2927 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2928 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2929 T2_FFIRST_RSP_PARMS * parms;
2930 int rc = 0;
2931 int bytes_returned = 0;
2932 int name_len;
2933 __u16 params, byte_count;
2935 cFYI(1, ("In FindFirst for %s",searchName));
2937 findFirstRetry:
2938 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2939 (void **) &pSMBr);
2940 if (rc)
2941 return rc;
2943 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2944 name_len =
2945 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2946 PATH_MAX, nls_codepage, remap);
2947 /* We can not add the asterik earlier in case
2948 it got remapped to 0xF03A as if it were part of the
2949 directory name instead of a wildcard */
2950 name_len *= 2;
2951 pSMB->FileName[name_len] = dirsep;
2952 pSMB->FileName[name_len+1] = 0;
2953 pSMB->FileName[name_len+2] = '*';
2954 pSMB->FileName[name_len+3] = 0;
2955 name_len += 4; /* now the trailing null */
2956 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2957 pSMB->FileName[name_len+1] = 0;
2958 name_len += 2;
2959 } else { /* BB add check for overrun of SMB buf BB */
2960 name_len = strnlen(searchName, PATH_MAX);
2961 /* BB fix here and in unicode clause above ie
2962 if(name_len > buffersize-header)
2963 free buffer exit; BB */
2964 strncpy(pSMB->FileName, searchName, name_len);
2965 pSMB->FileName[name_len] = dirsep;
2966 pSMB->FileName[name_len+1] = '*';
2967 pSMB->FileName[name_len+2] = 0;
2968 name_len += 3;
2971 params = 12 + name_len /* includes null */ ;
2972 pSMB->TotalDataCount = 0; /* no EAs */
2973 pSMB->MaxParameterCount = cpu_to_le16(10);
2974 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2975 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2976 pSMB->MaxSetupCount = 0;
2977 pSMB->Reserved = 0;
2978 pSMB->Flags = 0;
2979 pSMB->Timeout = 0;
2980 pSMB->Reserved2 = 0;
2981 byte_count = params + 1 /* pad */ ;
2982 pSMB->TotalParameterCount = cpu_to_le16(params);
2983 pSMB->ParameterCount = pSMB->TotalParameterCount;
2984 pSMB->ParameterOffset = cpu_to_le16(
2985 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2986 pSMB->DataCount = 0;
2987 pSMB->DataOffset = 0;
2988 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2989 pSMB->Reserved3 = 0;
2990 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2991 pSMB->SearchAttributes =
2992 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2993 ATTR_DIRECTORY);
2994 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2995 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2996 CIFS_SEARCH_RETURN_RESUME);
2997 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2999 /* BB what should we set StorageType to? Does it matter? BB */
3000 pSMB->SearchStorageType = 0;
3001 pSMB->hdr.smb_buf_length += byte_count;
3002 pSMB->ByteCount = cpu_to_le16(byte_count);
3004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3006 cifs_stats_inc(&tcon->num_ffirst);
3008 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
3009 /* BB Add code to handle unsupported level rc */
3010 cFYI(1, ("Error in FindFirst = %d", rc));
3012 if (pSMB)
3013 cifs_buf_release(pSMB);
3015 /* BB eventually could optimize out free and realloc of buf */
3016 /* for this case */
3017 if (rc == -EAGAIN)
3018 goto findFirstRetry;
3019 } else { /* decode response */
3020 /* BB remember to free buffer if error BB */
3021 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3022 if(rc == 0) {
3023 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3024 psrch_inf->unicode = TRUE;
3025 else
3026 psrch_inf->unicode = FALSE;
3028 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3029 psrch_inf->smallBuf = 0;
3030 psrch_inf->srch_entries_start =
3031 (char *) &pSMBr->hdr.Protocol +
3032 le16_to_cpu(pSMBr->t2.DataOffset);
3033 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3034 le16_to_cpu(pSMBr->t2.ParameterOffset));
3036 if(parms->EndofSearch)
3037 psrch_inf->endOfSearch = TRUE;
3038 else
3039 psrch_inf->endOfSearch = FALSE;
3041 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3042 psrch_inf->index_of_last_entry =
3043 psrch_inf->entries_in_buffer;
3044 *pnetfid = parms->SearchHandle;
3045 } else {
3046 cifs_buf_release(pSMB);
3050 return rc;
3053 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3054 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3056 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3057 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3058 T2_FNEXT_RSP_PARMS * parms;
3059 char *response_data;
3060 int rc = 0;
3061 int bytes_returned, name_len;
3062 __u16 params, byte_count;
3064 cFYI(1, ("In FindNext"));
3066 if(psrch_inf->endOfSearch == TRUE)
3067 return -ENOENT;
3069 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3070 (void **) &pSMBr);
3071 if (rc)
3072 return rc;
3074 params = 14; /* includes 2 bytes of null string, converted to LE below */
3075 byte_count = 0;
3076 pSMB->TotalDataCount = 0; /* no EAs */
3077 pSMB->MaxParameterCount = cpu_to_le16(8);
3078 pSMB->MaxDataCount =
3079 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3080 pSMB->MaxSetupCount = 0;
3081 pSMB->Reserved = 0;
3082 pSMB->Flags = 0;
3083 pSMB->Timeout = 0;
3084 pSMB->Reserved2 = 0;
3085 pSMB->ParameterOffset = cpu_to_le16(
3086 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3087 pSMB->DataCount = 0;
3088 pSMB->DataOffset = 0;
3089 pSMB->SetupCount = 1;
3090 pSMB->Reserved3 = 0;
3091 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3092 pSMB->SearchHandle = searchHandle; /* always kept as le */
3093 pSMB->SearchCount =
3094 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3095 /* test for Unix extensions */
3096 /* if (tcon->ses->capabilities & CAP_UNIX) {
3097 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3098 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3099 } else {
3100 pSMB->InformationLevel =
3101 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3102 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3103 } */
3104 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3105 pSMB->ResumeKey = psrch_inf->resume_key;
3106 pSMB->SearchFlags =
3107 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3109 name_len = psrch_inf->resume_name_len;
3110 params += name_len;
3111 if(name_len < PATH_MAX) {
3112 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3113 byte_count += name_len;
3114 /* 14 byte parm len above enough for 2 byte null terminator */
3115 pSMB->ResumeFileName[name_len] = 0;
3116 pSMB->ResumeFileName[name_len+1] = 0;
3117 } else {
3118 rc = -EINVAL;
3119 goto FNext2_err_exit;
3121 byte_count = params + 1 /* pad */ ;
3122 pSMB->TotalParameterCount = cpu_to_le16(params);
3123 pSMB->ParameterCount = pSMB->TotalParameterCount;
3124 pSMB->hdr.smb_buf_length += byte_count;
3125 pSMB->ByteCount = cpu_to_le16(byte_count);
3127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3129 cifs_stats_inc(&tcon->num_fnext);
3130 if (rc) {
3131 if (rc == -EBADF) {
3132 psrch_inf->endOfSearch = TRUE;
3133 rc = 0; /* search probably was closed at end of search above */
3134 } else
3135 cFYI(1, ("FindNext returned = %d", rc));
3136 } else { /* decode response */
3137 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3139 if(rc == 0) {
3140 /* BB fixme add lock for file (srch_info) struct here */
3141 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3142 psrch_inf->unicode = TRUE;
3143 else
3144 psrch_inf->unicode = FALSE;
3145 response_data = (char *) &pSMBr->hdr.Protocol +
3146 le16_to_cpu(pSMBr->t2.ParameterOffset);
3147 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3148 response_data = (char *)&pSMBr->hdr.Protocol +
3149 le16_to_cpu(pSMBr->t2.DataOffset);
3150 if(psrch_inf->smallBuf)
3151 cifs_small_buf_release(
3152 psrch_inf->ntwrk_buf_start);
3153 else
3154 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3155 psrch_inf->srch_entries_start = response_data;
3156 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3157 psrch_inf->smallBuf = 0;
3158 if(parms->EndofSearch)
3159 psrch_inf->endOfSearch = TRUE;
3160 else
3161 psrch_inf->endOfSearch = FALSE;
3163 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3164 psrch_inf->index_of_last_entry +=
3165 psrch_inf->entries_in_buffer;
3166 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3168 /* BB fixme add unlock here */
3173 /* BB On error, should we leave previous search buf (and count and
3174 last entry fields) intact or free the previous one? */
3176 /* Note: On -EAGAIN error only caller can retry on handle based calls
3177 since file handle passed in no longer valid */
3178 FNext2_err_exit:
3179 if (rc != 0)
3180 cifs_buf_release(pSMB);
3182 return rc;
3186 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3188 int rc = 0;
3189 FINDCLOSE_REQ *pSMB = NULL;
3190 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3191 int bytes_returned;
3193 cFYI(1, ("In CIFSSMBFindClose"));
3194 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3196 /* no sense returning error if session restarted
3197 as file handle has been closed */
3198 if(rc == -EAGAIN)
3199 return 0;
3200 if (rc)
3201 return rc;
3203 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3204 pSMB->FileID = searchHandle;
3205 pSMB->ByteCount = 0;
3206 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3207 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3208 if (rc) {
3209 cERROR(1, ("Send error in FindClose = %d", rc));
3211 cifs_stats_inc(&tcon->num_fclose);
3212 cifs_small_buf_release(pSMB);
3214 /* Since session is dead, search handle closed on server already */
3215 if (rc == -EAGAIN)
3216 rc = 0;
3218 return rc;
3222 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3223 const unsigned char *searchName,
3224 __u64 * inode_number,
3225 const struct nls_table *nls_codepage, int remap)
3227 int rc = 0;
3228 TRANSACTION2_QPI_REQ *pSMB = NULL;
3229 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3230 int name_len, bytes_returned;
3231 __u16 params, byte_count;
3233 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3234 if(tcon == NULL)
3235 return -ENODEV;
3237 GetInodeNumberRetry:
3238 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3239 (void **) &pSMBr);
3240 if (rc)
3241 return rc;
3244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3245 name_len =
3246 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3247 PATH_MAX,nls_codepage, remap);
3248 name_len++; /* trailing null */
3249 name_len *= 2;
3250 } else { /* BB improve the check for buffer overruns BB */
3251 name_len = strnlen(searchName, PATH_MAX);
3252 name_len++; /* trailing null */
3253 strncpy(pSMB->FileName, searchName, name_len);
3256 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3257 pSMB->TotalDataCount = 0;
3258 pSMB->MaxParameterCount = cpu_to_le16(2);
3259 /* BB find exact max data count below from sess structure BB */
3260 pSMB->MaxDataCount = cpu_to_le16(4000);
3261 pSMB->MaxSetupCount = 0;
3262 pSMB->Reserved = 0;
3263 pSMB->Flags = 0;
3264 pSMB->Timeout = 0;
3265 pSMB->Reserved2 = 0;
3266 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3267 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3268 pSMB->DataCount = 0;
3269 pSMB->DataOffset = 0;
3270 pSMB->SetupCount = 1;
3271 pSMB->Reserved3 = 0;
3272 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3273 byte_count = params + 1 /* pad */ ;
3274 pSMB->TotalParameterCount = cpu_to_le16(params);
3275 pSMB->ParameterCount = pSMB->TotalParameterCount;
3276 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3277 pSMB->Reserved4 = 0;
3278 pSMB->hdr.smb_buf_length += byte_count;
3279 pSMB->ByteCount = cpu_to_le16(byte_count);
3281 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3282 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3283 if (rc) {
3284 cFYI(1, ("error %d in QueryInternalInfo", rc));
3285 } else {
3286 /* decode response */
3287 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3288 if (rc || (pSMBr->ByteCount < 2))
3289 /* BB also check enough total bytes returned */
3290 /* If rc should we check for EOPNOSUPP and
3291 disable the srvino flag? or in caller? */
3292 rc = -EIO; /* bad smb */
3293 else {
3294 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3295 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3296 struct file_internal_info * pfinfo;
3297 /* BB Do we need a cast or hash here ? */
3298 if(count < 8) {
3299 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3300 rc = -EIO;
3301 goto GetInodeNumOut;
3303 pfinfo = (struct file_internal_info *)
3304 (data_offset + (char *) &pSMBr->hdr.Protocol);
3305 *inode_number = pfinfo->UniqueId;
3308 GetInodeNumOut:
3309 cifs_buf_release(pSMB);
3310 if (rc == -EAGAIN)
3311 goto GetInodeNumberRetry;
3312 return rc;
3316 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3317 const unsigned char *searchName,
3318 unsigned char **targetUNCs,
3319 unsigned int *number_of_UNC_in_array,
3320 const struct nls_table *nls_codepage, int remap)
3322 /* TRANS2_GET_DFS_REFERRAL */
3323 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3324 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3325 struct dfs_referral_level_3 * referrals = NULL;
3326 int rc = 0;
3327 int bytes_returned;
3328 int name_len;
3329 unsigned int i;
3330 char * temp;
3331 __u16 params, byte_count;
3332 *number_of_UNC_in_array = 0;
3333 *targetUNCs = NULL;
3335 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3336 if (ses == NULL)
3337 return -ENODEV;
3338 getDFSRetry:
3339 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3340 (void **) &pSMBr);
3341 if (rc)
3342 return rc;
3344 /* server pointer checked in called function,
3345 but should never be null here anyway */
3346 pSMB->hdr.Mid = GetNextMid(ses->server);
3347 pSMB->hdr.Tid = ses->ipc_tid;
3348 pSMB->hdr.Uid = ses->Suid;
3349 if (ses->capabilities & CAP_STATUS32) {
3350 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3352 if (ses->capabilities & CAP_DFS) {
3353 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3356 if (ses->capabilities & CAP_UNICODE) {
3357 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3358 name_len =
3359 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3360 searchName, PATH_MAX, nls_codepage, remap);
3361 name_len++; /* trailing null */
3362 name_len *= 2;
3363 } else { /* BB improve the check for buffer overruns BB */
3364 name_len = strnlen(searchName, PATH_MAX);
3365 name_len++; /* trailing null */
3366 strncpy(pSMB->RequestFileName, searchName, name_len);
3369 params = 2 /* level */ + name_len /*includes null */ ;
3370 pSMB->TotalDataCount = 0;
3371 pSMB->DataCount = 0;
3372 pSMB->DataOffset = 0;
3373 pSMB->MaxParameterCount = 0;
3374 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3375 pSMB->MaxSetupCount = 0;
3376 pSMB->Reserved = 0;
3377 pSMB->Flags = 0;
3378 pSMB->Timeout = 0;
3379 pSMB->Reserved2 = 0;
3380 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3381 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3382 pSMB->SetupCount = 1;
3383 pSMB->Reserved3 = 0;
3384 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3385 byte_count = params + 3 /* pad */ ;
3386 pSMB->ParameterCount = cpu_to_le16(params);
3387 pSMB->TotalParameterCount = pSMB->ParameterCount;
3388 pSMB->MaxReferralLevel = cpu_to_le16(3);
3389 pSMB->hdr.smb_buf_length += byte_count;
3390 pSMB->ByteCount = cpu_to_le16(byte_count);
3392 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3393 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3394 if (rc) {
3395 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3396 } else { /* decode response */
3397 /* BB Add logic to parse referrals here */
3398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3400 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3401 rc = -EIO; /* bad smb */
3402 else {
3403 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3404 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3406 cFYI(1,
3407 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3408 pSMBr->ByteCount, data_offset));
3409 referrals =
3410 (struct dfs_referral_level_3 *)
3411 (8 /* sizeof start of data block */ +
3412 data_offset +
3413 (char *) &pSMBr->hdr.Protocol);
3414 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",
3415 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)));
3416 /* BB This field is actually two bytes in from start of
3417 data block so we could do safety check that DataBlock
3418 begins at address of pSMBr->NumberOfReferrals */
3419 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3421 /* BB Fix below so can return more than one referral */
3422 if(*number_of_UNC_in_array > 1)
3423 *number_of_UNC_in_array = 1;
3425 /* get the length of the strings describing refs */
3426 name_len = 0;
3427 for(i=0;i<*number_of_UNC_in_array;i++) {
3428 /* make sure that DfsPathOffset not past end */
3429 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3430 if (offset > data_count) {
3431 /* if invalid referral, stop here and do
3432 not try to copy any more */
3433 *number_of_UNC_in_array = i;
3434 break;
3436 temp = ((char *)referrals) + offset;
3438 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3439 name_len += UniStrnlen((wchar_t *)temp,data_count);
3440 } else {
3441 name_len += strnlen(temp,data_count);
3443 referrals++;
3444 /* BB add check that referral pointer does not fall off end PDU */
3447 /* BB add check for name_len bigger than bcc */
3448 *targetUNCs =
3449 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3450 if(*targetUNCs == NULL) {
3451 rc = -ENOMEM;
3452 goto GetDFSRefExit;
3454 /* copy the ref strings */
3455 referrals =
3456 (struct dfs_referral_level_3 *)
3457 (8 /* sizeof data hdr */ +
3458 data_offset +
3459 (char *) &pSMBr->hdr.Protocol);
3461 for(i=0;i<*number_of_UNC_in_array;i++) {
3462 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3463 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3464 cifs_strfromUCS_le(*targetUNCs,
3465 (__le16 *) temp, name_len, nls_codepage);
3466 } else {
3467 strncpy(*targetUNCs,temp,name_len);
3469 /* BB update target_uncs pointers */
3470 referrals++;
3472 temp = *targetUNCs;
3473 temp[name_len] = 0;
3477 GetDFSRefExit:
3478 if (pSMB)
3479 cifs_buf_release(pSMB);
3481 if (rc == -EAGAIN)
3482 goto getDFSRetry;
3484 return rc;
3487 /* Query File System Info such as free space to old servers such as Win 9x */
3489 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3491 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3492 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3493 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3494 FILE_SYSTEM_ALLOC_INFO *response_data;
3495 int rc = 0;
3496 int bytes_returned = 0;
3497 __u16 params, byte_count;
3499 cFYI(1, ("OldQFSInfo"));
3500 oldQFSInfoRetry:
3501 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3502 (void **) &pSMBr);
3503 if (rc)
3504 return rc;
3505 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3506 (void **) &pSMBr);
3507 if (rc)
3508 return rc;
3510 params = 2; /* level */
3511 pSMB->TotalDataCount = 0;
3512 pSMB->MaxParameterCount = cpu_to_le16(2);
3513 pSMB->MaxDataCount = cpu_to_le16(1000);
3514 pSMB->MaxSetupCount = 0;
3515 pSMB->Reserved = 0;
3516 pSMB->Flags = 0;
3517 pSMB->Timeout = 0;
3518 pSMB->Reserved2 = 0;
3519 byte_count = params + 1 /* pad */ ;
3520 pSMB->TotalParameterCount = cpu_to_le16(params);
3521 pSMB->ParameterCount = pSMB->TotalParameterCount;
3522 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3523 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3524 pSMB->DataCount = 0;
3525 pSMB->DataOffset = 0;
3526 pSMB->SetupCount = 1;
3527 pSMB->Reserved3 = 0;
3528 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3529 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3530 pSMB->hdr.smb_buf_length += byte_count;
3531 pSMB->ByteCount = cpu_to_le16(byte_count);
3533 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3534 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3535 if (rc) {
3536 cFYI(1, ("Send error in QFSInfo = %d", rc));
3537 } else { /* decode response */
3538 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3540 if (rc || (pSMBr->ByteCount < 18))
3541 rc = -EIO; /* bad smb */
3542 else {
3543 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3544 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3545 pSMBr->ByteCount, data_offset));
3547 response_data =
3548 (FILE_SYSTEM_ALLOC_INFO *)
3549 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3550 FSData->f_bsize =
3551 le16_to_cpu(response_data->BytesPerSector) *
3552 le32_to_cpu(response_data->
3553 SectorsPerAllocationUnit);
3554 FSData->f_blocks =
3555 le32_to_cpu(response_data->TotalAllocationUnits);
3556 FSData->f_bfree = FSData->f_bavail =
3557 le32_to_cpu(response_data->FreeAllocationUnits);
3558 cFYI(1,
3559 ("Blocks: %lld Free: %lld Block size %ld",
3560 (unsigned long long)FSData->f_blocks,
3561 (unsigned long long)FSData->f_bfree,
3562 FSData->f_bsize));
3565 cifs_buf_release(pSMB);
3567 if (rc == -EAGAIN)
3568 goto oldQFSInfoRetry;
3570 return rc;
3574 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3576 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3577 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3578 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3579 FILE_SYSTEM_INFO *response_data;
3580 int rc = 0;
3581 int bytes_returned = 0;
3582 __u16 params, byte_count;
3584 cFYI(1, ("In QFSInfo"));
3585 QFSInfoRetry:
3586 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3587 (void **) &pSMBr);
3588 if (rc)
3589 return rc;
3591 params = 2; /* level */
3592 pSMB->TotalDataCount = 0;
3593 pSMB->MaxParameterCount = cpu_to_le16(2);
3594 pSMB->MaxDataCount = cpu_to_le16(1000);
3595 pSMB->MaxSetupCount = 0;
3596 pSMB->Reserved = 0;
3597 pSMB->Flags = 0;
3598 pSMB->Timeout = 0;
3599 pSMB->Reserved2 = 0;
3600 byte_count = params + 1 /* pad */ ;
3601 pSMB->TotalParameterCount = cpu_to_le16(params);
3602 pSMB->ParameterCount = pSMB->TotalParameterCount;
3603 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3604 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3605 pSMB->DataCount = 0;
3606 pSMB->DataOffset = 0;
3607 pSMB->SetupCount = 1;
3608 pSMB->Reserved3 = 0;
3609 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3610 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3611 pSMB->hdr.smb_buf_length += byte_count;
3612 pSMB->ByteCount = cpu_to_le16(byte_count);
3614 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3616 if (rc) {
3617 cFYI(1, ("Send error in QFSInfo = %d", rc));
3618 } else { /* decode response */
3619 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3621 if (rc || (pSMBr->ByteCount < 24))
3622 rc = -EIO; /* bad smb */
3623 else {
3624 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3626 response_data =
3627 (FILE_SYSTEM_INFO
3628 *) (((char *) &pSMBr->hdr.Protocol) +
3629 data_offset);
3630 FSData->f_bsize =
3631 le32_to_cpu(response_data->BytesPerSector) *
3632 le32_to_cpu(response_data->
3633 SectorsPerAllocationUnit);
3634 FSData->f_blocks =
3635 le64_to_cpu(response_data->TotalAllocationUnits);
3636 FSData->f_bfree = FSData->f_bavail =
3637 le64_to_cpu(response_data->FreeAllocationUnits);
3638 cFYI(1,
3639 ("Blocks: %lld Free: %lld Block size %ld",
3640 (unsigned long long)FSData->f_blocks,
3641 (unsigned long long)FSData->f_bfree,
3642 FSData->f_bsize));
3645 cifs_buf_release(pSMB);
3647 if (rc == -EAGAIN)
3648 goto QFSInfoRetry;
3650 return rc;
3654 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3656 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3657 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3658 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3659 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3660 int rc = 0;
3661 int bytes_returned = 0;
3662 __u16 params, byte_count;
3664 cFYI(1, ("In QFSAttributeInfo"));
3665 QFSAttributeRetry:
3666 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3667 (void **) &pSMBr);
3668 if (rc)
3669 return rc;
3671 params = 2; /* level */
3672 pSMB->TotalDataCount = 0;
3673 pSMB->MaxParameterCount = cpu_to_le16(2);
3674 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3675 pSMB->MaxSetupCount = 0;
3676 pSMB->Reserved = 0;
3677 pSMB->Flags = 0;
3678 pSMB->Timeout = 0;
3679 pSMB->Reserved2 = 0;
3680 byte_count = params + 1 /* pad */ ;
3681 pSMB->TotalParameterCount = cpu_to_le16(params);
3682 pSMB->ParameterCount = pSMB->TotalParameterCount;
3683 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3684 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3685 pSMB->DataCount = 0;
3686 pSMB->DataOffset = 0;
3687 pSMB->SetupCount = 1;
3688 pSMB->Reserved3 = 0;
3689 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3690 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3691 pSMB->hdr.smb_buf_length += byte_count;
3692 pSMB->ByteCount = cpu_to_le16(byte_count);
3694 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3695 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3696 if (rc) {
3697 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3698 } else { /* decode response */
3699 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3701 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3702 rc = -EIO; /* bad smb */
3703 } else {
3704 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3705 response_data =
3706 (FILE_SYSTEM_ATTRIBUTE_INFO
3707 *) (((char *) &pSMBr->hdr.Protocol) +
3708 data_offset);
3709 memcpy(&tcon->fsAttrInfo, response_data,
3710 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3713 cifs_buf_release(pSMB);
3715 if (rc == -EAGAIN)
3716 goto QFSAttributeRetry;
3718 return rc;
3722 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3724 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3725 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3726 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3727 FILE_SYSTEM_DEVICE_INFO *response_data;
3728 int rc = 0;
3729 int bytes_returned = 0;
3730 __u16 params, byte_count;
3732 cFYI(1, ("In QFSDeviceInfo"));
3733 QFSDeviceRetry:
3734 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3735 (void **) &pSMBr);
3736 if (rc)
3737 return rc;
3739 params = 2; /* level */
3740 pSMB->TotalDataCount = 0;
3741 pSMB->MaxParameterCount = cpu_to_le16(2);
3742 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3743 pSMB->MaxSetupCount = 0;
3744 pSMB->Reserved = 0;
3745 pSMB->Flags = 0;
3746 pSMB->Timeout = 0;
3747 pSMB->Reserved2 = 0;
3748 byte_count = params + 1 /* pad */ ;
3749 pSMB->TotalParameterCount = cpu_to_le16(params);
3750 pSMB->ParameterCount = pSMB->TotalParameterCount;
3751 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3752 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3754 pSMB->DataCount = 0;
3755 pSMB->DataOffset = 0;
3756 pSMB->SetupCount = 1;
3757 pSMB->Reserved3 = 0;
3758 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3759 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3760 pSMB->hdr.smb_buf_length += byte_count;
3761 pSMB->ByteCount = cpu_to_le16(byte_count);
3763 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3764 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3765 if (rc) {
3766 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3767 } else { /* decode response */
3768 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3770 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3771 rc = -EIO; /* bad smb */
3772 else {
3773 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3774 response_data =
3775 (FILE_SYSTEM_DEVICE_INFO *)
3776 (((char *) &pSMBr->hdr.Protocol) +
3777 data_offset);
3778 memcpy(&tcon->fsDevInfo, response_data,
3779 sizeof (FILE_SYSTEM_DEVICE_INFO));
3782 cifs_buf_release(pSMB);
3784 if (rc == -EAGAIN)
3785 goto QFSDeviceRetry;
3787 return rc;
3791 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3793 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3794 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3795 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3796 FILE_SYSTEM_UNIX_INFO *response_data;
3797 int rc = 0;
3798 int bytes_returned = 0;
3799 __u16 params, byte_count;
3801 cFYI(1, ("In QFSUnixInfo"));
3802 QFSUnixRetry:
3803 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3804 (void **) &pSMBr);
3805 if (rc)
3806 return rc;
3808 params = 2; /* level */
3809 pSMB->TotalDataCount = 0;
3810 pSMB->DataCount = 0;
3811 pSMB->DataOffset = 0;
3812 pSMB->MaxParameterCount = cpu_to_le16(2);
3813 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3814 pSMB->MaxSetupCount = 0;
3815 pSMB->Reserved = 0;
3816 pSMB->Flags = 0;
3817 pSMB->Timeout = 0;
3818 pSMB->Reserved2 = 0;
3819 byte_count = params + 1 /* pad */ ;
3820 pSMB->ParameterCount = cpu_to_le16(params);
3821 pSMB->TotalParameterCount = pSMB->ParameterCount;
3822 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3823 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3824 pSMB->SetupCount = 1;
3825 pSMB->Reserved3 = 0;
3826 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3827 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3828 pSMB->hdr.smb_buf_length += byte_count;
3829 pSMB->ByteCount = cpu_to_le16(byte_count);
3831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3833 if (rc) {
3834 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3835 } else { /* decode response */
3836 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3838 if (rc || (pSMBr->ByteCount < 13)) {
3839 rc = -EIO; /* bad smb */
3840 } else {
3841 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3842 response_data =
3843 (FILE_SYSTEM_UNIX_INFO
3844 *) (((char *) &pSMBr->hdr.Protocol) +
3845 data_offset);
3846 memcpy(&tcon->fsUnixInfo, response_data,
3847 sizeof (FILE_SYSTEM_UNIX_INFO));
3850 cifs_buf_release(pSMB);
3852 if (rc == -EAGAIN)
3853 goto QFSUnixRetry;
3856 return rc;
3860 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3862 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3863 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3864 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3865 int rc = 0;
3866 int bytes_returned = 0;
3867 __u16 params, param_offset, offset, byte_count;
3869 cFYI(1, ("In SETFSUnixInfo"));
3870 SETFSUnixRetry:
3871 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3872 (void **) &pSMBr);
3873 if (rc)
3874 return rc;
3876 params = 4; /* 2 bytes zero followed by info level. */
3877 pSMB->MaxSetupCount = 0;
3878 pSMB->Reserved = 0;
3879 pSMB->Flags = 0;
3880 pSMB->Timeout = 0;
3881 pSMB->Reserved2 = 0;
3882 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3883 offset = param_offset + params;
3885 pSMB->MaxParameterCount = cpu_to_le16(4);
3886 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3887 pSMB->SetupCount = 1;
3888 pSMB->Reserved3 = 0;
3889 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3890 byte_count = 1 /* pad */ + params + 12;
3892 pSMB->DataCount = cpu_to_le16(12);
3893 pSMB->ParameterCount = cpu_to_le16(params);
3894 pSMB->TotalDataCount = pSMB->DataCount;
3895 pSMB->TotalParameterCount = pSMB->ParameterCount;
3896 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3897 pSMB->DataOffset = cpu_to_le16(offset);
3899 /* Params. */
3900 pSMB->FileNum = 0;
3901 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3903 /* Data. */
3904 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3905 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3906 pSMB->ClientUnixCap = cpu_to_le64(cap);
3908 pSMB->hdr.smb_buf_length += byte_count;
3909 pSMB->ByteCount = cpu_to_le16(byte_count);
3911 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3912 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3913 if (rc) {
3914 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3915 } else { /* decode response */
3916 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3917 if (rc) {
3918 rc = -EIO; /* bad smb */
3921 cifs_buf_release(pSMB);
3923 if (rc == -EAGAIN)
3924 goto SETFSUnixRetry;
3926 return rc;
3932 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3933 struct kstatfs *FSData)
3935 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3936 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3937 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3938 FILE_SYSTEM_POSIX_INFO *response_data;
3939 int rc = 0;
3940 int bytes_returned = 0;
3941 __u16 params, byte_count;
3943 cFYI(1, ("In QFSPosixInfo"));
3944 QFSPosixRetry:
3945 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3946 (void **) &pSMBr);
3947 if (rc)
3948 return rc;
3950 params = 2; /* level */
3951 pSMB->TotalDataCount = 0;
3952 pSMB->DataCount = 0;
3953 pSMB->DataOffset = 0;
3954 pSMB->MaxParameterCount = cpu_to_le16(2);
3955 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3956 pSMB->MaxSetupCount = 0;
3957 pSMB->Reserved = 0;
3958 pSMB->Flags = 0;
3959 pSMB->Timeout = 0;
3960 pSMB->Reserved2 = 0;
3961 byte_count = params + 1 /* pad */ ;
3962 pSMB->ParameterCount = cpu_to_le16(params);
3963 pSMB->TotalParameterCount = pSMB->ParameterCount;
3964 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3965 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3966 pSMB->SetupCount = 1;
3967 pSMB->Reserved3 = 0;
3968 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3969 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3970 pSMB->hdr.smb_buf_length += byte_count;
3971 pSMB->ByteCount = cpu_to_le16(byte_count);
3973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3975 if (rc) {
3976 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3977 } else { /* decode response */
3978 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3980 if (rc || (pSMBr->ByteCount < 13)) {
3981 rc = -EIO; /* bad smb */
3982 } else {
3983 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3984 response_data =
3985 (FILE_SYSTEM_POSIX_INFO
3986 *) (((char *) &pSMBr->hdr.Protocol) +
3987 data_offset);
3988 FSData->f_bsize =
3989 le32_to_cpu(response_data->BlockSize);
3990 FSData->f_blocks =
3991 le64_to_cpu(response_data->TotalBlocks);
3992 FSData->f_bfree =
3993 le64_to_cpu(response_data->BlocksAvail);
3994 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
3995 FSData->f_bavail = FSData->f_bfree;
3996 } else {
3997 FSData->f_bavail =
3998 le64_to_cpu(response_data->UserBlocksAvail);
4000 if(response_data->TotalFileNodes != cpu_to_le64(-1))
4001 FSData->f_files =
4002 le64_to_cpu(response_data->TotalFileNodes);
4003 if(response_data->FreeFileNodes != cpu_to_le64(-1))
4004 FSData->f_ffree =
4005 le64_to_cpu(response_data->FreeFileNodes);
4008 cifs_buf_release(pSMB);
4010 if (rc == -EAGAIN)
4011 goto QFSPosixRetry;
4013 return rc;
4017 /* We can not use write of zero bytes trick to
4018 set file size due to need for large file support. Also note that
4019 this SetPathInfo is preferred to SetFileInfo based method in next
4020 routine which is only needed to work around a sharing violation bug
4021 in Samba which this routine can run into */
4024 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4025 __u64 size, int SetAllocation,
4026 const struct nls_table *nls_codepage, int remap)
4028 struct smb_com_transaction2_spi_req *pSMB = NULL;
4029 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4030 struct file_end_of_file_info *parm_data;
4031 int name_len;
4032 int rc = 0;
4033 int bytes_returned = 0;
4034 __u16 params, byte_count, data_count, param_offset, offset;
4036 cFYI(1, ("In SetEOF"));
4037 SetEOFRetry:
4038 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4039 (void **) &pSMBr);
4040 if (rc)
4041 return rc;
4043 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4044 name_len =
4045 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4046 PATH_MAX, nls_codepage, remap);
4047 name_len++; /* trailing null */
4048 name_len *= 2;
4049 } else { /* BB improve the check for buffer overruns BB */
4050 name_len = strnlen(fileName, PATH_MAX);
4051 name_len++; /* trailing null */
4052 strncpy(pSMB->FileName, fileName, name_len);
4054 params = 6 + name_len;
4055 data_count = sizeof (struct file_end_of_file_info);
4056 pSMB->MaxParameterCount = cpu_to_le16(2);
4057 pSMB->MaxDataCount = cpu_to_le16(4100);
4058 pSMB->MaxSetupCount = 0;
4059 pSMB->Reserved = 0;
4060 pSMB->Flags = 0;
4061 pSMB->Timeout = 0;
4062 pSMB->Reserved2 = 0;
4063 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4064 InformationLevel) - 4;
4065 offset = param_offset + params;
4066 if(SetAllocation) {
4067 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4068 pSMB->InformationLevel =
4069 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4070 else
4071 pSMB->InformationLevel =
4072 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4073 } else /* Set File Size */ {
4074 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4075 pSMB->InformationLevel =
4076 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4077 else
4078 pSMB->InformationLevel =
4079 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4082 parm_data =
4083 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4084 offset);
4085 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4086 pSMB->DataOffset = cpu_to_le16(offset);
4087 pSMB->SetupCount = 1;
4088 pSMB->Reserved3 = 0;
4089 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4090 byte_count = 3 /* pad */ + params + data_count;
4091 pSMB->DataCount = cpu_to_le16(data_count);
4092 pSMB->TotalDataCount = pSMB->DataCount;
4093 pSMB->ParameterCount = cpu_to_le16(params);
4094 pSMB->TotalParameterCount = pSMB->ParameterCount;
4095 pSMB->Reserved4 = 0;
4096 pSMB->hdr.smb_buf_length += byte_count;
4097 parm_data->FileSize = cpu_to_le64(size);
4098 pSMB->ByteCount = cpu_to_le16(byte_count);
4099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4101 if (rc) {
4102 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4105 cifs_buf_release(pSMB);
4107 if (rc == -EAGAIN)
4108 goto SetEOFRetry;
4110 return rc;
4114 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4115 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4117 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4118 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4119 char *data_offset;
4120 struct file_end_of_file_info *parm_data;
4121 int rc = 0;
4122 int bytes_returned = 0;
4123 __u16 params, param_offset, offset, byte_count, count;
4125 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4126 (long long)size));
4127 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4129 if (rc)
4130 return rc;
4132 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4134 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4135 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4137 params = 6;
4138 pSMB->MaxSetupCount = 0;
4139 pSMB->Reserved = 0;
4140 pSMB->Flags = 0;
4141 pSMB->Timeout = 0;
4142 pSMB->Reserved2 = 0;
4143 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4144 offset = param_offset + params;
4146 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4148 count = sizeof(struct file_end_of_file_info);
4149 pSMB->MaxParameterCount = cpu_to_le16(2);
4150 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4151 pSMB->SetupCount = 1;
4152 pSMB->Reserved3 = 0;
4153 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4154 byte_count = 3 /* pad */ + params + count;
4155 pSMB->DataCount = cpu_to_le16(count);
4156 pSMB->ParameterCount = cpu_to_le16(params);
4157 pSMB->TotalDataCount = pSMB->DataCount;
4158 pSMB->TotalParameterCount = pSMB->ParameterCount;
4159 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4160 parm_data =
4161 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4162 offset);
4163 pSMB->DataOffset = cpu_to_le16(offset);
4164 parm_data->FileSize = cpu_to_le64(size);
4165 pSMB->Fid = fid;
4166 if(SetAllocation) {
4167 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4168 pSMB->InformationLevel =
4169 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4170 else
4171 pSMB->InformationLevel =
4172 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4173 } else /* Set File Size */ {
4174 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4175 pSMB->InformationLevel =
4176 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4177 else
4178 pSMB->InformationLevel =
4179 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4181 pSMB->Reserved4 = 0;
4182 pSMB->hdr.smb_buf_length += byte_count;
4183 pSMB->ByteCount = cpu_to_le16(byte_count);
4184 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4185 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4186 if (rc) {
4187 cFYI(1,
4188 ("Send error in SetFileInfo (SetFileSize) = %d",
4189 rc));
4192 if (pSMB)
4193 cifs_small_buf_release(pSMB);
4195 /* Note: On -EAGAIN error only caller can retry on handle based calls
4196 since file handle passed in no longer valid */
4198 return rc;
4201 /* Some legacy servers such as NT4 require that the file times be set on
4202 an open handle, rather than by pathname - this is awkward due to
4203 potential access conflicts on the open, but it is unavoidable for these
4204 old servers since the only other choice is to go from 100 nanosecond DCE
4205 time and resort to the original setpathinfo level which takes the ancient
4206 DOS time format with 2 second granularity */
4208 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4209 __u16 fid)
4211 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4212 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4213 char *data_offset;
4214 int rc = 0;
4215 int bytes_returned = 0;
4216 __u16 params, param_offset, offset, byte_count, count;
4218 cFYI(1, ("Set Times (via SetFileInfo)"));
4219 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4221 if (rc)
4222 return rc;
4224 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4226 /* At this point there is no need to override the current pid
4227 with the pid of the opener, but that could change if we someday
4228 use an existing handle (rather than opening one on the fly) */
4229 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4230 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4232 params = 6;
4233 pSMB->MaxSetupCount = 0;
4234 pSMB->Reserved = 0;
4235 pSMB->Flags = 0;
4236 pSMB->Timeout = 0;
4237 pSMB->Reserved2 = 0;
4238 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4239 offset = param_offset + params;
4241 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4243 count = sizeof (FILE_BASIC_INFO);
4244 pSMB->MaxParameterCount = cpu_to_le16(2);
4245 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4246 pSMB->SetupCount = 1;
4247 pSMB->Reserved3 = 0;
4248 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4249 byte_count = 3 /* pad */ + params + count;
4250 pSMB->DataCount = cpu_to_le16(count);
4251 pSMB->ParameterCount = cpu_to_le16(params);
4252 pSMB->TotalDataCount = pSMB->DataCount;
4253 pSMB->TotalParameterCount = pSMB->ParameterCount;
4254 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4255 pSMB->DataOffset = cpu_to_le16(offset);
4256 pSMB->Fid = fid;
4257 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4258 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4259 else
4260 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4261 pSMB->Reserved4 = 0;
4262 pSMB->hdr.smb_buf_length += byte_count;
4263 pSMB->ByteCount = cpu_to_le16(byte_count);
4264 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4265 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4266 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4267 if (rc) {
4268 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4271 cifs_small_buf_release(pSMB);
4273 /* Note: On -EAGAIN error only caller can retry on handle based calls
4274 since file handle passed in no longer valid */
4276 return rc;
4281 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4282 const FILE_BASIC_INFO * data,
4283 const struct nls_table *nls_codepage, int remap)
4285 TRANSACTION2_SPI_REQ *pSMB = NULL;
4286 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4287 int name_len;
4288 int rc = 0;
4289 int bytes_returned = 0;
4290 char *data_offset;
4291 __u16 params, param_offset, offset, byte_count, count;
4293 cFYI(1, ("In SetTimes"));
4295 SetTimesRetry:
4296 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4297 (void **) &pSMBr);
4298 if (rc)
4299 return rc;
4301 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4302 name_len =
4303 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4304 PATH_MAX, nls_codepage, remap);
4305 name_len++; /* trailing null */
4306 name_len *= 2;
4307 } else { /* BB improve the check for buffer overruns BB */
4308 name_len = strnlen(fileName, PATH_MAX);
4309 name_len++; /* trailing null */
4310 strncpy(pSMB->FileName, fileName, name_len);
4313 params = 6 + name_len;
4314 count = sizeof (FILE_BASIC_INFO);
4315 pSMB->MaxParameterCount = cpu_to_le16(2);
4316 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4317 pSMB->MaxSetupCount = 0;
4318 pSMB->Reserved = 0;
4319 pSMB->Flags = 0;
4320 pSMB->Timeout = 0;
4321 pSMB->Reserved2 = 0;
4322 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4323 InformationLevel) - 4;
4324 offset = param_offset + params;
4325 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4326 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4327 pSMB->DataOffset = cpu_to_le16(offset);
4328 pSMB->SetupCount = 1;
4329 pSMB->Reserved3 = 0;
4330 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4331 byte_count = 3 /* pad */ + params + count;
4333 pSMB->DataCount = cpu_to_le16(count);
4334 pSMB->ParameterCount = cpu_to_le16(params);
4335 pSMB->TotalDataCount = pSMB->DataCount;
4336 pSMB->TotalParameterCount = pSMB->ParameterCount;
4337 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4338 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4339 else
4340 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4341 pSMB->Reserved4 = 0;
4342 pSMB->hdr.smb_buf_length += byte_count;
4343 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4344 pSMB->ByteCount = cpu_to_le16(byte_count);
4345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4347 if (rc) {
4348 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4351 cifs_buf_release(pSMB);
4353 if (rc == -EAGAIN)
4354 goto SetTimesRetry;
4356 return rc;
4359 /* Can not be used to set time stamps yet (due to old DOS time format) */
4360 /* Can be used to set attributes */
4361 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4362 handling it anyway and NT4 was what we thought it would be needed for
4363 Do not delete it until we prove whether needed for Win9x though */
4365 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4366 __u16 dos_attrs, const struct nls_table *nls_codepage)
4368 SETATTR_REQ *pSMB = NULL;
4369 SETATTR_RSP *pSMBr = NULL;
4370 int rc = 0;
4371 int bytes_returned;
4372 int name_len;
4374 cFYI(1, ("In SetAttrLegacy"));
4376 SetAttrLgcyRetry:
4377 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4378 (void **) &pSMBr);
4379 if (rc)
4380 return rc;
4382 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4383 name_len =
4384 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4385 PATH_MAX, nls_codepage);
4386 name_len++; /* trailing null */
4387 name_len *= 2;
4388 } else { /* BB improve the check for buffer overruns BB */
4389 name_len = strnlen(fileName, PATH_MAX);
4390 name_len++; /* trailing null */
4391 strncpy(pSMB->fileName, fileName, name_len);
4393 pSMB->attr = cpu_to_le16(dos_attrs);
4394 pSMB->BufferFormat = 0x04;
4395 pSMB->hdr.smb_buf_length += name_len + 1;
4396 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4397 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4398 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4399 if (rc) {
4400 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4403 cifs_buf_release(pSMB);
4405 if (rc == -EAGAIN)
4406 goto SetAttrLgcyRetry;
4408 return rc;
4410 #endif /* temporarily unneeded SetAttr legacy function */
4413 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4414 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4415 dev_t device, const struct nls_table *nls_codepage,
4416 int remap)
4418 TRANSACTION2_SPI_REQ *pSMB = NULL;
4419 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4420 int name_len;
4421 int rc = 0;
4422 int bytes_returned = 0;
4423 FILE_UNIX_BASIC_INFO *data_offset;
4424 __u16 params, param_offset, offset, count, byte_count;
4426 cFYI(1, ("In SetUID/GID/Mode"));
4427 setPermsRetry:
4428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429 (void **) &pSMBr);
4430 if (rc)
4431 return rc;
4433 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4434 name_len =
4435 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4436 PATH_MAX, nls_codepage, remap);
4437 name_len++; /* trailing null */
4438 name_len *= 2;
4439 } else { /* BB improve the check for buffer overruns BB */
4440 name_len = strnlen(fileName, PATH_MAX);
4441 name_len++; /* trailing null */
4442 strncpy(pSMB->FileName, fileName, name_len);
4445 params = 6 + name_len;
4446 count = sizeof (FILE_UNIX_BASIC_INFO);
4447 pSMB->MaxParameterCount = cpu_to_le16(2);
4448 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4449 pSMB->MaxSetupCount = 0;
4450 pSMB->Reserved = 0;
4451 pSMB->Flags = 0;
4452 pSMB->Timeout = 0;
4453 pSMB->Reserved2 = 0;
4454 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4455 InformationLevel) - 4;
4456 offset = param_offset + params;
4457 data_offset =
4458 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4459 offset);
4460 memset(data_offset, 0, count);
4461 pSMB->DataOffset = cpu_to_le16(offset);
4462 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4463 pSMB->SetupCount = 1;
4464 pSMB->Reserved3 = 0;
4465 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4466 byte_count = 3 /* pad */ + params + count;
4467 pSMB->ParameterCount = cpu_to_le16(params);
4468 pSMB->DataCount = cpu_to_le16(count);
4469 pSMB->TotalParameterCount = pSMB->ParameterCount;
4470 pSMB->TotalDataCount = pSMB->DataCount;
4471 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4472 pSMB->Reserved4 = 0;
4473 pSMB->hdr.smb_buf_length += byte_count;
4474 data_offset->Uid = cpu_to_le64(uid);
4475 data_offset->Gid = cpu_to_le64(gid);
4476 /* better to leave device as zero when it is */
4477 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4478 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4479 data_offset->Permissions = cpu_to_le64(mode);
4481 if(S_ISREG(mode))
4482 data_offset->Type = cpu_to_le32(UNIX_FILE);
4483 else if(S_ISDIR(mode))
4484 data_offset->Type = cpu_to_le32(UNIX_DIR);
4485 else if(S_ISLNK(mode))
4486 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4487 else if(S_ISCHR(mode))
4488 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4489 else if(S_ISBLK(mode))
4490 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4491 else if(S_ISFIFO(mode))
4492 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4493 else if(S_ISSOCK(mode))
4494 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4497 pSMB->ByteCount = cpu_to_le16(byte_count);
4498 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4500 if (rc) {
4501 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4504 if (pSMB)
4505 cifs_buf_release(pSMB);
4506 if (rc == -EAGAIN)
4507 goto setPermsRetry;
4508 return rc;
4511 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4512 const int notify_subdirs, const __u16 netfid,
4513 __u32 filter, struct file * pfile, int multishot,
4514 const struct nls_table *nls_codepage)
4516 int rc = 0;
4517 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4518 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4519 struct dir_notify_req *dnotify_req;
4520 int bytes_returned;
4522 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4523 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4524 (void **) &pSMBr);
4525 if (rc)
4526 return rc;
4528 pSMB->TotalParameterCount = 0 ;
4529 pSMB->TotalDataCount = 0;
4530 pSMB->MaxParameterCount = cpu_to_le32(2);
4531 /* BB find exact data count max from sess structure BB */
4532 pSMB->MaxDataCount = 0; /* same in little endian or be */
4533 /* BB VERIFY verify which is correct for above BB */
4534 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4535 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4537 pSMB->MaxSetupCount = 4;
4538 pSMB->Reserved = 0;
4539 pSMB->ParameterOffset = 0;
4540 pSMB->DataCount = 0;
4541 pSMB->DataOffset = 0;
4542 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4543 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4544 pSMB->ParameterCount = pSMB->TotalParameterCount;
4545 if(notify_subdirs)
4546 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4547 pSMB->Reserved2 = 0;
4548 pSMB->CompletionFilter = cpu_to_le32(filter);
4549 pSMB->Fid = netfid; /* file handle always le */
4550 pSMB->ByteCount = 0;
4552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4553 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4554 if (rc) {
4555 cFYI(1, ("Error in Notify = %d", rc));
4556 } else {
4557 /* Add file to outstanding requests */
4558 /* BB change to kmem cache alloc */
4559 dnotify_req = (struct dir_notify_req *) kmalloc(
4560 sizeof(struct dir_notify_req),
4561 GFP_KERNEL);
4562 if(dnotify_req) {
4563 dnotify_req->Pid = pSMB->hdr.Pid;
4564 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4565 dnotify_req->Mid = pSMB->hdr.Mid;
4566 dnotify_req->Tid = pSMB->hdr.Tid;
4567 dnotify_req->Uid = pSMB->hdr.Uid;
4568 dnotify_req->netfid = netfid;
4569 dnotify_req->pfile = pfile;
4570 dnotify_req->filter = filter;
4571 dnotify_req->multishot = multishot;
4572 spin_lock(&GlobalMid_Lock);
4573 list_add_tail(&dnotify_req->lhead,
4574 &GlobalDnotifyReqList);
4575 spin_unlock(&GlobalMid_Lock);
4576 } else
4577 rc = -ENOMEM;
4579 cifs_buf_release(pSMB);
4580 return rc;
4582 #ifdef CONFIG_CIFS_XATTR
4583 ssize_t
4584 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4585 const unsigned char *searchName,
4586 char * EAData, size_t buf_size,
4587 const struct nls_table *nls_codepage, int remap)
4589 /* BB assumes one setup word */
4590 TRANSACTION2_QPI_REQ *pSMB = NULL;
4591 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4592 int rc = 0;
4593 int bytes_returned;
4594 int name_len;
4595 struct fea * temp_fea;
4596 char * temp_ptr;
4597 __u16 params, byte_count;
4599 cFYI(1, ("In Query All EAs path %s", searchName));
4600 QAllEAsRetry:
4601 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4602 (void **) &pSMBr);
4603 if (rc)
4604 return rc;
4606 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4607 name_len =
4608 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4609 PATH_MAX, nls_codepage, remap);
4610 name_len++; /* trailing null */
4611 name_len *= 2;
4612 } else { /* BB improve the check for buffer overruns BB */
4613 name_len = strnlen(searchName, PATH_MAX);
4614 name_len++; /* trailing null */
4615 strncpy(pSMB->FileName, searchName, name_len);
4618 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4619 pSMB->TotalDataCount = 0;
4620 pSMB->MaxParameterCount = cpu_to_le16(2);
4621 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4622 pSMB->MaxSetupCount = 0;
4623 pSMB->Reserved = 0;
4624 pSMB->Flags = 0;
4625 pSMB->Timeout = 0;
4626 pSMB->Reserved2 = 0;
4627 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4628 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4629 pSMB->DataCount = 0;
4630 pSMB->DataOffset = 0;
4631 pSMB->SetupCount = 1;
4632 pSMB->Reserved3 = 0;
4633 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4634 byte_count = params + 1 /* pad */ ;
4635 pSMB->TotalParameterCount = cpu_to_le16(params);
4636 pSMB->ParameterCount = pSMB->TotalParameterCount;
4637 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4638 pSMB->Reserved4 = 0;
4639 pSMB->hdr.smb_buf_length += byte_count;
4640 pSMB->ByteCount = cpu_to_le16(byte_count);
4642 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4643 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4644 if (rc) {
4645 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4646 } else { /* decode response */
4647 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4649 /* BB also check enough total bytes returned */
4650 /* BB we need to improve the validity checking
4651 of these trans2 responses */
4652 if (rc || (pSMBr->ByteCount < 4))
4653 rc = -EIO; /* bad smb */
4654 /* else if (pFindData){
4655 memcpy((char *) pFindData,
4656 (char *) &pSMBr->hdr.Protocol +
4657 data_offset, kl);
4658 }*/ else {
4659 /* check that length of list is not more than bcc */
4660 /* check that each entry does not go beyond length
4661 of list */
4662 /* check that each element of each entry does not
4663 go beyond end of list */
4664 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4665 struct fealist * ea_response_data;
4666 rc = 0;
4667 /* validate_trans2_offsets() */
4668 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4669 ea_response_data = (struct fealist *)
4670 (((char *) &pSMBr->hdr.Protocol) +
4671 data_offset);
4672 name_len = le32_to_cpu(ea_response_data->list_len);
4673 cFYI(1,("ea length %d", name_len));
4674 if(name_len <= 8) {
4675 /* returned EA size zeroed at top of function */
4676 cFYI(1,("empty EA list returned from server"));
4677 } else {
4678 /* account for ea list len */
4679 name_len -= 4;
4680 temp_fea = ea_response_data->list;
4681 temp_ptr = (char *)temp_fea;
4682 while(name_len > 0) {
4683 __u16 value_len;
4684 name_len -= 4;
4685 temp_ptr += 4;
4686 rc += temp_fea->name_len;
4687 /* account for prefix user. and trailing null */
4688 rc = rc + 5 + 1;
4689 if(rc<(int)buf_size) {
4690 memcpy(EAData,"user.",5);
4691 EAData+=5;
4692 memcpy(EAData,temp_ptr,temp_fea->name_len);
4693 EAData+=temp_fea->name_len;
4694 /* null terminate name */
4695 *EAData = 0;
4696 EAData = EAData + 1;
4697 } else if(buf_size == 0) {
4698 /* skip copy - calc size only */
4699 } else {
4700 /* stop before overrun buffer */
4701 rc = -ERANGE;
4702 break;
4704 name_len -= temp_fea->name_len;
4705 temp_ptr += temp_fea->name_len;
4706 /* account for trailing null */
4707 name_len--;
4708 temp_ptr++;
4709 value_len = le16_to_cpu(temp_fea->value_len);
4710 name_len -= value_len;
4711 temp_ptr += value_len;
4712 /* BB check that temp_ptr is still within smb BB*/
4713 /* no trailing null to account for in value len */
4714 /* go on to next EA */
4715 temp_fea = (struct fea *)temp_ptr;
4720 if (pSMB)
4721 cifs_buf_release(pSMB);
4722 if (rc == -EAGAIN)
4723 goto QAllEAsRetry;
4725 return (ssize_t)rc;
4728 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4729 const unsigned char * searchName,const unsigned char * ea_name,
4730 unsigned char * ea_value, size_t buf_size,
4731 const struct nls_table *nls_codepage, int remap)
4733 TRANSACTION2_QPI_REQ *pSMB = NULL;
4734 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4735 int rc = 0;
4736 int bytes_returned;
4737 int name_len;
4738 struct fea * temp_fea;
4739 char * temp_ptr;
4740 __u16 params, byte_count;
4742 cFYI(1, ("In Query EA path %s", searchName));
4743 QEARetry:
4744 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4745 (void **) &pSMBr);
4746 if (rc)
4747 return rc;
4749 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4750 name_len =
4751 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4752 PATH_MAX, nls_codepage, remap);
4753 name_len++; /* trailing null */
4754 name_len *= 2;
4755 } else { /* BB improve the check for buffer overruns BB */
4756 name_len = strnlen(searchName, PATH_MAX);
4757 name_len++; /* trailing null */
4758 strncpy(pSMB->FileName, searchName, name_len);
4761 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4762 pSMB->TotalDataCount = 0;
4763 pSMB->MaxParameterCount = cpu_to_le16(2);
4764 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4765 pSMB->MaxSetupCount = 0;
4766 pSMB->Reserved = 0;
4767 pSMB->Flags = 0;
4768 pSMB->Timeout = 0;
4769 pSMB->Reserved2 = 0;
4770 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4771 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4772 pSMB->DataCount = 0;
4773 pSMB->DataOffset = 0;
4774 pSMB->SetupCount = 1;
4775 pSMB->Reserved3 = 0;
4776 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4777 byte_count = params + 1 /* pad */ ;
4778 pSMB->TotalParameterCount = cpu_to_le16(params);
4779 pSMB->ParameterCount = pSMB->TotalParameterCount;
4780 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4781 pSMB->Reserved4 = 0;
4782 pSMB->hdr.smb_buf_length += byte_count;
4783 pSMB->ByteCount = cpu_to_le16(byte_count);
4785 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4786 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4787 if (rc) {
4788 cFYI(1, ("Send error in Query EA = %d", rc));
4789 } else { /* decode response */
4790 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4792 /* BB also check enough total bytes returned */
4793 /* BB we need to improve the validity checking
4794 of these trans2 responses */
4795 if (rc || (pSMBr->ByteCount < 4))
4796 rc = -EIO; /* bad smb */
4797 /* else if (pFindData){
4798 memcpy((char *) pFindData,
4799 (char *) &pSMBr->hdr.Protocol +
4800 data_offset, kl);
4801 }*/ else {
4802 /* check that length of list is not more than bcc */
4803 /* check that each entry does not go beyond length
4804 of list */
4805 /* check that each element of each entry does not
4806 go beyond end of list */
4807 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4808 struct fealist * ea_response_data;
4809 rc = -ENODATA;
4810 /* validate_trans2_offsets() */
4811 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4812 ea_response_data = (struct fealist *)
4813 (((char *) &pSMBr->hdr.Protocol) +
4814 data_offset);
4815 name_len = le32_to_cpu(ea_response_data->list_len);
4816 cFYI(1,("ea length %d", name_len));
4817 if(name_len <= 8) {
4818 /* returned EA size zeroed at top of function */
4819 cFYI(1,("empty EA list returned from server"));
4820 } else {
4821 /* account for ea list len */
4822 name_len -= 4;
4823 temp_fea = ea_response_data->list;
4824 temp_ptr = (char *)temp_fea;
4825 /* loop through checking if we have a matching
4826 name and then return the associated value */
4827 while(name_len > 0) {
4828 __u16 value_len;
4829 name_len -= 4;
4830 temp_ptr += 4;
4831 value_len = le16_to_cpu(temp_fea->value_len);
4832 /* BB validate that value_len falls within SMB,
4833 even though maximum for name_len is 255 */
4834 if(memcmp(temp_fea->name,ea_name,
4835 temp_fea->name_len) == 0) {
4836 /* found a match */
4837 rc = value_len;
4838 /* account for prefix user. and trailing null */
4839 if(rc<=(int)buf_size) {
4840 memcpy(ea_value,
4841 temp_fea->name+temp_fea->name_len+1,
4842 rc);
4843 /* ea values, unlike ea names,
4844 are not null terminated */
4845 } else if(buf_size == 0) {
4846 /* skip copy - calc size only */
4847 } else {
4848 /* stop before overrun buffer */
4849 rc = -ERANGE;
4851 break;
4853 name_len -= temp_fea->name_len;
4854 temp_ptr += temp_fea->name_len;
4855 /* account for trailing null */
4856 name_len--;
4857 temp_ptr++;
4858 name_len -= value_len;
4859 temp_ptr += value_len;
4860 /* no trailing null to account for in value len */
4861 /* go on to next EA */
4862 temp_fea = (struct fea *)temp_ptr;
4867 if (pSMB)
4868 cifs_buf_release(pSMB);
4869 if (rc == -EAGAIN)
4870 goto QEARetry;
4872 return (ssize_t)rc;
4876 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4877 const char * ea_name, const void * ea_value,
4878 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4879 int remap)
4881 struct smb_com_transaction2_spi_req *pSMB = NULL;
4882 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4883 struct fealist *parm_data;
4884 int name_len;
4885 int rc = 0;
4886 int bytes_returned = 0;
4887 __u16 params, param_offset, byte_count, offset, count;
4889 cFYI(1, ("In SetEA"));
4890 SetEARetry:
4891 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4892 (void **) &pSMBr);
4893 if (rc)
4894 return rc;
4896 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4897 name_len =
4898 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4899 PATH_MAX, nls_codepage, remap);
4900 name_len++; /* trailing null */
4901 name_len *= 2;
4902 } else { /* BB improve the check for buffer overruns BB */
4903 name_len = strnlen(fileName, PATH_MAX);
4904 name_len++; /* trailing null */
4905 strncpy(pSMB->FileName, fileName, name_len);
4908 params = 6 + name_len;
4910 /* done calculating parms using name_len of file name,
4911 now use name_len to calculate length of ea name
4912 we are going to create in the inode xattrs */
4913 if(ea_name == NULL)
4914 name_len = 0;
4915 else
4916 name_len = strnlen(ea_name,255);
4918 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4919 pSMB->MaxParameterCount = cpu_to_le16(2);
4920 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4921 pSMB->MaxSetupCount = 0;
4922 pSMB->Reserved = 0;
4923 pSMB->Flags = 0;
4924 pSMB->Timeout = 0;
4925 pSMB->Reserved2 = 0;
4926 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4927 InformationLevel) - 4;
4928 offset = param_offset + params;
4929 pSMB->InformationLevel =
4930 cpu_to_le16(SMB_SET_FILE_EA);
4932 parm_data =
4933 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4934 offset);
4935 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4936 pSMB->DataOffset = cpu_to_le16(offset);
4937 pSMB->SetupCount = 1;
4938 pSMB->Reserved3 = 0;
4939 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4940 byte_count = 3 /* pad */ + params + count;
4941 pSMB->DataCount = cpu_to_le16(count);
4942 parm_data->list_len = cpu_to_le32(count);
4943 parm_data->list[0].EA_flags = 0;
4944 /* we checked above that name len is less than 255 */
4945 parm_data->list[0].name_len = (__u8)name_len;;
4946 /* EA names are always ASCII */
4947 if(ea_name)
4948 strncpy(parm_data->list[0].name,ea_name,name_len);
4949 parm_data->list[0].name[name_len] = 0;
4950 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4951 /* caller ensures that ea_value_len is less than 64K but
4952 we need to ensure that it fits within the smb */
4954 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4955 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4956 if(ea_value_len)
4957 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4959 pSMB->TotalDataCount = pSMB->DataCount;
4960 pSMB->ParameterCount = cpu_to_le16(params);
4961 pSMB->TotalParameterCount = pSMB->ParameterCount;
4962 pSMB->Reserved4 = 0;
4963 pSMB->hdr.smb_buf_length += byte_count;
4964 pSMB->ByteCount = cpu_to_le16(byte_count);
4965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4967 if (rc) {
4968 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4971 cifs_buf_release(pSMB);
4973 if (rc == -EAGAIN)
4974 goto SetEARetry;
4976 return rc;
4979 #endif