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