[PATCH] libata: cosmetic updates
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / cifssmb.c
blob925881e00ff210e08822cc456337be1734f801d8
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 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1357 const __u16 smb_file_id, const int get_flag, const __u64 len,
1358 struct file_lock *pLockData, const __u16 lock_type,
1359 const int waitFlag)
1361 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1362 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1363 char *data_offset;
1364 struct cifs_posix_lock *parm_data;
1365 int rc = 0;
1366 int bytes_returned = 0;
1367 __u16 params, param_offset, offset, byte_count, count;
1369 cFYI(1, ("Posix Lock"));
1371 if(pLockData == NULL)
1372 return EINVAL;
1374 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1376 if (rc)
1377 return rc;
1379 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1381 params = 6;
1382 pSMB->MaxSetupCount = 0;
1383 pSMB->Reserved = 0;
1384 pSMB->Flags = 0;
1385 pSMB->Timeout = 0;
1386 pSMB->Reserved2 = 0;
1387 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1388 offset = param_offset + params;
1390 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1392 count = sizeof(struct cifs_posix_lock);
1393 pSMB->MaxParameterCount = cpu_to_le16(2);
1394 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1395 pSMB->SetupCount = 1;
1396 pSMB->Reserved3 = 0;
1397 if(get_flag)
1398 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1399 else
1400 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1401 byte_count = 3 /* pad */ + params + count;
1402 pSMB->DataCount = cpu_to_le16(count);
1403 pSMB->ParameterCount = cpu_to_le16(params);
1404 pSMB->TotalDataCount = pSMB->DataCount;
1405 pSMB->TotalParameterCount = pSMB->ParameterCount;
1406 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1407 parm_data = (struct cifs_posix_lock *)
1408 (((char *) &pSMB->hdr.Protocol) + offset);
1410 parm_data->lock_type = cpu_to_le16(lock_type);
1411 if(waitFlag)
1412 parm_data->lock_flags = cpu_to_le16(1);
1413 parm_data->pid = cpu_to_le32(current->tgid);
1414 parm_data->start = cpu_to_le64(pLockData->fl_start);
1415 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1417 pSMB->DataOffset = cpu_to_le16(offset);
1418 pSMB->Fid = smb_file_id;
1419 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1420 pSMB->Reserved4 = 0;
1421 pSMB->hdr.smb_buf_length += byte_count;
1422 pSMB->ByteCount = cpu_to_le16(byte_count);
1423 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1425 if (rc) {
1426 cFYI(1, ("Send error in Posix Lock = %d", rc));
1427 } else if (get_flag) {
1428 /* lock structure can be returned on get */
1429 __u16 data_offset;
1430 __u16 data_count;
1431 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1433 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1434 rc = -EIO; /* bad smb */
1435 goto plk_err_exit;
1437 if(pLockData == NULL) {
1438 rc = -EINVAL;
1439 goto plk_err_exit;
1441 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1442 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1443 if(data_count < sizeof(struct cifs_posix_lock)) {
1444 rc = -EIO;
1445 goto plk_err_exit;
1447 parm_data = (struct cifs_posix_lock *)
1448 ((char *)&pSMBr->hdr.Protocol + data_offset);
1449 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1450 pLockData->fl_type = F_UNLCK;
1453 plk_err_exit:
1454 if (pSMB)
1455 cifs_small_buf_release(pSMB);
1457 /* Note: On -EAGAIN error only caller can retry on handle based calls
1458 since file handle passed in no longer valid */
1460 return rc;
1465 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1467 int rc = 0;
1468 CLOSE_REQ *pSMB = NULL;
1469 CLOSE_RSP *pSMBr = NULL;
1470 int bytes_returned;
1471 cFYI(1, ("In CIFSSMBClose"));
1473 /* do not retry on dead session on close */
1474 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1475 if(rc == -EAGAIN)
1476 return 0;
1477 if (rc)
1478 return rc;
1480 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1482 pSMB->FileID = (__u16) smb_file_id;
1483 pSMB->LastWriteTime = 0;
1484 pSMB->ByteCount = 0;
1485 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1486 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1487 cifs_stats_inc(&tcon->num_closes);
1488 if (rc) {
1489 if(rc!=-EINTR) {
1490 /* EINTR is expected when user ctl-c to kill app */
1491 cERROR(1, ("Send error in Close = %d", rc));
1495 cifs_small_buf_release(pSMB);
1497 /* Since session is dead, file will be closed on server already */
1498 if(rc == -EAGAIN)
1499 rc = 0;
1501 return rc;
1505 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1506 const char *fromName, const char *toName,
1507 const struct nls_table *nls_codepage, int remap)
1509 int rc = 0;
1510 RENAME_REQ *pSMB = NULL;
1511 RENAME_RSP *pSMBr = NULL;
1512 int bytes_returned;
1513 int name_len, name_len2;
1514 __u16 count;
1516 cFYI(1, ("In CIFSSMBRename"));
1517 renameRetry:
1518 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1519 (void **) &pSMBr);
1520 if (rc)
1521 return rc;
1523 pSMB->BufferFormat = 0x04;
1524 pSMB->SearchAttributes =
1525 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1526 ATTR_DIRECTORY);
1528 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1529 name_len =
1530 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1531 PATH_MAX, nls_codepage, remap);
1532 name_len++; /* trailing null */
1533 name_len *= 2;
1534 pSMB->OldFileName[name_len] = 0x04; /* pad */
1535 /* protocol requires ASCII signature byte on Unicode string */
1536 pSMB->OldFileName[name_len + 1] = 0x00;
1537 name_len2 =
1538 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1539 toName, PATH_MAX, nls_codepage, remap);
1540 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1541 name_len2 *= 2; /* convert to bytes */
1542 } else { /* BB improve the check for buffer overruns BB */
1543 name_len = strnlen(fromName, PATH_MAX);
1544 name_len++; /* trailing null */
1545 strncpy(pSMB->OldFileName, fromName, name_len);
1546 name_len2 = strnlen(toName, PATH_MAX);
1547 name_len2++; /* trailing null */
1548 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1549 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1550 name_len2++; /* trailing null */
1551 name_len2++; /* signature byte */
1554 count = 1 /* 1st signature byte */ + name_len + name_len2;
1555 pSMB->hdr.smb_buf_length += count;
1556 pSMB->ByteCount = cpu_to_le16(count);
1558 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1559 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1560 cifs_stats_inc(&tcon->num_renames);
1561 if (rc) {
1562 cFYI(1, ("Send error in rename = %d", rc));
1565 cifs_buf_release(pSMB);
1567 if (rc == -EAGAIN)
1568 goto renameRetry;
1570 return rc;
1573 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
1574 int netfid, char * target_name,
1575 const struct nls_table * nls_codepage, int remap)
1577 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1578 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1579 struct set_file_rename * rename_info;
1580 char *data_offset;
1581 char dummy_string[30];
1582 int rc = 0;
1583 int bytes_returned = 0;
1584 int len_of_str;
1585 __u16 params, param_offset, offset, count, byte_count;
1587 cFYI(1, ("Rename to File by handle"));
1588 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1589 (void **) &pSMBr);
1590 if (rc)
1591 return rc;
1593 params = 6;
1594 pSMB->MaxSetupCount = 0;
1595 pSMB->Reserved = 0;
1596 pSMB->Flags = 0;
1597 pSMB->Timeout = 0;
1598 pSMB->Reserved2 = 0;
1599 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1600 offset = param_offset + params;
1602 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1603 rename_info = (struct set_file_rename *) data_offset;
1604 pSMB->MaxParameterCount = cpu_to_le16(2);
1605 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1606 pSMB->SetupCount = 1;
1607 pSMB->Reserved3 = 0;
1608 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1609 byte_count = 3 /* pad */ + params;
1610 pSMB->ParameterCount = cpu_to_le16(params);
1611 pSMB->TotalParameterCount = pSMB->ParameterCount;
1612 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1613 pSMB->DataOffset = cpu_to_le16(offset);
1614 /* construct random name ".cifs_tmp<inodenum><mid>" */
1615 rename_info->overwrite = cpu_to_le32(1);
1616 rename_info->root_fid = 0;
1617 /* unicode only call */
1618 if(target_name == NULL) {
1619 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1620 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1621 dummy_string, 24, nls_codepage, remap);
1622 } else {
1623 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1624 target_name, PATH_MAX, nls_codepage, remap);
1626 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1627 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1628 byte_count += count;
1629 pSMB->DataCount = cpu_to_le16(count);
1630 pSMB->TotalDataCount = pSMB->DataCount;
1631 pSMB->Fid = netfid;
1632 pSMB->InformationLevel =
1633 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1634 pSMB->Reserved4 = 0;
1635 pSMB->hdr.smb_buf_length += byte_count;
1636 pSMB->ByteCount = cpu_to_le16(byte_count);
1637 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1638 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1639 cifs_stats_inc(&pTcon->num_t2renames);
1640 if (rc) {
1641 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1644 cifs_buf_release(pSMB);
1646 /* Note: On -EAGAIN error only caller can retry on handle based calls
1647 since file handle passed in no longer valid */
1649 return rc;
1653 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1654 const __u16 target_tid, const char *toName, const int flags,
1655 const struct nls_table *nls_codepage, int remap)
1657 int rc = 0;
1658 COPY_REQ *pSMB = NULL;
1659 COPY_RSP *pSMBr = NULL;
1660 int bytes_returned;
1661 int name_len, name_len2;
1662 __u16 count;
1664 cFYI(1, ("In CIFSSMBCopy"));
1665 copyRetry:
1666 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1667 (void **) &pSMBr);
1668 if (rc)
1669 return rc;
1671 pSMB->BufferFormat = 0x04;
1672 pSMB->Tid2 = target_tid;
1674 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1676 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1677 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
1678 fromName, PATH_MAX, nls_codepage,
1679 remap);
1680 name_len++; /* trailing null */
1681 name_len *= 2;
1682 pSMB->OldFileName[name_len] = 0x04; /* pad */
1683 /* protocol requires ASCII signature byte on Unicode string */
1684 pSMB->OldFileName[name_len + 1] = 0x00;
1685 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1686 toName, PATH_MAX, nls_codepage, remap);
1687 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1688 name_len2 *= 2; /* convert to bytes */
1689 } else { /* BB improve the check for buffer overruns BB */
1690 name_len = strnlen(fromName, PATH_MAX);
1691 name_len++; /* trailing null */
1692 strncpy(pSMB->OldFileName, fromName, name_len);
1693 name_len2 = strnlen(toName, PATH_MAX);
1694 name_len2++; /* trailing null */
1695 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1696 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1697 name_len2++; /* trailing null */
1698 name_len2++; /* signature byte */
1701 count = 1 /* 1st signature byte */ + name_len + name_len2;
1702 pSMB->hdr.smb_buf_length += count;
1703 pSMB->ByteCount = cpu_to_le16(count);
1705 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1706 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1707 if (rc) {
1708 cFYI(1, ("Send error in copy = %d with %d files copied",
1709 rc, le16_to_cpu(pSMBr->CopyCount)));
1711 if (pSMB)
1712 cifs_buf_release(pSMB);
1714 if (rc == -EAGAIN)
1715 goto copyRetry;
1717 return rc;
1721 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1722 const char *fromName, const char *toName,
1723 const struct nls_table *nls_codepage)
1725 TRANSACTION2_SPI_REQ *pSMB = NULL;
1726 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1727 char *data_offset;
1728 int name_len;
1729 int name_len_target;
1730 int rc = 0;
1731 int bytes_returned = 0;
1732 __u16 params, param_offset, offset, byte_count;
1734 cFYI(1, ("In Symlink Unix style"));
1735 createSymLinkRetry:
1736 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1737 (void **) &pSMBr);
1738 if (rc)
1739 return rc;
1741 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1742 name_len =
1743 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1744 /* find define for this maxpathcomponent */
1745 , nls_codepage);
1746 name_len++; /* trailing null */
1747 name_len *= 2;
1749 } else { /* BB improve the check for buffer overruns BB */
1750 name_len = strnlen(fromName, PATH_MAX);
1751 name_len++; /* trailing null */
1752 strncpy(pSMB->FileName, fromName, name_len);
1754 params = 6 + name_len;
1755 pSMB->MaxSetupCount = 0;
1756 pSMB->Reserved = 0;
1757 pSMB->Flags = 0;
1758 pSMB->Timeout = 0;
1759 pSMB->Reserved2 = 0;
1760 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1761 InformationLevel) - 4;
1762 offset = param_offset + params;
1764 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1765 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1766 name_len_target =
1767 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1768 /* find define for this maxpathcomponent */
1769 , nls_codepage);
1770 name_len_target++; /* trailing null */
1771 name_len_target *= 2;
1772 } else { /* BB improve the check for buffer overruns BB */
1773 name_len_target = strnlen(toName, PATH_MAX);
1774 name_len_target++; /* trailing null */
1775 strncpy(data_offset, toName, name_len_target);
1778 pSMB->MaxParameterCount = cpu_to_le16(2);
1779 /* BB find exact max on data count below from sess */
1780 pSMB->MaxDataCount = cpu_to_le16(1000);
1781 pSMB->SetupCount = 1;
1782 pSMB->Reserved3 = 0;
1783 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1784 byte_count = 3 /* pad */ + params + name_len_target;
1785 pSMB->DataCount = cpu_to_le16(name_len_target);
1786 pSMB->ParameterCount = cpu_to_le16(params);
1787 pSMB->TotalDataCount = pSMB->DataCount;
1788 pSMB->TotalParameterCount = pSMB->ParameterCount;
1789 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1790 pSMB->DataOffset = cpu_to_le16(offset);
1791 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1792 pSMB->Reserved4 = 0;
1793 pSMB->hdr.smb_buf_length += byte_count;
1794 pSMB->ByteCount = cpu_to_le16(byte_count);
1795 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1796 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1797 cifs_stats_inc(&tcon->num_symlinks);
1798 if (rc) {
1799 cFYI(1,
1800 ("Send error in SetPathInfo (create symlink) = %d",
1801 rc));
1804 if (pSMB)
1805 cifs_buf_release(pSMB);
1807 if (rc == -EAGAIN)
1808 goto createSymLinkRetry;
1810 return rc;
1814 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1815 const char *fromName, const char *toName,
1816 const struct nls_table *nls_codepage, int remap)
1818 TRANSACTION2_SPI_REQ *pSMB = NULL;
1819 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1820 char *data_offset;
1821 int name_len;
1822 int name_len_target;
1823 int rc = 0;
1824 int bytes_returned = 0;
1825 __u16 params, param_offset, offset, byte_count;
1827 cFYI(1, ("In Create Hard link Unix style"));
1828 createHardLinkRetry:
1829 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1830 (void **) &pSMBr);
1831 if (rc)
1832 return rc;
1834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1835 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1836 PATH_MAX, nls_codepage, remap);
1837 name_len++; /* trailing null */
1838 name_len *= 2;
1840 } else { /* BB improve the check for buffer overruns BB */
1841 name_len = strnlen(toName, PATH_MAX);
1842 name_len++; /* trailing null */
1843 strncpy(pSMB->FileName, toName, name_len);
1845 params = 6 + name_len;
1846 pSMB->MaxSetupCount = 0;
1847 pSMB->Reserved = 0;
1848 pSMB->Flags = 0;
1849 pSMB->Timeout = 0;
1850 pSMB->Reserved2 = 0;
1851 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1852 InformationLevel) - 4;
1853 offset = param_offset + params;
1855 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1857 name_len_target =
1858 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1859 nls_codepage, remap);
1860 name_len_target++; /* trailing null */
1861 name_len_target *= 2;
1862 } else { /* BB improve the check for buffer overruns BB */
1863 name_len_target = strnlen(fromName, PATH_MAX);
1864 name_len_target++; /* trailing null */
1865 strncpy(data_offset, fromName, name_len_target);
1868 pSMB->MaxParameterCount = cpu_to_le16(2);
1869 /* BB find exact max on data count below from sess*/
1870 pSMB->MaxDataCount = cpu_to_le16(1000);
1871 pSMB->SetupCount = 1;
1872 pSMB->Reserved3 = 0;
1873 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1874 byte_count = 3 /* pad */ + params + name_len_target;
1875 pSMB->ParameterCount = cpu_to_le16(params);
1876 pSMB->TotalParameterCount = pSMB->ParameterCount;
1877 pSMB->DataCount = cpu_to_le16(name_len_target);
1878 pSMB->TotalDataCount = pSMB->DataCount;
1879 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1880 pSMB->DataOffset = cpu_to_le16(offset);
1881 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1882 pSMB->Reserved4 = 0;
1883 pSMB->hdr.smb_buf_length += byte_count;
1884 pSMB->ByteCount = cpu_to_le16(byte_count);
1885 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1886 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1887 cifs_stats_inc(&tcon->num_hardlinks);
1888 if (rc) {
1889 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1892 cifs_buf_release(pSMB);
1893 if (rc == -EAGAIN)
1894 goto createHardLinkRetry;
1896 return rc;
1900 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1901 const char *fromName, const char *toName,
1902 const struct nls_table *nls_codepage, int remap)
1904 int rc = 0;
1905 NT_RENAME_REQ *pSMB = NULL;
1906 RENAME_RSP *pSMBr = NULL;
1907 int bytes_returned;
1908 int name_len, name_len2;
1909 __u16 count;
1911 cFYI(1, ("In CIFSCreateHardLink"));
1912 winCreateHardLinkRetry:
1914 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1915 (void **) &pSMBr);
1916 if (rc)
1917 return rc;
1919 pSMB->SearchAttributes =
1920 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1921 ATTR_DIRECTORY);
1922 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1923 pSMB->ClusterCount = 0;
1925 pSMB->BufferFormat = 0x04;
1927 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1928 name_len =
1929 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1930 PATH_MAX, nls_codepage, remap);
1931 name_len++; /* trailing null */
1932 name_len *= 2;
1933 pSMB->OldFileName[name_len] = 0; /* pad */
1934 pSMB->OldFileName[name_len + 1] = 0x04;
1935 name_len2 =
1936 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
1937 toName, PATH_MAX, nls_codepage, remap);
1938 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1939 name_len2 *= 2; /* convert to bytes */
1940 } else { /* BB improve the check for buffer overruns BB */
1941 name_len = strnlen(fromName, PATH_MAX);
1942 name_len++; /* trailing null */
1943 strncpy(pSMB->OldFileName, fromName, name_len);
1944 name_len2 = strnlen(toName, PATH_MAX);
1945 name_len2++; /* trailing null */
1946 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1947 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1948 name_len2++; /* trailing null */
1949 name_len2++; /* signature byte */
1952 count = 1 /* string type byte */ + name_len + name_len2;
1953 pSMB->hdr.smb_buf_length += count;
1954 pSMB->ByteCount = cpu_to_le16(count);
1956 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1957 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1958 cifs_stats_inc(&tcon->num_hardlinks);
1959 if (rc) {
1960 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1962 cifs_buf_release(pSMB);
1963 if (rc == -EAGAIN)
1964 goto winCreateHardLinkRetry;
1966 return rc;
1970 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1971 const unsigned char *searchName,
1972 char *symlinkinfo, const int buflen,
1973 const struct nls_table *nls_codepage)
1975 /* SMB_QUERY_FILE_UNIX_LINK */
1976 TRANSACTION2_QPI_REQ *pSMB = NULL;
1977 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1978 int rc = 0;
1979 int bytes_returned;
1980 int name_len;
1981 __u16 params, byte_count;
1983 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1985 querySymLinkRetry:
1986 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1987 (void **) &pSMBr);
1988 if (rc)
1989 return rc;
1991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1992 name_len =
1993 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1994 /* find define for this maxpathcomponent */
1995 , nls_codepage);
1996 name_len++; /* trailing null */
1997 name_len *= 2;
1998 } else { /* BB improve the check for buffer overruns BB */
1999 name_len = strnlen(searchName, PATH_MAX);
2000 name_len++; /* trailing null */
2001 strncpy(pSMB->FileName, searchName, name_len);
2004 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2005 pSMB->TotalDataCount = 0;
2006 pSMB->MaxParameterCount = cpu_to_le16(2);
2007 /* BB find exact max data count below from sess structure BB */
2008 pSMB->MaxDataCount = cpu_to_le16(4000);
2009 pSMB->MaxSetupCount = 0;
2010 pSMB->Reserved = 0;
2011 pSMB->Flags = 0;
2012 pSMB->Timeout = 0;
2013 pSMB->Reserved2 = 0;
2014 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2015 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2016 pSMB->DataCount = 0;
2017 pSMB->DataOffset = 0;
2018 pSMB->SetupCount = 1;
2019 pSMB->Reserved3 = 0;
2020 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2021 byte_count = params + 1 /* pad */ ;
2022 pSMB->TotalParameterCount = cpu_to_le16(params);
2023 pSMB->ParameterCount = pSMB->TotalParameterCount;
2024 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2025 pSMB->Reserved4 = 0;
2026 pSMB->hdr.smb_buf_length += byte_count;
2027 pSMB->ByteCount = cpu_to_le16(byte_count);
2029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2031 if (rc) {
2032 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2033 } else {
2034 /* decode response */
2036 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2037 if (rc || (pSMBr->ByteCount < 2))
2038 /* BB also check enough total bytes returned */
2039 rc = -EIO; /* bad smb */
2040 else {
2041 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2042 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2044 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2045 name_len = UniStrnlen((wchar_t *) ((char *)
2046 &pSMBr->hdr.Protocol +data_offset),
2047 min_t(const int, buflen,count) / 2);
2048 /* BB FIXME investigate remapping reserved chars here */
2049 cifs_strfromUCS_le(symlinkinfo,
2050 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
2051 data_offset),
2052 name_len, nls_codepage);
2053 } else {
2054 strncpy(symlinkinfo,
2055 (char *) &pSMBr->hdr.Protocol +
2056 data_offset,
2057 min_t(const int, buflen, count));
2059 symlinkinfo[buflen] = 0;
2060 /* just in case so calling code does not go off the end of buffer */
2063 cifs_buf_release(pSMB);
2064 if (rc == -EAGAIN)
2065 goto querySymLinkRetry;
2066 return rc;
2069 /* Initialize NT TRANSACT SMB into small smb request buffer.
2070 This assumes that all NT TRANSACTS that we init here have
2071 total parm and data under about 400 bytes (to fit in small cifs
2072 buffer size), which is the case so far, it easily fits. NB:
2073 Setup words themselves and ByteCount
2074 MaxSetupCount (size of returned setup area) and
2075 MaxParameterCount (returned parms size) must be set by caller */
2076 static int
2077 smb_init_ntransact(const __u16 sub_command, const int setup_count,
2078 const int parm_len, struct cifsTconInfo *tcon,
2079 void ** ret_buf)
2081 int rc;
2082 __u32 temp_offset;
2083 struct smb_com_ntransact_req * pSMB;
2085 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2086 (void **)&pSMB);
2087 if (rc)
2088 return rc;
2089 *ret_buf = (void *)pSMB;
2090 pSMB->Reserved = 0;
2091 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2092 pSMB->TotalDataCount = 0;
2093 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2094 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2095 pSMB->ParameterCount = pSMB->TotalParameterCount;
2096 pSMB->DataCount = pSMB->TotalDataCount;
2097 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2098 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2099 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2100 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2101 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2102 pSMB->SubCommand = cpu_to_le16(sub_command);
2103 return 0;
2106 static int
2107 validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2108 int * pdatalen, int * pparmlen)
2110 char * end_of_smb;
2111 __u32 data_count, data_offset, parm_count, parm_offset;
2112 struct smb_com_ntransact_rsp * pSMBr;
2114 if(buf == NULL)
2115 return -EINVAL;
2117 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2119 /* ByteCount was converted from little endian in SendReceive */
2120 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2121 (char *)&pSMBr->ByteCount;
2124 data_offset = le32_to_cpu(pSMBr->DataOffset);
2125 data_count = le32_to_cpu(pSMBr->DataCount);
2126 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2127 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2129 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2130 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2132 /* should we also check that parm and data areas do not overlap? */
2133 if(*ppparm > end_of_smb) {
2134 cFYI(1,("parms start after end of smb"));
2135 return -EINVAL;
2136 } else if(parm_count + *ppparm > end_of_smb) {
2137 cFYI(1,("parm end after end of smb"));
2138 return -EINVAL;
2139 } else if(*ppdata > end_of_smb) {
2140 cFYI(1,("data starts after end of smb"));
2141 return -EINVAL;
2142 } else if(data_count + *ppdata > end_of_smb) {
2143 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2144 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2145 return -EINVAL;
2146 } else if(parm_count + data_count > pSMBr->ByteCount) {
2147 cFYI(1,("parm count and data count larger than SMB"));
2148 return -EINVAL;
2150 return 0;
2154 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2155 const unsigned char *searchName,
2156 char *symlinkinfo, const int buflen,__u16 fid,
2157 const struct nls_table *nls_codepage)
2159 int rc = 0;
2160 int bytes_returned;
2161 int name_len;
2162 struct smb_com_transaction_ioctl_req * pSMB;
2163 struct smb_com_transaction_ioctl_rsp * pSMBr;
2165 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2166 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2167 (void **) &pSMBr);
2168 if (rc)
2169 return rc;
2171 pSMB->TotalParameterCount = 0 ;
2172 pSMB->TotalDataCount = 0;
2173 pSMB->MaxParameterCount = cpu_to_le32(2);
2174 /* BB find exact data count max from sess structure BB */
2175 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2176 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2177 pSMB->MaxSetupCount = 4;
2178 pSMB->Reserved = 0;
2179 pSMB->ParameterOffset = 0;
2180 pSMB->DataCount = 0;
2181 pSMB->DataOffset = 0;
2182 pSMB->SetupCount = 4;
2183 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2184 pSMB->ParameterCount = pSMB->TotalParameterCount;
2185 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2186 pSMB->IsFsctl = 1; /* FSCTL */
2187 pSMB->IsRootFlag = 0;
2188 pSMB->Fid = fid; /* file handle always le */
2189 pSMB->ByteCount = 0;
2191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2193 if (rc) {
2194 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2195 } else { /* decode response */
2196 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2197 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2198 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2199 /* BB also check enough total bytes returned */
2200 rc = -EIO; /* bad smb */
2201 else {
2202 if(data_count && (data_count < 2048)) {
2203 char * end_of_smb = 2 /* sizeof byte count */ +
2204 pSMBr->ByteCount +
2205 (char *)&pSMBr->ByteCount;
2207 struct reparse_data * reparse_buf = (struct reparse_data *)
2208 ((char *)&pSMBr->hdr.Protocol + data_offset);
2209 if((char*)reparse_buf >= end_of_smb) {
2210 rc = -EIO;
2211 goto qreparse_out;
2213 if((reparse_buf->LinkNamesBuf +
2214 reparse_buf->TargetNameOffset +
2215 reparse_buf->TargetNameLen) >
2216 end_of_smb) {
2217 cFYI(1,("reparse buf extended beyond SMB"));
2218 rc = -EIO;
2219 goto qreparse_out;
2222 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2223 name_len = UniStrnlen((wchar_t *)
2224 (reparse_buf->LinkNamesBuf +
2225 reparse_buf->TargetNameOffset),
2226 min(buflen/2, reparse_buf->TargetNameLen / 2));
2227 cifs_strfromUCS_le(symlinkinfo,
2228 (__le16 *) (reparse_buf->LinkNamesBuf +
2229 reparse_buf->TargetNameOffset),
2230 name_len, nls_codepage);
2231 } else { /* ASCII names */
2232 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2233 reparse_buf->TargetNameOffset,
2234 min_t(const int, buflen, reparse_buf->TargetNameLen));
2236 } else {
2237 rc = -EIO;
2238 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2240 symlinkinfo[buflen] = 0; /* just in case so the caller
2241 does not go off the end of the buffer */
2242 cFYI(1,("readlink result - %s ",symlinkinfo));
2245 qreparse_out:
2246 cifs_buf_release(pSMB);
2248 /* Note: On -EAGAIN error only caller can retry on handle based calls
2249 since file handle passed in no longer valid */
2251 return rc;
2254 #ifdef CONFIG_CIFS_POSIX
2256 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2257 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2259 /* u8 cifs fields do not need le conversion */
2260 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2261 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2262 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2263 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2265 return;
2268 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2269 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2270 const int acl_type,const int size_of_data_area)
2272 int size = 0;
2273 int i;
2274 __u16 count;
2275 struct cifs_posix_ace * pACE;
2276 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2277 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2279 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2280 return -EOPNOTSUPP;
2282 if(acl_type & ACL_TYPE_ACCESS) {
2283 count = le16_to_cpu(cifs_acl->access_entry_count);
2284 pACE = &cifs_acl->ace_array[0];
2285 size = sizeof(struct cifs_posix_acl);
2286 size += sizeof(struct cifs_posix_ace) * count;
2287 /* check if we would go beyond end of SMB */
2288 if(size_of_data_area < size) {
2289 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2290 return -EINVAL;
2292 } else if(acl_type & ACL_TYPE_DEFAULT) {
2293 count = le16_to_cpu(cifs_acl->access_entry_count);
2294 size = sizeof(struct cifs_posix_acl);
2295 size += sizeof(struct cifs_posix_ace) * count;
2296 /* skip past access ACEs to get to default ACEs */
2297 pACE = &cifs_acl->ace_array[count];
2298 count = le16_to_cpu(cifs_acl->default_entry_count);
2299 size += sizeof(struct cifs_posix_ace) * count;
2300 /* check if we would go beyond end of SMB */
2301 if(size_of_data_area < size)
2302 return -EINVAL;
2303 } else {
2304 /* illegal type */
2305 return -EINVAL;
2308 size = posix_acl_xattr_size(count);
2309 if((buflen == 0) || (local_acl == NULL)) {
2310 /* used to query ACL EA size */
2311 } else if(size > buflen) {
2312 return -ERANGE;
2313 } else /* buffer big enough */ {
2314 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2315 for(i = 0;i < count ;i++) {
2316 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2317 pACE ++;
2320 return size;
2323 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2324 const posix_acl_xattr_entry * local_ace)
2326 __u16 rc = 0; /* 0 = ACL converted ok */
2328 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2329 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2330 /* BB is there a better way to handle the large uid? */
2331 if(local_ace->e_id == cpu_to_le32(-1)) {
2332 /* Probably no need to le convert -1 on any arch but can not hurt */
2333 cifs_ace->cifs_uid = cpu_to_le64(-1);
2334 } else
2335 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2336 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2337 return rc;
2340 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2341 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2342 const int acl_type)
2344 __u16 rc = 0;
2345 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2346 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2347 int count;
2348 int i;
2350 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2351 return 0;
2353 count = posix_acl_xattr_count((size_t)buflen);
2354 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2355 count, buflen, le32_to_cpu(local_acl->a_version)));
2356 if(le32_to_cpu(local_acl->a_version) != 2) {
2357 cFYI(1,("unknown POSIX ACL version %d",
2358 le32_to_cpu(local_acl->a_version)));
2359 return 0;
2361 cifs_acl->version = cpu_to_le16(1);
2362 if(acl_type == ACL_TYPE_ACCESS)
2363 cifs_acl->access_entry_count = cpu_to_le16(count);
2364 else if(acl_type == ACL_TYPE_DEFAULT)
2365 cifs_acl->default_entry_count = cpu_to_le16(count);
2366 else {
2367 cFYI(1,("unknown ACL type %d",acl_type));
2368 return 0;
2370 for(i=0;i<count;i++) {
2371 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2372 &local_acl->a_entries[i]);
2373 if(rc != 0) {
2374 /* ACE not converted */
2375 break;
2378 if(rc == 0) {
2379 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2380 rc += sizeof(struct cifs_posix_acl);
2381 /* BB add check to make sure ACL does not overflow SMB */
2383 return rc;
2387 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2388 const unsigned char *searchName,
2389 char *acl_inf, const int buflen, const int acl_type,
2390 const struct nls_table *nls_codepage, int remap)
2392 /* SMB_QUERY_POSIX_ACL */
2393 TRANSACTION2_QPI_REQ *pSMB = NULL;
2394 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2395 int rc = 0;
2396 int bytes_returned;
2397 int name_len;
2398 __u16 params, byte_count;
2400 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2402 queryAclRetry:
2403 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2404 (void **) &pSMBr);
2405 if (rc)
2406 return rc;
2408 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2409 name_len =
2410 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2411 PATH_MAX, nls_codepage, remap);
2412 name_len++; /* trailing null */
2413 name_len *= 2;
2414 pSMB->FileName[name_len] = 0;
2415 pSMB->FileName[name_len+1] = 0;
2416 } else { /* BB improve the check for buffer overruns BB */
2417 name_len = strnlen(searchName, PATH_MAX);
2418 name_len++; /* trailing null */
2419 strncpy(pSMB->FileName, searchName, name_len);
2422 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2423 pSMB->TotalDataCount = 0;
2424 pSMB->MaxParameterCount = cpu_to_le16(2);
2425 /* BB find exact max data count below from sess structure BB */
2426 pSMB->MaxDataCount = cpu_to_le16(4000);
2427 pSMB->MaxSetupCount = 0;
2428 pSMB->Reserved = 0;
2429 pSMB->Flags = 0;
2430 pSMB->Timeout = 0;
2431 pSMB->Reserved2 = 0;
2432 pSMB->ParameterOffset = cpu_to_le16(
2433 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2434 pSMB->DataCount = 0;
2435 pSMB->DataOffset = 0;
2436 pSMB->SetupCount = 1;
2437 pSMB->Reserved3 = 0;
2438 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2439 byte_count = params + 1 /* pad */ ;
2440 pSMB->TotalParameterCount = cpu_to_le16(params);
2441 pSMB->ParameterCount = pSMB->TotalParameterCount;
2442 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2443 pSMB->Reserved4 = 0;
2444 pSMB->hdr.smb_buf_length += byte_count;
2445 pSMB->ByteCount = cpu_to_le16(byte_count);
2447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2449 cifs_stats_inc(&tcon->num_acl_get);
2450 if (rc) {
2451 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2452 } else {
2453 /* decode response */
2455 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2456 if (rc || (pSMBr->ByteCount < 2))
2457 /* BB also check enough total bytes returned */
2458 rc = -EIO; /* bad smb */
2459 else {
2460 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2461 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2462 rc = cifs_copy_posix_acl(acl_inf,
2463 (char *)&pSMBr->hdr.Protocol+data_offset,
2464 buflen,acl_type,count);
2467 cifs_buf_release(pSMB);
2468 if (rc == -EAGAIN)
2469 goto queryAclRetry;
2470 return rc;
2474 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2475 const unsigned char *fileName,
2476 const char *local_acl, const int buflen,
2477 const int acl_type,
2478 const struct nls_table *nls_codepage, int remap)
2480 struct smb_com_transaction2_spi_req *pSMB = NULL;
2481 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2482 char *parm_data;
2483 int name_len;
2484 int rc = 0;
2485 int bytes_returned = 0;
2486 __u16 params, byte_count, data_count, param_offset, offset;
2488 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2489 setAclRetry:
2490 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2491 (void **) &pSMBr);
2492 if (rc)
2493 return rc;
2494 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2495 name_len =
2496 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2497 PATH_MAX, nls_codepage, remap);
2498 name_len++; /* trailing null */
2499 name_len *= 2;
2500 } else { /* BB improve the check for buffer overruns BB */
2501 name_len = strnlen(fileName, PATH_MAX);
2502 name_len++; /* trailing null */
2503 strncpy(pSMB->FileName, fileName, name_len);
2505 params = 6 + name_len;
2506 pSMB->MaxParameterCount = cpu_to_le16(2);
2507 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2508 pSMB->MaxSetupCount = 0;
2509 pSMB->Reserved = 0;
2510 pSMB->Flags = 0;
2511 pSMB->Timeout = 0;
2512 pSMB->Reserved2 = 0;
2513 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2514 InformationLevel) - 4;
2515 offset = param_offset + params;
2516 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2517 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2519 /* convert to on the wire format for POSIX ACL */
2520 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2522 if(data_count == 0) {
2523 rc = -EOPNOTSUPP;
2524 goto setACLerrorExit;
2526 pSMB->DataOffset = cpu_to_le16(offset);
2527 pSMB->SetupCount = 1;
2528 pSMB->Reserved3 = 0;
2529 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2530 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2531 byte_count = 3 /* pad */ + params + data_count;
2532 pSMB->DataCount = cpu_to_le16(data_count);
2533 pSMB->TotalDataCount = pSMB->DataCount;
2534 pSMB->ParameterCount = cpu_to_le16(params);
2535 pSMB->TotalParameterCount = pSMB->ParameterCount;
2536 pSMB->Reserved4 = 0;
2537 pSMB->hdr.smb_buf_length += byte_count;
2538 pSMB->ByteCount = cpu_to_le16(byte_count);
2539 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2540 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2541 if (rc) {
2542 cFYI(1, ("Set POSIX ACL returned %d", rc));
2545 setACLerrorExit:
2546 cifs_buf_release(pSMB);
2547 if (rc == -EAGAIN)
2548 goto setAclRetry;
2549 return rc;
2552 /* BB fix tabs in this function FIXME BB */
2554 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2555 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2557 int rc = 0;
2558 struct smb_t2_qfi_req *pSMB = NULL;
2559 struct smb_t2_qfi_rsp *pSMBr = NULL;
2560 int bytes_returned;
2561 __u16 params, byte_count;
2563 cFYI(1,("In GetExtAttr"));
2564 if(tcon == NULL)
2565 return -ENODEV;
2567 GetExtAttrRetry:
2568 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2569 (void **) &pSMBr);
2570 if (rc)
2571 return rc;
2573 params = 2 /* level */ +2 /* fid */;
2574 pSMB->t2.TotalDataCount = 0;
2575 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2576 /* BB find exact max data count below from sess structure BB */
2577 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2578 pSMB->t2.MaxSetupCount = 0;
2579 pSMB->t2.Reserved = 0;
2580 pSMB->t2.Flags = 0;
2581 pSMB->t2.Timeout = 0;
2582 pSMB->t2.Reserved2 = 0;
2583 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2584 Fid) - 4);
2585 pSMB->t2.DataCount = 0;
2586 pSMB->t2.DataOffset = 0;
2587 pSMB->t2.SetupCount = 1;
2588 pSMB->t2.Reserved3 = 0;
2589 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2590 byte_count = params + 1 /* pad */ ;
2591 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2592 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2593 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2594 pSMB->Pad = 0;
2595 pSMB->Fid = netfid;
2596 pSMB->hdr.smb_buf_length += byte_count;
2597 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2599 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2600 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2601 if (rc) {
2602 cFYI(1, ("error %d in GetExtAttr", rc));
2603 } else {
2604 /* decode response */
2605 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2606 if (rc || (pSMBr->ByteCount < 2))
2607 /* BB also check enough total bytes returned */
2608 /* If rc should we check for EOPNOSUPP and
2609 disable the srvino flag? or in caller? */
2610 rc = -EIO; /* bad smb */
2611 else {
2612 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2613 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2614 struct file_chattr_info * pfinfo;
2615 /* BB Do we need a cast or hash here ? */
2616 if(count != 16) {
2617 cFYI(1, ("Illegal size ret in GetExtAttr"));
2618 rc = -EIO;
2619 goto GetExtAttrOut;
2621 pfinfo = (struct file_chattr_info *)
2622 (data_offset + (char *) &pSMBr->hdr.Protocol);
2623 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2624 *pMask = le64_to_cpu(pfinfo->mask);
2627 GetExtAttrOut:
2628 cifs_buf_release(pSMB);
2629 if (rc == -EAGAIN)
2630 goto GetExtAttrRetry;
2631 return rc;
2635 #endif /* CONFIG_POSIX */
2638 /* security id for everyone */
2639 const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2640 /* group users */
2641 const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2643 /* Convert CIFS ACL to POSIX form */
2644 static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
2646 return 0;
2649 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2651 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2652 /* BB fix up return info */ char *acl_inf, const int buflen,
2653 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2655 int rc = 0;
2656 int buf_type = 0;
2657 QUERY_SEC_DESC_REQ * pSMB;
2658 struct kvec iov[1];
2660 cFYI(1, ("GetCifsACL"));
2662 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2663 8 /* parm len */, tcon, (void **) &pSMB);
2664 if (rc)
2665 return rc;
2667 pSMB->MaxParameterCount = cpu_to_le32(4);
2668 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2669 pSMB->MaxSetupCount = 0;
2670 pSMB->Fid = fid; /* file handle always le */
2671 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2672 CIFS_ACL_DACL);
2673 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2674 pSMB->hdr.smb_buf_length += 11;
2675 iov[0].iov_base = (char *)pSMB;
2676 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2678 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2679 cifs_stats_inc(&tcon->num_acl_get);
2680 if (rc) {
2681 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2682 } else { /* decode response */
2683 struct cifs_sid * psec_desc;
2684 __le32 * parm;
2685 int parm_len;
2686 int data_len;
2687 int acl_len;
2688 struct smb_com_ntransact_rsp * pSMBr;
2690 /* validate_nttransact */
2691 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2692 (char **)&psec_desc,
2693 &parm_len, &data_len);
2695 if(rc)
2696 goto qsec_out;
2697 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2699 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2701 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2702 rc = -EIO; /* bad smb */
2703 goto qsec_out;
2706 /* BB check that data area is minimum length and as big as acl_len */
2708 acl_len = le32_to_cpu(*(__le32 *)parm);
2709 /* BB check if(acl_len > bufsize) */
2711 parse_sec_desc(psec_desc, acl_len);
2713 qsec_out:
2714 if(buf_type == CIFS_SMALL_BUFFER)
2715 cifs_small_buf_release(iov[0].iov_base);
2716 else if(buf_type == CIFS_LARGE_BUFFER)
2717 cifs_buf_release(iov[0].iov_base);
2718 /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
2719 return rc;
2723 /* Legacy Query Path Information call for lookup to old servers such
2724 as Win9x/WinME */
2725 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2726 const unsigned char *searchName,
2727 FILE_ALL_INFO * pFinfo,
2728 const struct nls_table *nls_codepage, int remap)
2730 QUERY_INFORMATION_REQ * pSMB;
2731 QUERY_INFORMATION_RSP * pSMBr;
2732 int rc = 0;
2733 int bytes_returned;
2734 int name_len;
2736 cFYI(1, ("In SMBQPath path %s", searchName));
2737 QInfRetry:
2738 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2739 (void **) &pSMBr);
2740 if (rc)
2741 return rc;
2743 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2744 name_len =
2745 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2746 PATH_MAX, nls_codepage, remap);
2747 name_len++; /* trailing null */
2748 name_len *= 2;
2749 } else {
2750 name_len = strnlen(searchName, PATH_MAX);
2751 name_len++; /* trailing null */
2752 strncpy(pSMB->FileName, searchName, name_len);
2754 pSMB->BufferFormat = 0x04;
2755 name_len++; /* account for buffer type byte */
2756 pSMB->hdr.smb_buf_length += (__u16) name_len;
2757 pSMB->ByteCount = cpu_to_le16(name_len);
2759 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2761 if (rc) {
2762 cFYI(1, ("Send error in QueryInfo = %d", rc));
2763 } else if (pFinfo) { /* decode response */
2764 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2765 pFinfo->AllocationSize =
2766 cpu_to_le64(le32_to_cpu(pSMBr->size));
2767 pFinfo->EndOfFile = pFinfo->AllocationSize;
2768 pFinfo->Attributes =
2769 cpu_to_le32(le16_to_cpu(pSMBr->attr));
2770 } else
2771 rc = -EIO; /* bad buffer passed in */
2773 cifs_buf_release(pSMB);
2775 if (rc == -EAGAIN)
2776 goto QInfRetry;
2778 return rc;
2785 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2786 const unsigned char *searchName,
2787 FILE_ALL_INFO * pFindData,
2788 const struct nls_table *nls_codepage, int remap)
2790 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2791 TRANSACTION2_QPI_REQ *pSMB = NULL;
2792 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2793 int rc = 0;
2794 int bytes_returned;
2795 int name_len;
2796 __u16 params, byte_count;
2798 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2799 QPathInfoRetry:
2800 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2801 (void **) &pSMBr);
2802 if (rc)
2803 return rc;
2805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2806 name_len =
2807 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2808 PATH_MAX, nls_codepage, remap);
2809 name_len++; /* trailing null */
2810 name_len *= 2;
2811 } else { /* BB improve the check for buffer overruns BB */
2812 name_len = strnlen(searchName, PATH_MAX);
2813 name_len++; /* trailing null */
2814 strncpy(pSMB->FileName, searchName, name_len);
2817 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2818 pSMB->TotalDataCount = 0;
2819 pSMB->MaxParameterCount = cpu_to_le16(2);
2820 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2821 pSMB->MaxSetupCount = 0;
2822 pSMB->Reserved = 0;
2823 pSMB->Flags = 0;
2824 pSMB->Timeout = 0;
2825 pSMB->Reserved2 = 0;
2826 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2827 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2828 pSMB->DataCount = 0;
2829 pSMB->DataOffset = 0;
2830 pSMB->SetupCount = 1;
2831 pSMB->Reserved3 = 0;
2832 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2833 byte_count = params + 1 /* pad */ ;
2834 pSMB->TotalParameterCount = cpu_to_le16(params);
2835 pSMB->ParameterCount = pSMB->TotalParameterCount;
2836 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2837 pSMB->Reserved4 = 0;
2838 pSMB->hdr.smb_buf_length += byte_count;
2839 pSMB->ByteCount = cpu_to_le16(byte_count);
2841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2842 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2843 if (rc) {
2844 cFYI(1, ("Send error in QPathInfo = %d", rc));
2845 } else { /* decode response */
2846 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2848 if (rc || (pSMBr->ByteCount < 40))
2849 rc = -EIO; /* bad smb */
2850 else if (pFindData){
2851 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2852 memcpy((char *) pFindData,
2853 (char *) &pSMBr->hdr.Protocol +
2854 data_offset, sizeof (FILE_ALL_INFO));
2855 } else
2856 rc = -ENOMEM;
2858 cifs_buf_release(pSMB);
2859 if (rc == -EAGAIN)
2860 goto QPathInfoRetry;
2862 return rc;
2866 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2867 const unsigned char *searchName,
2868 FILE_UNIX_BASIC_INFO * pFindData,
2869 const struct nls_table *nls_codepage, int remap)
2871 /* SMB_QUERY_FILE_UNIX_BASIC */
2872 TRANSACTION2_QPI_REQ *pSMB = NULL;
2873 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2874 int rc = 0;
2875 int bytes_returned = 0;
2876 int name_len;
2877 __u16 params, byte_count;
2879 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2880 UnixQPathInfoRetry:
2881 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2882 (void **) &pSMBr);
2883 if (rc)
2884 return rc;
2886 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2887 name_len =
2888 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2889 PATH_MAX, nls_codepage, remap);
2890 name_len++; /* trailing null */
2891 name_len *= 2;
2892 } else { /* BB improve the check for buffer overruns BB */
2893 name_len = strnlen(searchName, PATH_MAX);
2894 name_len++; /* trailing null */
2895 strncpy(pSMB->FileName, searchName, name_len);
2898 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2899 pSMB->TotalDataCount = 0;
2900 pSMB->MaxParameterCount = cpu_to_le16(2);
2901 /* BB find exact max SMB PDU from sess structure BB */
2902 pSMB->MaxDataCount = cpu_to_le16(4000);
2903 pSMB->MaxSetupCount = 0;
2904 pSMB->Reserved = 0;
2905 pSMB->Flags = 0;
2906 pSMB->Timeout = 0;
2907 pSMB->Reserved2 = 0;
2908 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2909 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2910 pSMB->DataCount = 0;
2911 pSMB->DataOffset = 0;
2912 pSMB->SetupCount = 1;
2913 pSMB->Reserved3 = 0;
2914 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2915 byte_count = params + 1 /* pad */ ;
2916 pSMB->TotalParameterCount = cpu_to_le16(params);
2917 pSMB->ParameterCount = pSMB->TotalParameterCount;
2918 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2919 pSMB->Reserved4 = 0;
2920 pSMB->hdr.smb_buf_length += byte_count;
2921 pSMB->ByteCount = cpu_to_le16(byte_count);
2923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2925 if (rc) {
2926 cFYI(1, ("Send error in QPathInfo = %d", rc));
2927 } else { /* decode response */
2928 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2930 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2931 rc = -EIO; /* bad smb */
2932 } else {
2933 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2934 memcpy((char *) pFindData,
2935 (char *) &pSMBr->hdr.Protocol +
2936 data_offset,
2937 sizeof (FILE_UNIX_BASIC_INFO));
2940 cifs_buf_release(pSMB);
2941 if (rc == -EAGAIN)
2942 goto UnixQPathInfoRetry;
2944 return rc;
2947 #if 0 /* function unused at present */
2948 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2949 const char *searchName, FILE_ALL_INFO * findData,
2950 const struct nls_table *nls_codepage)
2952 /* level 257 SMB_ */
2953 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2954 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2955 int rc = 0;
2956 int bytes_returned;
2957 int name_len;
2958 __u16 params, byte_count;
2960 cFYI(1, ("In FindUnique"));
2961 findUniqueRetry:
2962 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2963 (void **) &pSMBr);
2964 if (rc)
2965 return rc;
2967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2968 name_len =
2969 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2970 /* find define for this maxpathcomponent */
2971 , nls_codepage);
2972 name_len++; /* trailing null */
2973 name_len *= 2;
2974 } else { /* BB improve the check for buffer overruns BB */
2975 name_len = strnlen(searchName, PATH_MAX);
2976 name_len++; /* trailing null */
2977 strncpy(pSMB->FileName, searchName, name_len);
2980 params = 12 + name_len /* includes null */ ;
2981 pSMB->TotalDataCount = 0; /* no EAs */
2982 pSMB->MaxParameterCount = cpu_to_le16(2);
2983 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2984 pSMB->MaxSetupCount = 0;
2985 pSMB->Reserved = 0;
2986 pSMB->Flags = 0;
2987 pSMB->Timeout = 0;
2988 pSMB->Reserved2 = 0;
2989 pSMB->ParameterOffset = cpu_to_le16(
2990 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2991 pSMB->DataCount = 0;
2992 pSMB->DataOffset = 0;
2993 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2994 pSMB->Reserved3 = 0;
2995 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2996 byte_count = params + 1 /* pad */ ;
2997 pSMB->TotalParameterCount = cpu_to_le16(params);
2998 pSMB->ParameterCount = pSMB->TotalParameterCount;
2999 pSMB->SearchAttributes =
3000 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3001 ATTR_DIRECTORY);
3002 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3003 pSMB->SearchFlags = cpu_to_le16(1);
3004 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3005 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3006 pSMB->hdr.smb_buf_length += byte_count;
3007 pSMB->ByteCount = cpu_to_le16(byte_count);
3009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3012 if (rc) {
3013 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3014 } else { /* decode response */
3015 cifs_stats_inc(&tcon->num_ffirst);
3016 /* BB fill in */
3019 cifs_buf_release(pSMB);
3020 if (rc == -EAGAIN)
3021 goto findUniqueRetry;
3023 return rc;
3025 #endif /* end unused (temporarily) function */
3027 /* xid, tcon, searchName and codepage are input parms, rest are returned */
3029 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3030 const char *searchName,
3031 const struct nls_table *nls_codepage,
3032 __u16 * pnetfid,
3033 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
3035 /* level 257 SMB_ */
3036 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3037 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3038 T2_FFIRST_RSP_PARMS * parms;
3039 int rc = 0;
3040 int bytes_returned = 0;
3041 int name_len;
3042 __u16 params, byte_count;
3044 cFYI(1, ("In FindFirst for %s",searchName));
3046 findFirstRetry:
3047 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3048 (void **) &pSMBr);
3049 if (rc)
3050 return rc;
3052 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3053 name_len =
3054 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
3055 PATH_MAX, nls_codepage, remap);
3056 /* We can not add the asterik earlier in case
3057 it got remapped to 0xF03A as if it were part of the
3058 directory name instead of a wildcard */
3059 name_len *= 2;
3060 pSMB->FileName[name_len] = dirsep;
3061 pSMB->FileName[name_len+1] = 0;
3062 pSMB->FileName[name_len+2] = '*';
3063 pSMB->FileName[name_len+3] = 0;
3064 name_len += 4; /* now the trailing null */
3065 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3066 pSMB->FileName[name_len+1] = 0;
3067 name_len += 2;
3068 } else { /* BB add check for overrun of SMB buf BB */
3069 name_len = strnlen(searchName, PATH_MAX);
3070 /* BB fix here and in unicode clause above ie
3071 if(name_len > buffersize-header)
3072 free buffer exit; BB */
3073 strncpy(pSMB->FileName, searchName, name_len);
3074 pSMB->FileName[name_len] = dirsep;
3075 pSMB->FileName[name_len+1] = '*';
3076 pSMB->FileName[name_len+2] = 0;
3077 name_len += 3;
3080 params = 12 + name_len /* includes null */ ;
3081 pSMB->TotalDataCount = 0; /* no EAs */
3082 pSMB->MaxParameterCount = cpu_to_le16(10);
3083 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3084 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3085 pSMB->MaxSetupCount = 0;
3086 pSMB->Reserved = 0;
3087 pSMB->Flags = 0;
3088 pSMB->Timeout = 0;
3089 pSMB->Reserved2 = 0;
3090 byte_count = params + 1 /* pad */ ;
3091 pSMB->TotalParameterCount = cpu_to_le16(params);
3092 pSMB->ParameterCount = pSMB->TotalParameterCount;
3093 pSMB->ParameterOffset = cpu_to_le16(
3094 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3095 - 4);
3096 pSMB->DataCount = 0;
3097 pSMB->DataOffset = 0;
3098 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3099 pSMB->Reserved3 = 0;
3100 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3101 pSMB->SearchAttributes =
3102 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3103 ATTR_DIRECTORY);
3104 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3105 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3106 CIFS_SEARCH_RETURN_RESUME);
3107 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3109 /* BB what should we set StorageType to? Does it matter? BB */
3110 pSMB->SearchStorageType = 0;
3111 pSMB->hdr.smb_buf_length += byte_count;
3112 pSMB->ByteCount = cpu_to_le16(byte_count);
3114 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3115 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3116 cifs_stats_inc(&tcon->num_ffirst);
3118 if (rc) {/* BB add logic to retry regular search if Unix search
3119 rejected unexpectedly by server */
3120 /* BB Add code to handle unsupported level rc */
3121 cFYI(1, ("Error in FindFirst = %d", rc));
3123 cifs_buf_release(pSMB);
3125 /* BB eventually could optimize out free and realloc of buf */
3126 /* for this case */
3127 if (rc == -EAGAIN)
3128 goto findFirstRetry;
3129 } else { /* decode response */
3130 /* BB remember to free buffer if error BB */
3131 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3132 if(rc == 0) {
3133 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3134 psrch_inf->unicode = TRUE;
3135 else
3136 psrch_inf->unicode = FALSE;
3138 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3139 psrch_inf->smallBuf = 0;
3140 psrch_inf->srch_entries_start =
3141 (char *) &pSMBr->hdr.Protocol +
3142 le16_to_cpu(pSMBr->t2.DataOffset);
3143 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3144 le16_to_cpu(pSMBr->t2.ParameterOffset));
3146 if(parms->EndofSearch)
3147 psrch_inf->endOfSearch = TRUE;
3148 else
3149 psrch_inf->endOfSearch = FALSE;
3151 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3152 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3153 psrch_inf->entries_in_buffer;
3154 *pnetfid = parms->SearchHandle;
3155 } else {
3156 cifs_buf_release(pSMB);
3160 return rc;
3163 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3164 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3166 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3167 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3168 T2_FNEXT_RSP_PARMS * parms;
3169 char *response_data;
3170 int rc = 0;
3171 int bytes_returned, name_len;
3172 __u16 params, byte_count;
3174 cFYI(1, ("In FindNext"));
3176 if(psrch_inf->endOfSearch == TRUE)
3177 return -ENOENT;
3179 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3180 (void **) &pSMBr);
3181 if (rc)
3182 return rc;
3184 params = 14; /* includes 2 bytes of null string, converted to LE below */
3185 byte_count = 0;
3186 pSMB->TotalDataCount = 0; /* no EAs */
3187 pSMB->MaxParameterCount = cpu_to_le16(8);
3188 pSMB->MaxDataCount =
3189 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3190 pSMB->MaxSetupCount = 0;
3191 pSMB->Reserved = 0;
3192 pSMB->Flags = 0;
3193 pSMB->Timeout = 0;
3194 pSMB->Reserved2 = 0;
3195 pSMB->ParameterOffset = cpu_to_le16(
3196 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3197 pSMB->DataCount = 0;
3198 pSMB->DataOffset = 0;
3199 pSMB->SetupCount = 1;
3200 pSMB->Reserved3 = 0;
3201 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3202 pSMB->SearchHandle = searchHandle; /* always kept as le */
3203 pSMB->SearchCount =
3204 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3205 /* test for Unix extensions */
3206 /* if (tcon->ses->capabilities & CAP_UNIX) {
3207 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3208 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3209 } else {
3210 pSMB->InformationLevel =
3211 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3212 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3213 } */
3214 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3215 pSMB->ResumeKey = psrch_inf->resume_key;
3216 pSMB->SearchFlags =
3217 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3219 name_len = psrch_inf->resume_name_len;
3220 params += name_len;
3221 if(name_len < PATH_MAX) {
3222 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3223 byte_count += name_len;
3224 /* 14 byte parm len above enough for 2 byte null terminator */
3225 pSMB->ResumeFileName[name_len] = 0;
3226 pSMB->ResumeFileName[name_len+1] = 0;
3227 } else {
3228 rc = -EINVAL;
3229 goto FNext2_err_exit;
3231 byte_count = params + 1 /* pad */ ;
3232 pSMB->TotalParameterCount = cpu_to_le16(params);
3233 pSMB->ParameterCount = pSMB->TotalParameterCount;
3234 pSMB->hdr.smb_buf_length += byte_count;
3235 pSMB->ByteCount = cpu_to_le16(byte_count);
3237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3238 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3239 cifs_stats_inc(&tcon->num_fnext);
3240 if (rc) {
3241 if (rc == -EBADF) {
3242 psrch_inf->endOfSearch = TRUE;
3243 rc = 0; /* search probably was closed at end of search above */
3244 } else
3245 cFYI(1, ("FindNext returned = %d", rc));
3246 } else { /* decode response */
3247 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3249 if(rc == 0) {
3250 /* BB fixme add lock for file (srch_info) struct here */
3251 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3252 psrch_inf->unicode = TRUE;
3253 else
3254 psrch_inf->unicode = FALSE;
3255 response_data = (char *) &pSMBr->hdr.Protocol +
3256 le16_to_cpu(pSMBr->t2.ParameterOffset);
3257 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3258 response_data = (char *)&pSMBr->hdr.Protocol +
3259 le16_to_cpu(pSMBr->t2.DataOffset);
3260 if(psrch_inf->smallBuf)
3261 cifs_small_buf_release(
3262 psrch_inf->ntwrk_buf_start);
3263 else
3264 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3265 psrch_inf->srch_entries_start = response_data;
3266 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3267 psrch_inf->smallBuf = 0;
3268 if(parms->EndofSearch)
3269 psrch_inf->endOfSearch = TRUE;
3270 else
3271 psrch_inf->endOfSearch = FALSE;
3273 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3274 psrch_inf->index_of_last_entry +=
3275 psrch_inf->entries_in_buffer;
3276 /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3278 /* BB fixme add unlock here */
3283 /* BB On error, should we leave previous search buf (and count and
3284 last entry fields) intact or free the previous one? */
3286 /* Note: On -EAGAIN error only caller can retry on handle based calls
3287 since file handle passed in no longer valid */
3288 FNext2_err_exit:
3289 if (rc != 0)
3290 cifs_buf_release(pSMB);
3292 return rc;
3296 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3298 int rc = 0;
3299 FINDCLOSE_REQ *pSMB = NULL;
3300 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3301 int bytes_returned;
3303 cFYI(1, ("In CIFSSMBFindClose"));
3304 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3306 /* no sense returning error if session restarted
3307 as file handle has been closed */
3308 if(rc == -EAGAIN)
3309 return 0;
3310 if (rc)
3311 return rc;
3313 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3314 pSMB->FileID = searchHandle;
3315 pSMB->ByteCount = 0;
3316 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3317 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3318 if (rc) {
3319 cERROR(1, ("Send error in FindClose = %d", rc));
3321 cifs_stats_inc(&tcon->num_fclose);
3322 cifs_small_buf_release(pSMB);
3324 /* Since session is dead, search handle closed on server already */
3325 if (rc == -EAGAIN)
3326 rc = 0;
3328 return rc;
3332 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3333 const unsigned char *searchName,
3334 __u64 * inode_number,
3335 const struct nls_table *nls_codepage, int remap)
3337 int rc = 0;
3338 TRANSACTION2_QPI_REQ *pSMB = NULL;
3339 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3340 int name_len, bytes_returned;
3341 __u16 params, byte_count;
3343 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3344 if(tcon == NULL)
3345 return -ENODEV;
3347 GetInodeNumberRetry:
3348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3349 (void **) &pSMBr);
3350 if (rc)
3351 return rc;
3354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3355 name_len =
3356 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3357 PATH_MAX,nls_codepage, remap);
3358 name_len++; /* trailing null */
3359 name_len *= 2;
3360 } else { /* BB improve the check for buffer overruns BB */
3361 name_len = strnlen(searchName, PATH_MAX);
3362 name_len++; /* trailing null */
3363 strncpy(pSMB->FileName, searchName, name_len);
3366 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3367 pSMB->TotalDataCount = 0;
3368 pSMB->MaxParameterCount = cpu_to_le16(2);
3369 /* BB find exact max data count below from sess structure BB */
3370 pSMB->MaxDataCount = cpu_to_le16(4000);
3371 pSMB->MaxSetupCount = 0;
3372 pSMB->Reserved = 0;
3373 pSMB->Flags = 0;
3374 pSMB->Timeout = 0;
3375 pSMB->Reserved2 = 0;
3376 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3377 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3378 pSMB->DataCount = 0;
3379 pSMB->DataOffset = 0;
3380 pSMB->SetupCount = 1;
3381 pSMB->Reserved3 = 0;
3382 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3383 byte_count = params + 1 /* pad */ ;
3384 pSMB->TotalParameterCount = cpu_to_le16(params);
3385 pSMB->ParameterCount = pSMB->TotalParameterCount;
3386 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3387 pSMB->Reserved4 = 0;
3388 pSMB->hdr.smb_buf_length += byte_count;
3389 pSMB->ByteCount = cpu_to_le16(byte_count);
3391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3392 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3393 if (rc) {
3394 cFYI(1, ("error %d in QueryInternalInfo", rc));
3395 } else {
3396 /* decode response */
3397 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3398 if (rc || (pSMBr->ByteCount < 2))
3399 /* BB also check enough total bytes returned */
3400 /* If rc should we check for EOPNOSUPP and
3401 disable the srvino flag? or in caller? */
3402 rc = -EIO; /* bad smb */
3403 else {
3404 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3405 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3406 struct file_internal_info * pfinfo;
3407 /* BB Do we need a cast or hash here ? */
3408 if(count < 8) {
3409 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3410 rc = -EIO;
3411 goto GetInodeNumOut;
3413 pfinfo = (struct file_internal_info *)
3414 (data_offset + (char *) &pSMBr->hdr.Protocol);
3415 *inode_number = pfinfo->UniqueId;
3418 GetInodeNumOut:
3419 cifs_buf_release(pSMB);
3420 if (rc == -EAGAIN)
3421 goto GetInodeNumberRetry;
3422 return rc;
3426 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3427 const unsigned char *searchName,
3428 unsigned char **targetUNCs,
3429 unsigned int *number_of_UNC_in_array,
3430 const struct nls_table *nls_codepage, int remap)
3432 /* TRANS2_GET_DFS_REFERRAL */
3433 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3434 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3435 struct dfs_referral_level_3 * referrals = NULL;
3436 int rc = 0;
3437 int bytes_returned;
3438 int name_len;
3439 unsigned int i;
3440 char * temp;
3441 __u16 params, byte_count;
3442 *number_of_UNC_in_array = 0;
3443 *targetUNCs = NULL;
3445 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3446 if (ses == NULL)
3447 return -ENODEV;
3448 getDFSRetry:
3449 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3450 (void **) &pSMBr);
3451 if (rc)
3452 return rc;
3454 /* server pointer checked in called function,
3455 but should never be null here anyway */
3456 pSMB->hdr.Mid = GetNextMid(ses->server);
3457 pSMB->hdr.Tid = ses->ipc_tid;
3458 pSMB->hdr.Uid = ses->Suid;
3459 if (ses->capabilities & CAP_STATUS32) {
3460 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3462 if (ses->capabilities & CAP_DFS) {
3463 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3466 if (ses->capabilities & CAP_UNICODE) {
3467 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3468 name_len =
3469 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3470 searchName, PATH_MAX, nls_codepage, remap);
3471 name_len++; /* trailing null */
3472 name_len *= 2;
3473 } else { /* BB improve the check for buffer overruns BB */
3474 name_len = strnlen(searchName, PATH_MAX);
3475 name_len++; /* trailing null */
3476 strncpy(pSMB->RequestFileName, searchName, name_len);
3479 params = 2 /* level */ + name_len /*includes null */ ;
3480 pSMB->TotalDataCount = 0;
3481 pSMB->DataCount = 0;
3482 pSMB->DataOffset = 0;
3483 pSMB->MaxParameterCount = 0;
3484 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3485 pSMB->MaxSetupCount = 0;
3486 pSMB->Reserved = 0;
3487 pSMB->Flags = 0;
3488 pSMB->Timeout = 0;
3489 pSMB->Reserved2 = 0;
3490 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3491 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3492 pSMB->SetupCount = 1;
3493 pSMB->Reserved3 = 0;
3494 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3495 byte_count = params + 3 /* pad */ ;
3496 pSMB->ParameterCount = cpu_to_le16(params);
3497 pSMB->TotalParameterCount = pSMB->ParameterCount;
3498 pSMB->MaxReferralLevel = cpu_to_le16(3);
3499 pSMB->hdr.smb_buf_length += byte_count;
3500 pSMB->ByteCount = cpu_to_le16(byte_count);
3502 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3504 if (rc) {
3505 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3506 } else { /* decode response */
3507 /* BB Add logic to parse referrals here */
3508 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3510 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3511 rc = -EIO; /* bad smb */
3512 else {
3513 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3514 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3516 cFYI(1,
3517 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3518 pSMBr->ByteCount, data_offset));
3519 referrals =
3520 (struct dfs_referral_level_3 *)
3521 (8 /* sizeof start of data block */ +
3522 data_offset +
3523 (char *) &pSMBr->hdr.Protocol);
3524 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",
3525 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)));
3526 /* BB This field is actually two bytes in from start of
3527 data block so we could do safety check that DataBlock
3528 begins at address of pSMBr->NumberOfReferrals */
3529 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3531 /* BB Fix below so can return more than one referral */
3532 if(*number_of_UNC_in_array > 1)
3533 *number_of_UNC_in_array = 1;
3535 /* get the length of the strings describing refs */
3536 name_len = 0;
3537 for(i=0;i<*number_of_UNC_in_array;i++) {
3538 /* make sure that DfsPathOffset not past end */
3539 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3540 if (offset > data_count) {
3541 /* if invalid referral, stop here and do
3542 not try to copy any more */
3543 *number_of_UNC_in_array = i;
3544 break;
3546 temp = ((char *)referrals) + offset;
3548 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3549 name_len += UniStrnlen((wchar_t *)temp,data_count);
3550 } else {
3551 name_len += strnlen(temp,data_count);
3553 referrals++;
3554 /* BB add check that referral pointer does not fall off end PDU */
3557 /* BB add check for name_len bigger than bcc */
3558 *targetUNCs =
3559 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3560 if(*targetUNCs == NULL) {
3561 rc = -ENOMEM;
3562 goto GetDFSRefExit;
3564 /* copy the ref strings */
3565 referrals =
3566 (struct dfs_referral_level_3 *)
3567 (8 /* sizeof data hdr */ +
3568 data_offset +
3569 (char *) &pSMBr->hdr.Protocol);
3571 for(i=0;i<*number_of_UNC_in_array;i++) {
3572 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3573 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3574 cifs_strfromUCS_le(*targetUNCs,
3575 (__le16 *) temp, name_len, nls_codepage);
3576 } else {
3577 strncpy(*targetUNCs,temp,name_len);
3579 /* BB update target_uncs pointers */
3580 referrals++;
3582 temp = *targetUNCs;
3583 temp[name_len] = 0;
3587 GetDFSRefExit:
3588 if (pSMB)
3589 cifs_buf_release(pSMB);
3591 if (rc == -EAGAIN)
3592 goto getDFSRetry;
3594 return rc;
3597 /* Query File System Info such as free space to old servers such as Win 9x */
3599 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3601 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3602 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3603 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3604 FILE_SYSTEM_ALLOC_INFO *response_data;
3605 int rc = 0;
3606 int bytes_returned = 0;
3607 __u16 params, byte_count;
3609 cFYI(1, ("OldQFSInfo"));
3610 oldQFSInfoRetry:
3611 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3612 (void **) &pSMBr);
3613 if (rc)
3614 return rc;
3615 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3616 (void **) &pSMBr);
3617 if (rc)
3618 return rc;
3620 params = 2; /* level */
3621 pSMB->TotalDataCount = 0;
3622 pSMB->MaxParameterCount = cpu_to_le16(2);
3623 pSMB->MaxDataCount = cpu_to_le16(1000);
3624 pSMB->MaxSetupCount = 0;
3625 pSMB->Reserved = 0;
3626 pSMB->Flags = 0;
3627 pSMB->Timeout = 0;
3628 pSMB->Reserved2 = 0;
3629 byte_count = params + 1 /* pad */ ;
3630 pSMB->TotalParameterCount = cpu_to_le16(params);
3631 pSMB->ParameterCount = pSMB->TotalParameterCount;
3632 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3633 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3634 pSMB->DataCount = 0;
3635 pSMB->DataOffset = 0;
3636 pSMB->SetupCount = 1;
3637 pSMB->Reserved3 = 0;
3638 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3639 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3640 pSMB->hdr.smb_buf_length += byte_count;
3641 pSMB->ByteCount = cpu_to_le16(byte_count);
3643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3645 if (rc) {
3646 cFYI(1, ("Send error in QFSInfo = %d", rc));
3647 } else { /* decode response */
3648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3650 if (rc || (pSMBr->ByteCount < 18))
3651 rc = -EIO; /* bad smb */
3652 else {
3653 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3654 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3655 pSMBr->ByteCount, data_offset));
3657 response_data =
3658 (FILE_SYSTEM_ALLOC_INFO *)
3659 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3660 FSData->f_bsize =
3661 le16_to_cpu(response_data->BytesPerSector) *
3662 le32_to_cpu(response_data->
3663 SectorsPerAllocationUnit);
3664 FSData->f_blocks =
3665 le32_to_cpu(response_data->TotalAllocationUnits);
3666 FSData->f_bfree = FSData->f_bavail =
3667 le32_to_cpu(response_data->FreeAllocationUnits);
3668 cFYI(1,
3669 ("Blocks: %lld Free: %lld Block size %ld",
3670 (unsigned long long)FSData->f_blocks,
3671 (unsigned long long)FSData->f_bfree,
3672 FSData->f_bsize));
3675 cifs_buf_release(pSMB);
3677 if (rc == -EAGAIN)
3678 goto oldQFSInfoRetry;
3680 return rc;
3684 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3686 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3687 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3688 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3689 FILE_SYSTEM_INFO *response_data;
3690 int rc = 0;
3691 int bytes_returned = 0;
3692 __u16 params, byte_count;
3694 cFYI(1, ("In QFSInfo"));
3695 QFSInfoRetry:
3696 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3697 (void **) &pSMBr);
3698 if (rc)
3699 return rc;
3701 params = 2; /* level */
3702 pSMB->TotalDataCount = 0;
3703 pSMB->MaxParameterCount = cpu_to_le16(2);
3704 pSMB->MaxDataCount = cpu_to_le16(1000);
3705 pSMB->MaxSetupCount = 0;
3706 pSMB->Reserved = 0;
3707 pSMB->Flags = 0;
3708 pSMB->Timeout = 0;
3709 pSMB->Reserved2 = 0;
3710 byte_count = params + 1 /* pad */ ;
3711 pSMB->TotalParameterCount = cpu_to_le16(params);
3712 pSMB->ParameterCount = pSMB->TotalParameterCount;
3713 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3714 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3715 pSMB->DataCount = 0;
3716 pSMB->DataOffset = 0;
3717 pSMB->SetupCount = 1;
3718 pSMB->Reserved3 = 0;
3719 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3720 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3721 pSMB->hdr.smb_buf_length += byte_count;
3722 pSMB->ByteCount = cpu_to_le16(byte_count);
3724 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3725 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3726 if (rc) {
3727 cFYI(1, ("Send error in QFSInfo = %d", rc));
3728 } else { /* decode response */
3729 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3731 if (rc || (pSMBr->ByteCount < 24))
3732 rc = -EIO; /* bad smb */
3733 else {
3734 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3736 response_data =
3737 (FILE_SYSTEM_INFO
3738 *) (((char *) &pSMBr->hdr.Protocol) +
3739 data_offset);
3740 FSData->f_bsize =
3741 le32_to_cpu(response_data->BytesPerSector) *
3742 le32_to_cpu(response_data->
3743 SectorsPerAllocationUnit);
3744 FSData->f_blocks =
3745 le64_to_cpu(response_data->TotalAllocationUnits);
3746 FSData->f_bfree = FSData->f_bavail =
3747 le64_to_cpu(response_data->FreeAllocationUnits);
3748 cFYI(1,
3749 ("Blocks: %lld Free: %lld Block size %ld",
3750 (unsigned long long)FSData->f_blocks,
3751 (unsigned long long)FSData->f_bfree,
3752 FSData->f_bsize));
3755 cifs_buf_release(pSMB);
3757 if (rc == -EAGAIN)
3758 goto QFSInfoRetry;
3760 return rc;
3764 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3766 /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3767 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3768 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3769 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3770 int rc = 0;
3771 int bytes_returned = 0;
3772 __u16 params, byte_count;
3774 cFYI(1, ("In QFSAttributeInfo"));
3775 QFSAttributeRetry:
3776 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3777 (void **) &pSMBr);
3778 if (rc)
3779 return rc;
3781 params = 2; /* level */
3782 pSMB->TotalDataCount = 0;
3783 pSMB->MaxParameterCount = cpu_to_le16(2);
3784 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3785 pSMB->MaxSetupCount = 0;
3786 pSMB->Reserved = 0;
3787 pSMB->Flags = 0;
3788 pSMB->Timeout = 0;
3789 pSMB->Reserved2 = 0;
3790 byte_count = params + 1 /* pad */ ;
3791 pSMB->TotalParameterCount = cpu_to_le16(params);
3792 pSMB->ParameterCount = pSMB->TotalParameterCount;
3793 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3794 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3795 pSMB->DataCount = 0;
3796 pSMB->DataOffset = 0;
3797 pSMB->SetupCount = 1;
3798 pSMB->Reserved3 = 0;
3799 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3800 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3801 pSMB->hdr.smb_buf_length += byte_count;
3802 pSMB->ByteCount = cpu_to_le16(byte_count);
3804 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3805 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3806 if (rc) {
3807 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3808 } else { /* decode response */
3809 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3811 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3812 rc = -EIO; /* bad smb */
3813 } else {
3814 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3815 response_data =
3816 (FILE_SYSTEM_ATTRIBUTE_INFO
3817 *) (((char *) &pSMBr->hdr.Protocol) +
3818 data_offset);
3819 memcpy(&tcon->fsAttrInfo, response_data,
3820 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3823 cifs_buf_release(pSMB);
3825 if (rc == -EAGAIN)
3826 goto QFSAttributeRetry;
3828 return rc;
3832 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3834 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3835 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3836 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3837 FILE_SYSTEM_DEVICE_INFO *response_data;
3838 int rc = 0;
3839 int bytes_returned = 0;
3840 __u16 params, byte_count;
3842 cFYI(1, ("In QFSDeviceInfo"));
3843 QFSDeviceRetry:
3844 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3845 (void **) &pSMBr);
3846 if (rc)
3847 return rc;
3849 params = 2; /* level */
3850 pSMB->TotalDataCount = 0;
3851 pSMB->MaxParameterCount = cpu_to_le16(2);
3852 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3853 pSMB->MaxSetupCount = 0;
3854 pSMB->Reserved = 0;
3855 pSMB->Flags = 0;
3856 pSMB->Timeout = 0;
3857 pSMB->Reserved2 = 0;
3858 byte_count = params + 1 /* pad */ ;
3859 pSMB->TotalParameterCount = cpu_to_le16(params);
3860 pSMB->ParameterCount = pSMB->TotalParameterCount;
3861 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3862 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3864 pSMB->DataCount = 0;
3865 pSMB->DataOffset = 0;
3866 pSMB->SetupCount = 1;
3867 pSMB->Reserved3 = 0;
3868 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3869 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3870 pSMB->hdr.smb_buf_length += byte_count;
3871 pSMB->ByteCount = cpu_to_le16(byte_count);
3873 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3874 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3875 if (rc) {
3876 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3877 } else { /* decode response */
3878 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3880 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3881 rc = -EIO; /* bad smb */
3882 else {
3883 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3884 response_data =
3885 (FILE_SYSTEM_DEVICE_INFO *)
3886 (((char *) &pSMBr->hdr.Protocol) +
3887 data_offset);
3888 memcpy(&tcon->fsDevInfo, response_data,
3889 sizeof (FILE_SYSTEM_DEVICE_INFO));
3892 cifs_buf_release(pSMB);
3894 if (rc == -EAGAIN)
3895 goto QFSDeviceRetry;
3897 return rc;
3901 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3903 /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3904 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3905 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3906 FILE_SYSTEM_UNIX_INFO *response_data;
3907 int rc = 0;
3908 int bytes_returned = 0;
3909 __u16 params, byte_count;
3911 cFYI(1, ("In QFSUnixInfo"));
3912 QFSUnixRetry:
3913 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3914 (void **) &pSMBr);
3915 if (rc)
3916 return rc;
3918 params = 2; /* level */
3919 pSMB->TotalDataCount = 0;
3920 pSMB->DataCount = 0;
3921 pSMB->DataOffset = 0;
3922 pSMB->MaxParameterCount = cpu_to_le16(2);
3923 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3924 pSMB->MaxSetupCount = 0;
3925 pSMB->Reserved = 0;
3926 pSMB->Flags = 0;
3927 pSMB->Timeout = 0;
3928 pSMB->Reserved2 = 0;
3929 byte_count = params + 1 /* pad */ ;
3930 pSMB->ParameterCount = cpu_to_le16(params);
3931 pSMB->TotalParameterCount = pSMB->ParameterCount;
3932 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3933 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3934 pSMB->SetupCount = 1;
3935 pSMB->Reserved3 = 0;
3936 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3937 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3938 pSMB->hdr.smb_buf_length += byte_count;
3939 pSMB->ByteCount = cpu_to_le16(byte_count);
3941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3943 if (rc) {
3944 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3945 } else { /* decode response */
3946 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3948 if (rc || (pSMBr->ByteCount < 13)) {
3949 rc = -EIO; /* bad smb */
3950 } else {
3951 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3952 response_data =
3953 (FILE_SYSTEM_UNIX_INFO
3954 *) (((char *) &pSMBr->hdr.Protocol) +
3955 data_offset);
3956 memcpy(&tcon->fsUnixInfo, response_data,
3957 sizeof (FILE_SYSTEM_UNIX_INFO));
3960 cifs_buf_release(pSMB);
3962 if (rc == -EAGAIN)
3963 goto QFSUnixRetry;
3966 return rc;
3970 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3972 /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3973 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3974 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3975 int rc = 0;
3976 int bytes_returned = 0;
3977 __u16 params, param_offset, offset, byte_count;
3979 cFYI(1, ("In SETFSUnixInfo"));
3980 SETFSUnixRetry:
3981 /* BB switch to small buf init to save memory */
3982 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3983 (void **) &pSMBr);
3984 if (rc)
3985 return rc;
3987 params = 4; /* 2 bytes zero followed by info level. */
3988 pSMB->MaxSetupCount = 0;
3989 pSMB->Reserved = 0;
3990 pSMB->Flags = 0;
3991 pSMB->Timeout = 0;
3992 pSMB->Reserved2 = 0;
3993 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3994 offset = param_offset + params;
3996 pSMB->MaxParameterCount = cpu_to_le16(4);
3997 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3998 pSMB->SetupCount = 1;
3999 pSMB->Reserved3 = 0;
4000 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4001 byte_count = 1 /* pad */ + params + 12;
4003 pSMB->DataCount = cpu_to_le16(12);
4004 pSMB->ParameterCount = cpu_to_le16(params);
4005 pSMB->TotalDataCount = pSMB->DataCount;
4006 pSMB->TotalParameterCount = pSMB->ParameterCount;
4007 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4008 pSMB->DataOffset = cpu_to_le16(offset);
4010 /* Params. */
4011 pSMB->FileNum = 0;
4012 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4014 /* Data. */
4015 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4016 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4017 pSMB->ClientUnixCap = cpu_to_le64(cap);
4019 pSMB->hdr.smb_buf_length += byte_count;
4020 pSMB->ByteCount = cpu_to_le16(byte_count);
4022 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4024 if (rc) {
4025 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4026 } else { /* decode response */
4027 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4028 if (rc) {
4029 rc = -EIO; /* bad smb */
4032 cifs_buf_release(pSMB);
4034 if (rc == -EAGAIN)
4035 goto SETFSUnixRetry;
4037 return rc;
4043 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4044 struct kstatfs *FSData)
4046 /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4047 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4048 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4049 FILE_SYSTEM_POSIX_INFO *response_data;
4050 int rc = 0;
4051 int bytes_returned = 0;
4052 __u16 params, byte_count;
4054 cFYI(1, ("In QFSPosixInfo"));
4055 QFSPosixRetry:
4056 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4057 (void **) &pSMBr);
4058 if (rc)
4059 return rc;
4061 params = 2; /* level */
4062 pSMB->TotalDataCount = 0;
4063 pSMB->DataCount = 0;
4064 pSMB->DataOffset = 0;
4065 pSMB->MaxParameterCount = cpu_to_le16(2);
4066 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4067 pSMB->MaxSetupCount = 0;
4068 pSMB->Reserved = 0;
4069 pSMB->Flags = 0;
4070 pSMB->Timeout = 0;
4071 pSMB->Reserved2 = 0;
4072 byte_count = params + 1 /* pad */ ;
4073 pSMB->ParameterCount = cpu_to_le16(params);
4074 pSMB->TotalParameterCount = pSMB->ParameterCount;
4075 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4076 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4077 pSMB->SetupCount = 1;
4078 pSMB->Reserved3 = 0;
4079 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4080 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4081 pSMB->hdr.smb_buf_length += byte_count;
4082 pSMB->ByteCount = cpu_to_le16(byte_count);
4084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4086 if (rc) {
4087 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4088 } else { /* decode response */
4089 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4091 if (rc || (pSMBr->ByteCount < 13)) {
4092 rc = -EIO; /* bad smb */
4093 } else {
4094 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4095 response_data =
4096 (FILE_SYSTEM_POSIX_INFO
4097 *) (((char *) &pSMBr->hdr.Protocol) +
4098 data_offset);
4099 FSData->f_bsize =
4100 le32_to_cpu(response_data->BlockSize);
4101 FSData->f_blocks =
4102 le64_to_cpu(response_data->TotalBlocks);
4103 FSData->f_bfree =
4104 le64_to_cpu(response_data->BlocksAvail);
4105 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4106 FSData->f_bavail = FSData->f_bfree;
4107 } else {
4108 FSData->f_bavail =
4109 le64_to_cpu(response_data->UserBlocksAvail);
4111 if(response_data->TotalFileNodes != cpu_to_le64(-1))
4112 FSData->f_files =
4113 le64_to_cpu(response_data->TotalFileNodes);
4114 if(response_data->FreeFileNodes != cpu_to_le64(-1))
4115 FSData->f_ffree =
4116 le64_to_cpu(response_data->FreeFileNodes);
4119 cifs_buf_release(pSMB);
4121 if (rc == -EAGAIN)
4122 goto QFSPosixRetry;
4124 return rc;
4128 /* We can not use write of zero bytes trick to
4129 set file size due to need for large file support. Also note that
4130 this SetPathInfo is preferred to SetFileInfo based method in next
4131 routine which is only needed to work around a sharing violation bug
4132 in Samba which this routine can run into */
4135 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4136 __u64 size, int SetAllocation,
4137 const struct nls_table *nls_codepage, int remap)
4139 struct smb_com_transaction2_spi_req *pSMB = NULL;
4140 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4141 struct file_end_of_file_info *parm_data;
4142 int name_len;
4143 int rc = 0;
4144 int bytes_returned = 0;
4145 __u16 params, byte_count, data_count, param_offset, offset;
4147 cFYI(1, ("In SetEOF"));
4148 SetEOFRetry:
4149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150 (void **) &pSMBr);
4151 if (rc)
4152 return rc;
4154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4155 name_len =
4156 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4157 PATH_MAX, nls_codepage, remap);
4158 name_len++; /* trailing null */
4159 name_len *= 2;
4160 } else { /* BB improve the check for buffer overruns BB */
4161 name_len = strnlen(fileName, PATH_MAX);
4162 name_len++; /* trailing null */
4163 strncpy(pSMB->FileName, fileName, name_len);
4165 params = 6 + name_len;
4166 data_count = sizeof (struct file_end_of_file_info);
4167 pSMB->MaxParameterCount = cpu_to_le16(2);
4168 pSMB->MaxDataCount = cpu_to_le16(4100);
4169 pSMB->MaxSetupCount = 0;
4170 pSMB->Reserved = 0;
4171 pSMB->Flags = 0;
4172 pSMB->Timeout = 0;
4173 pSMB->Reserved2 = 0;
4174 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4175 InformationLevel) - 4;
4176 offset = param_offset + params;
4177 if(SetAllocation) {
4178 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4179 pSMB->InformationLevel =
4180 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4181 else
4182 pSMB->InformationLevel =
4183 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4184 } else /* Set File Size */ {
4185 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4186 pSMB->InformationLevel =
4187 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4188 else
4189 pSMB->InformationLevel =
4190 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4193 parm_data =
4194 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4195 offset);
4196 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4197 pSMB->DataOffset = cpu_to_le16(offset);
4198 pSMB->SetupCount = 1;
4199 pSMB->Reserved3 = 0;
4200 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4201 byte_count = 3 /* pad */ + params + data_count;
4202 pSMB->DataCount = cpu_to_le16(data_count);
4203 pSMB->TotalDataCount = pSMB->DataCount;
4204 pSMB->ParameterCount = cpu_to_le16(params);
4205 pSMB->TotalParameterCount = pSMB->ParameterCount;
4206 pSMB->Reserved4 = 0;
4207 pSMB->hdr.smb_buf_length += byte_count;
4208 parm_data->FileSize = cpu_to_le64(size);
4209 pSMB->ByteCount = cpu_to_le16(byte_count);
4210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4212 if (rc) {
4213 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4216 cifs_buf_release(pSMB);
4218 if (rc == -EAGAIN)
4219 goto SetEOFRetry;
4221 return rc;
4225 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4226 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4228 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4229 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4230 char *data_offset;
4231 struct file_end_of_file_info *parm_data;
4232 int rc = 0;
4233 int bytes_returned = 0;
4234 __u16 params, param_offset, offset, byte_count, count;
4236 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4237 (long long)size));
4238 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4240 if (rc)
4241 return rc;
4243 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4245 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4246 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4248 params = 6;
4249 pSMB->MaxSetupCount = 0;
4250 pSMB->Reserved = 0;
4251 pSMB->Flags = 0;
4252 pSMB->Timeout = 0;
4253 pSMB->Reserved2 = 0;
4254 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4255 offset = param_offset + params;
4257 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4259 count = sizeof(struct file_end_of_file_info);
4260 pSMB->MaxParameterCount = cpu_to_le16(2);
4261 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4262 pSMB->SetupCount = 1;
4263 pSMB->Reserved3 = 0;
4264 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4265 byte_count = 3 /* pad */ + params + count;
4266 pSMB->DataCount = cpu_to_le16(count);
4267 pSMB->ParameterCount = cpu_to_le16(params);
4268 pSMB->TotalDataCount = pSMB->DataCount;
4269 pSMB->TotalParameterCount = pSMB->ParameterCount;
4270 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4271 parm_data =
4272 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4273 offset);
4274 pSMB->DataOffset = cpu_to_le16(offset);
4275 parm_data->FileSize = cpu_to_le64(size);
4276 pSMB->Fid = fid;
4277 if(SetAllocation) {
4278 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4279 pSMB->InformationLevel =
4280 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4281 else
4282 pSMB->InformationLevel =
4283 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4284 } else /* Set File Size */ {
4285 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4286 pSMB->InformationLevel =
4287 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4288 else
4289 pSMB->InformationLevel =
4290 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4292 pSMB->Reserved4 = 0;
4293 pSMB->hdr.smb_buf_length += byte_count;
4294 pSMB->ByteCount = cpu_to_le16(byte_count);
4295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4297 if (rc) {
4298 cFYI(1,
4299 ("Send error in SetFileInfo (SetFileSize) = %d",
4300 rc));
4303 if (pSMB)
4304 cifs_small_buf_release(pSMB);
4306 /* Note: On -EAGAIN error only caller can retry on handle based calls
4307 since file handle passed in no longer valid */
4309 return rc;
4312 /* Some legacy servers such as NT4 require that the file times be set on
4313 an open handle, rather than by pathname - this is awkward due to
4314 potential access conflicts on the open, but it is unavoidable for these
4315 old servers since the only other choice is to go from 100 nanosecond DCE
4316 time and resort to the original setpathinfo level which takes the ancient
4317 DOS time format with 2 second granularity */
4319 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4320 __u16 fid)
4322 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4323 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4324 char *data_offset;
4325 int rc = 0;
4326 int bytes_returned = 0;
4327 __u16 params, param_offset, offset, byte_count, count;
4329 cFYI(1, ("Set Times (via SetFileInfo)"));
4330 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4332 if (rc)
4333 return rc;
4335 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4337 /* At this point there is no need to override the current pid
4338 with the pid of the opener, but that could change if we someday
4339 use an existing handle (rather than opening one on the fly) */
4340 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4341 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4343 params = 6;
4344 pSMB->MaxSetupCount = 0;
4345 pSMB->Reserved = 0;
4346 pSMB->Flags = 0;
4347 pSMB->Timeout = 0;
4348 pSMB->Reserved2 = 0;
4349 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4350 offset = param_offset + params;
4352 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4354 count = sizeof (FILE_BASIC_INFO);
4355 pSMB->MaxParameterCount = cpu_to_le16(2);
4356 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4357 pSMB->SetupCount = 1;
4358 pSMB->Reserved3 = 0;
4359 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4360 byte_count = 3 /* pad */ + params + count;
4361 pSMB->DataCount = cpu_to_le16(count);
4362 pSMB->ParameterCount = cpu_to_le16(params);
4363 pSMB->TotalDataCount = pSMB->DataCount;
4364 pSMB->TotalParameterCount = pSMB->ParameterCount;
4365 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4366 pSMB->DataOffset = cpu_to_le16(offset);
4367 pSMB->Fid = fid;
4368 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4369 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4370 else
4371 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4372 pSMB->Reserved4 = 0;
4373 pSMB->hdr.smb_buf_length += byte_count;
4374 pSMB->ByteCount = cpu_to_le16(byte_count);
4375 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4378 if (rc) {
4379 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4382 cifs_small_buf_release(pSMB);
4384 /* Note: On -EAGAIN error only caller can retry on handle based calls
4385 since file handle passed in no longer valid */
4387 return rc;
4392 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4393 const FILE_BASIC_INFO * data,
4394 const struct nls_table *nls_codepage, int remap)
4396 TRANSACTION2_SPI_REQ *pSMB = NULL;
4397 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4398 int name_len;
4399 int rc = 0;
4400 int bytes_returned = 0;
4401 char *data_offset;
4402 __u16 params, param_offset, offset, byte_count, count;
4404 cFYI(1, ("In SetTimes"));
4406 SetTimesRetry:
4407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4408 (void **) &pSMBr);
4409 if (rc)
4410 return rc;
4412 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4413 name_len =
4414 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4415 PATH_MAX, nls_codepage, remap);
4416 name_len++; /* trailing null */
4417 name_len *= 2;
4418 } else { /* BB improve the check for buffer overruns BB */
4419 name_len = strnlen(fileName, PATH_MAX);
4420 name_len++; /* trailing null */
4421 strncpy(pSMB->FileName, fileName, name_len);
4424 params = 6 + name_len;
4425 count = sizeof (FILE_BASIC_INFO);
4426 pSMB->MaxParameterCount = cpu_to_le16(2);
4427 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4428 pSMB->MaxSetupCount = 0;
4429 pSMB->Reserved = 0;
4430 pSMB->Flags = 0;
4431 pSMB->Timeout = 0;
4432 pSMB->Reserved2 = 0;
4433 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4434 InformationLevel) - 4;
4435 offset = param_offset + params;
4436 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4437 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4438 pSMB->DataOffset = cpu_to_le16(offset);
4439 pSMB->SetupCount = 1;
4440 pSMB->Reserved3 = 0;
4441 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4442 byte_count = 3 /* pad */ + params + count;
4444 pSMB->DataCount = cpu_to_le16(count);
4445 pSMB->ParameterCount = cpu_to_le16(params);
4446 pSMB->TotalDataCount = pSMB->DataCount;
4447 pSMB->TotalParameterCount = pSMB->ParameterCount;
4448 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4449 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4450 else
4451 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4452 pSMB->Reserved4 = 0;
4453 pSMB->hdr.smb_buf_length += byte_count;
4454 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4455 pSMB->ByteCount = cpu_to_le16(byte_count);
4456 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4457 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4458 if (rc) {
4459 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4462 cifs_buf_release(pSMB);
4464 if (rc == -EAGAIN)
4465 goto SetTimesRetry;
4467 return rc;
4470 /* Can not be used to set time stamps yet (due to old DOS time format) */
4471 /* Can be used to set attributes */
4472 #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4473 handling it anyway and NT4 was what we thought it would be needed for
4474 Do not delete it until we prove whether needed for Win9x though */
4476 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4477 __u16 dos_attrs, const struct nls_table *nls_codepage)
4479 SETATTR_REQ *pSMB = NULL;
4480 SETATTR_RSP *pSMBr = NULL;
4481 int rc = 0;
4482 int bytes_returned;
4483 int name_len;
4485 cFYI(1, ("In SetAttrLegacy"));
4487 SetAttrLgcyRetry:
4488 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4489 (void **) &pSMBr);
4490 if (rc)
4491 return rc;
4493 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4494 name_len =
4495 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4496 PATH_MAX, nls_codepage);
4497 name_len++; /* trailing null */
4498 name_len *= 2;
4499 } else { /* BB improve the check for buffer overruns BB */
4500 name_len = strnlen(fileName, PATH_MAX);
4501 name_len++; /* trailing null */
4502 strncpy(pSMB->fileName, fileName, name_len);
4504 pSMB->attr = cpu_to_le16(dos_attrs);
4505 pSMB->BufferFormat = 0x04;
4506 pSMB->hdr.smb_buf_length += name_len + 1;
4507 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4510 if (rc) {
4511 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4514 cifs_buf_release(pSMB);
4516 if (rc == -EAGAIN)
4517 goto SetAttrLgcyRetry;
4519 return rc;
4521 #endif /* temporarily unneeded SetAttr legacy function */
4524 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4525 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4526 dev_t device, const struct nls_table *nls_codepage,
4527 int remap)
4529 TRANSACTION2_SPI_REQ *pSMB = NULL;
4530 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4531 int name_len;
4532 int rc = 0;
4533 int bytes_returned = 0;
4534 FILE_UNIX_BASIC_INFO *data_offset;
4535 __u16 params, param_offset, offset, count, byte_count;
4537 cFYI(1, ("In SetUID/GID/Mode"));
4538 setPermsRetry:
4539 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4540 (void **) &pSMBr);
4541 if (rc)
4542 return rc;
4544 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4545 name_len =
4546 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4547 PATH_MAX, nls_codepage, remap);
4548 name_len++; /* trailing null */
4549 name_len *= 2;
4550 } else { /* BB improve the check for buffer overruns BB */
4551 name_len = strnlen(fileName, PATH_MAX);
4552 name_len++; /* trailing null */
4553 strncpy(pSMB->FileName, fileName, name_len);
4556 params = 6 + name_len;
4557 count = sizeof (FILE_UNIX_BASIC_INFO);
4558 pSMB->MaxParameterCount = cpu_to_le16(2);
4559 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4560 pSMB->MaxSetupCount = 0;
4561 pSMB->Reserved = 0;
4562 pSMB->Flags = 0;
4563 pSMB->Timeout = 0;
4564 pSMB->Reserved2 = 0;
4565 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4566 InformationLevel) - 4;
4567 offset = param_offset + params;
4568 data_offset =
4569 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4570 offset);
4571 memset(data_offset, 0, count);
4572 pSMB->DataOffset = cpu_to_le16(offset);
4573 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4574 pSMB->SetupCount = 1;
4575 pSMB->Reserved3 = 0;
4576 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4577 byte_count = 3 /* pad */ + params + count;
4578 pSMB->ParameterCount = cpu_to_le16(params);
4579 pSMB->DataCount = cpu_to_le16(count);
4580 pSMB->TotalParameterCount = pSMB->ParameterCount;
4581 pSMB->TotalDataCount = pSMB->DataCount;
4582 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4583 pSMB->Reserved4 = 0;
4584 pSMB->hdr.smb_buf_length += byte_count;
4585 data_offset->Uid = cpu_to_le64(uid);
4586 data_offset->Gid = cpu_to_le64(gid);
4587 /* better to leave device as zero when it is */
4588 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4589 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4590 data_offset->Permissions = cpu_to_le64(mode);
4592 if(S_ISREG(mode))
4593 data_offset->Type = cpu_to_le32(UNIX_FILE);
4594 else if(S_ISDIR(mode))
4595 data_offset->Type = cpu_to_le32(UNIX_DIR);
4596 else if(S_ISLNK(mode))
4597 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4598 else if(S_ISCHR(mode))
4599 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4600 else if(S_ISBLK(mode))
4601 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4602 else if(S_ISFIFO(mode))
4603 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4604 else if(S_ISSOCK(mode))
4605 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4608 pSMB->ByteCount = cpu_to_le16(byte_count);
4609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4610 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4611 if (rc) {
4612 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4615 if (pSMB)
4616 cifs_buf_release(pSMB);
4617 if (rc == -EAGAIN)
4618 goto setPermsRetry;
4619 return rc;
4622 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
4623 const int notify_subdirs, const __u16 netfid,
4624 __u32 filter, struct file * pfile, int multishot,
4625 const struct nls_table *nls_codepage)
4627 int rc = 0;
4628 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4629 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4630 struct dir_notify_req *dnotify_req;
4631 int bytes_returned;
4633 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4634 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4635 (void **) &pSMBr);
4636 if (rc)
4637 return rc;
4639 pSMB->TotalParameterCount = 0 ;
4640 pSMB->TotalDataCount = 0;
4641 pSMB->MaxParameterCount = cpu_to_le32(2);
4642 /* BB find exact data count max from sess structure BB */
4643 pSMB->MaxDataCount = 0; /* same in little endian or be */
4644 /* BB VERIFY verify which is correct for above BB */
4645 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4646 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4648 pSMB->MaxSetupCount = 4;
4649 pSMB->Reserved = 0;
4650 pSMB->ParameterOffset = 0;
4651 pSMB->DataCount = 0;
4652 pSMB->DataOffset = 0;
4653 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4654 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4655 pSMB->ParameterCount = pSMB->TotalParameterCount;
4656 if(notify_subdirs)
4657 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4658 pSMB->Reserved2 = 0;
4659 pSMB->CompletionFilter = cpu_to_le32(filter);
4660 pSMB->Fid = netfid; /* file handle always le */
4661 pSMB->ByteCount = 0;
4663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4664 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4665 if (rc) {
4666 cFYI(1, ("Error in Notify = %d", rc));
4667 } else {
4668 /* Add file to outstanding requests */
4669 /* BB change to kmem cache alloc */
4670 dnotify_req = (struct dir_notify_req *) kmalloc(
4671 sizeof(struct dir_notify_req),
4672 GFP_KERNEL);
4673 if(dnotify_req) {
4674 dnotify_req->Pid = pSMB->hdr.Pid;
4675 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4676 dnotify_req->Mid = pSMB->hdr.Mid;
4677 dnotify_req->Tid = pSMB->hdr.Tid;
4678 dnotify_req->Uid = pSMB->hdr.Uid;
4679 dnotify_req->netfid = netfid;
4680 dnotify_req->pfile = pfile;
4681 dnotify_req->filter = filter;
4682 dnotify_req->multishot = multishot;
4683 spin_lock(&GlobalMid_Lock);
4684 list_add_tail(&dnotify_req->lhead,
4685 &GlobalDnotifyReqList);
4686 spin_unlock(&GlobalMid_Lock);
4687 } else
4688 rc = -ENOMEM;
4690 cifs_buf_release(pSMB);
4691 return rc;
4693 #ifdef CONFIG_CIFS_XATTR
4694 ssize_t
4695 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4696 const unsigned char *searchName,
4697 char * EAData, size_t buf_size,
4698 const struct nls_table *nls_codepage, int remap)
4700 /* BB assumes one setup word */
4701 TRANSACTION2_QPI_REQ *pSMB = NULL;
4702 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4703 int rc = 0;
4704 int bytes_returned;
4705 int name_len;
4706 struct fea * temp_fea;
4707 char * temp_ptr;
4708 __u16 params, byte_count;
4710 cFYI(1, ("In Query All EAs path %s", searchName));
4711 QAllEAsRetry:
4712 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4713 (void **) &pSMBr);
4714 if (rc)
4715 return rc;
4717 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4718 name_len =
4719 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4720 PATH_MAX, nls_codepage, remap);
4721 name_len++; /* trailing null */
4722 name_len *= 2;
4723 } else { /* BB improve the check for buffer overruns BB */
4724 name_len = strnlen(searchName, PATH_MAX);
4725 name_len++; /* trailing null */
4726 strncpy(pSMB->FileName, searchName, name_len);
4729 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4730 pSMB->TotalDataCount = 0;
4731 pSMB->MaxParameterCount = cpu_to_le16(2);
4732 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4733 pSMB->MaxSetupCount = 0;
4734 pSMB->Reserved = 0;
4735 pSMB->Flags = 0;
4736 pSMB->Timeout = 0;
4737 pSMB->Reserved2 = 0;
4738 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4739 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4740 pSMB->DataCount = 0;
4741 pSMB->DataOffset = 0;
4742 pSMB->SetupCount = 1;
4743 pSMB->Reserved3 = 0;
4744 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4745 byte_count = params + 1 /* pad */ ;
4746 pSMB->TotalParameterCount = cpu_to_le16(params);
4747 pSMB->ParameterCount = pSMB->TotalParameterCount;
4748 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4749 pSMB->Reserved4 = 0;
4750 pSMB->hdr.smb_buf_length += byte_count;
4751 pSMB->ByteCount = cpu_to_le16(byte_count);
4753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4754 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4755 if (rc) {
4756 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4757 } else { /* decode response */
4758 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4760 /* BB also check enough total bytes returned */
4761 /* BB we need to improve the validity checking
4762 of these trans2 responses */
4763 if (rc || (pSMBr->ByteCount < 4))
4764 rc = -EIO; /* bad smb */
4765 /* else if (pFindData){
4766 memcpy((char *) pFindData,
4767 (char *) &pSMBr->hdr.Protocol +
4768 data_offset, kl);
4769 }*/ else {
4770 /* check that length of list is not more than bcc */
4771 /* check that each entry does not go beyond length
4772 of list */
4773 /* check that each element of each entry does not
4774 go beyond end of list */
4775 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4776 struct fealist * ea_response_data;
4777 rc = 0;
4778 /* validate_trans2_offsets() */
4779 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4780 ea_response_data = (struct fealist *)
4781 (((char *) &pSMBr->hdr.Protocol) +
4782 data_offset);
4783 name_len = le32_to_cpu(ea_response_data->list_len);
4784 cFYI(1,("ea length %d", name_len));
4785 if(name_len <= 8) {
4786 /* returned EA size zeroed at top of function */
4787 cFYI(1,("empty EA list returned from server"));
4788 } else {
4789 /* account for ea list len */
4790 name_len -= 4;
4791 temp_fea = ea_response_data->list;
4792 temp_ptr = (char *)temp_fea;
4793 while(name_len > 0) {
4794 __u16 value_len;
4795 name_len -= 4;
4796 temp_ptr += 4;
4797 rc += temp_fea->name_len;
4798 /* account for prefix user. and trailing null */
4799 rc = rc + 5 + 1;
4800 if(rc<(int)buf_size) {
4801 memcpy(EAData,"user.",5);
4802 EAData+=5;
4803 memcpy(EAData,temp_ptr,temp_fea->name_len);
4804 EAData+=temp_fea->name_len;
4805 /* null terminate name */
4806 *EAData = 0;
4807 EAData = EAData + 1;
4808 } else if(buf_size == 0) {
4809 /* skip copy - calc size only */
4810 } else {
4811 /* stop before overrun buffer */
4812 rc = -ERANGE;
4813 break;
4815 name_len -= temp_fea->name_len;
4816 temp_ptr += temp_fea->name_len;
4817 /* account for trailing null */
4818 name_len--;
4819 temp_ptr++;
4820 value_len = le16_to_cpu(temp_fea->value_len);
4821 name_len -= value_len;
4822 temp_ptr += value_len;
4823 /* BB check that temp_ptr is still within smb BB*/
4824 /* no trailing null to account for in value len */
4825 /* go on to next EA */
4826 temp_fea = (struct fea *)temp_ptr;
4831 if (pSMB)
4832 cifs_buf_release(pSMB);
4833 if (rc == -EAGAIN)
4834 goto QAllEAsRetry;
4836 return (ssize_t)rc;
4839 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4840 const unsigned char * searchName,const unsigned char * ea_name,
4841 unsigned char * ea_value, size_t buf_size,
4842 const struct nls_table *nls_codepage, int remap)
4844 TRANSACTION2_QPI_REQ *pSMB = NULL;
4845 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4846 int rc = 0;
4847 int bytes_returned;
4848 int name_len;
4849 struct fea * temp_fea;
4850 char * temp_ptr;
4851 __u16 params, byte_count;
4853 cFYI(1, ("In Query EA path %s", searchName));
4854 QEARetry:
4855 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4856 (void **) &pSMBr);
4857 if (rc)
4858 return rc;
4860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4861 name_len =
4862 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
4863 PATH_MAX, nls_codepage, remap);
4864 name_len++; /* trailing null */
4865 name_len *= 2;
4866 } else { /* BB improve the check for buffer overruns BB */
4867 name_len = strnlen(searchName, PATH_MAX);
4868 name_len++; /* trailing null */
4869 strncpy(pSMB->FileName, searchName, name_len);
4872 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4873 pSMB->TotalDataCount = 0;
4874 pSMB->MaxParameterCount = cpu_to_le16(2);
4875 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4876 pSMB->MaxSetupCount = 0;
4877 pSMB->Reserved = 0;
4878 pSMB->Flags = 0;
4879 pSMB->Timeout = 0;
4880 pSMB->Reserved2 = 0;
4881 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4882 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4883 pSMB->DataCount = 0;
4884 pSMB->DataOffset = 0;
4885 pSMB->SetupCount = 1;
4886 pSMB->Reserved3 = 0;
4887 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4888 byte_count = params + 1 /* pad */ ;
4889 pSMB->TotalParameterCount = cpu_to_le16(params);
4890 pSMB->ParameterCount = pSMB->TotalParameterCount;
4891 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4892 pSMB->Reserved4 = 0;
4893 pSMB->hdr.smb_buf_length += byte_count;
4894 pSMB->ByteCount = cpu_to_le16(byte_count);
4896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4898 if (rc) {
4899 cFYI(1, ("Send error in Query EA = %d", rc));
4900 } else { /* decode response */
4901 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4903 /* BB also check enough total bytes returned */
4904 /* BB we need to improve the validity checking
4905 of these trans2 responses */
4906 if (rc || (pSMBr->ByteCount < 4))
4907 rc = -EIO; /* bad smb */
4908 /* else if (pFindData){
4909 memcpy((char *) pFindData,
4910 (char *) &pSMBr->hdr.Protocol +
4911 data_offset, kl);
4912 }*/ else {
4913 /* check that length of list is not more than bcc */
4914 /* check that each entry does not go beyond length
4915 of list */
4916 /* check that each element of each entry does not
4917 go beyond end of list */
4918 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4919 struct fealist * ea_response_data;
4920 rc = -ENODATA;
4921 /* validate_trans2_offsets() */
4922 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4923 ea_response_data = (struct fealist *)
4924 (((char *) &pSMBr->hdr.Protocol) +
4925 data_offset);
4926 name_len = le32_to_cpu(ea_response_data->list_len);
4927 cFYI(1,("ea length %d", name_len));
4928 if(name_len <= 8) {
4929 /* returned EA size zeroed at top of function */
4930 cFYI(1,("empty EA list returned from server"));
4931 } else {
4932 /* account for ea list len */
4933 name_len -= 4;
4934 temp_fea = ea_response_data->list;
4935 temp_ptr = (char *)temp_fea;
4936 /* loop through checking if we have a matching
4937 name and then return the associated value */
4938 while(name_len > 0) {
4939 __u16 value_len;
4940 name_len -= 4;
4941 temp_ptr += 4;
4942 value_len = le16_to_cpu(temp_fea->value_len);
4943 /* BB validate that value_len falls within SMB,
4944 even though maximum for name_len is 255 */
4945 if(memcmp(temp_fea->name,ea_name,
4946 temp_fea->name_len) == 0) {
4947 /* found a match */
4948 rc = value_len;
4949 /* account for prefix user. and trailing null */
4950 if(rc<=(int)buf_size) {
4951 memcpy(ea_value,
4952 temp_fea->name+temp_fea->name_len+1,
4953 rc);
4954 /* ea values, unlike ea names,
4955 are not null terminated */
4956 } else if(buf_size == 0) {
4957 /* skip copy - calc size only */
4958 } else {
4959 /* stop before overrun buffer */
4960 rc = -ERANGE;
4962 break;
4964 name_len -= temp_fea->name_len;
4965 temp_ptr += temp_fea->name_len;
4966 /* account for trailing null */
4967 name_len--;
4968 temp_ptr++;
4969 name_len -= value_len;
4970 temp_ptr += value_len;
4971 /* no trailing null to account for in value len */
4972 /* go on to next EA */
4973 temp_fea = (struct fea *)temp_ptr;
4978 if (pSMB)
4979 cifs_buf_release(pSMB);
4980 if (rc == -EAGAIN)
4981 goto QEARetry;
4983 return (ssize_t)rc;
4987 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4988 const char * ea_name, const void * ea_value,
4989 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4990 int remap)
4992 struct smb_com_transaction2_spi_req *pSMB = NULL;
4993 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4994 struct fealist *parm_data;
4995 int name_len;
4996 int rc = 0;
4997 int bytes_returned = 0;
4998 __u16 params, param_offset, byte_count, offset, count;
5000 cFYI(1, ("In SetEA"));
5001 SetEARetry:
5002 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5003 (void **) &pSMBr);
5004 if (rc)
5005 return rc;
5007 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5008 name_len =
5009 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5010 PATH_MAX, nls_codepage, remap);
5011 name_len++; /* trailing null */
5012 name_len *= 2;
5013 } else { /* BB improve the check for buffer overruns BB */
5014 name_len = strnlen(fileName, PATH_MAX);
5015 name_len++; /* trailing null */
5016 strncpy(pSMB->FileName, fileName, name_len);
5019 params = 6 + name_len;
5021 /* done calculating parms using name_len of file name,
5022 now use name_len to calculate length of ea name
5023 we are going to create in the inode xattrs */
5024 if(ea_name == NULL)
5025 name_len = 0;
5026 else
5027 name_len = strnlen(ea_name,255);
5029 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5030 pSMB->MaxParameterCount = cpu_to_le16(2);
5031 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5032 pSMB->MaxSetupCount = 0;
5033 pSMB->Reserved = 0;
5034 pSMB->Flags = 0;
5035 pSMB->Timeout = 0;
5036 pSMB->Reserved2 = 0;
5037 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5038 InformationLevel) - 4;
5039 offset = param_offset + params;
5040 pSMB->InformationLevel =
5041 cpu_to_le16(SMB_SET_FILE_EA);
5043 parm_data =
5044 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5045 offset);
5046 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5047 pSMB->DataOffset = cpu_to_le16(offset);
5048 pSMB->SetupCount = 1;
5049 pSMB->Reserved3 = 0;
5050 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5051 byte_count = 3 /* pad */ + params + count;
5052 pSMB->DataCount = cpu_to_le16(count);
5053 parm_data->list_len = cpu_to_le32(count);
5054 parm_data->list[0].EA_flags = 0;
5055 /* we checked above that name len is less than 255 */
5056 parm_data->list[0].name_len = (__u8)name_len;
5057 /* EA names are always ASCII */
5058 if(ea_name)
5059 strncpy(parm_data->list[0].name,ea_name,name_len);
5060 parm_data->list[0].name[name_len] = 0;
5061 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5062 /* caller ensures that ea_value_len is less than 64K but
5063 we need to ensure that it fits within the smb */
5065 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5066 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5067 if(ea_value_len)
5068 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5070 pSMB->TotalDataCount = pSMB->DataCount;
5071 pSMB->ParameterCount = cpu_to_le16(params);
5072 pSMB->TotalParameterCount = pSMB->ParameterCount;
5073 pSMB->Reserved4 = 0;
5074 pSMB->hdr.smb_buf_length += byte_count;
5075 pSMB->ByteCount = cpu_to_le16(byte_count);
5076 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5077 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5078 if (rc) {
5079 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5082 cifs_buf_release(pSMB);
5084 if (rc == -EAGAIN)
5085 goto SetEARetry;
5087 return rc;
5090 #endif