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