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