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