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