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