]> 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;
333
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"));
418 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
419 } else if(sign_CIFS_PDUs == 1) {
420 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
421 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
422 }
423
424 }
425 if (pSMB)
426 cifs_buf_release(pSMB);
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) {
521 if(ses->server->secMode &
522 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
523 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
524 }
525
526 pSMB->hdr.Uid = ses->Suid;
527
528 pSMB->AndXCommand = 0xFF;
529 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
530 smb_buffer_response, &length, 0);
531 if (ses->server) {
532 atomic_dec(&ses->server->socketUseCount);
533 if (atomic_read(&ses->server->socketUseCount) == 0) {
534 spin_lock(&GlobalMid_Lock);
535 ses->server->tcpStatus = CifsExiting;
536 spin_unlock(&GlobalMid_Lock);
537 rc = -ESHUTDOWN;
538 }
539 }
540 if (pSMB)
541 cifs_small_buf_release(pSMB);
542 up(&ses->sesSem);
543
544 /* if session dead then we do not need to do ulogoff,
545 since server closed smb session, no sense reporting
546 error */
547 if (rc == -EAGAIN)
548 rc = 0;
549 return rc;
550}
551
552int
737b758c
SF
553CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
554 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
555{
556 DELETE_FILE_REQ *pSMB = NULL;
557 DELETE_FILE_RSP *pSMBr = NULL;
558 int rc = 0;
559 int bytes_returned;
560 int name_len;
561
562DelFileRetry:
563 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
564 (void **) &pSMBr);
565 if (rc)
566 return rc;
567
568 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
569 name_len =
b1a45695 570 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
737b758c 571 PATH_MAX, nls_codepage, remap);
1da177e4
LT
572 name_len++; /* trailing null */
573 name_len *= 2;
09d1db5c 574 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
575 name_len = strnlen(fileName, PATH_MAX);
576 name_len++; /* trailing null */
577 strncpy(pSMB->fileName, fileName, name_len);
578 }
579 pSMB->SearchAttributes =
580 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
581 pSMB->BufferFormat = 0x04;
582 pSMB->hdr.smb_buf_length += name_len + 1;
583 pSMB->ByteCount = cpu_to_le16(name_len + 1);
584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
586 if (rc) {
587 cFYI(1, ("Error in RMFile = %d", rc));
588 }
589#ifdef CONFIG_CIFS_STATS
590 else {
591 atomic_inc(&tcon->num_deletes);
592 }
593#endif
594
595 cifs_buf_release(pSMB);
596 if (rc == -EAGAIN)
597 goto DelFileRetry;
598
599 return rc;
600}
601
602int
737b758c
SF
603CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
604 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
605{
606 DELETE_DIRECTORY_REQ *pSMB = NULL;
607 DELETE_DIRECTORY_RSP *pSMBr = NULL;
608 int rc = 0;
609 int bytes_returned;
610 int name_len;
611
612 cFYI(1, ("In CIFSSMBRmDir"));
613RmDirRetry:
614 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
615 (void **) &pSMBr);
616 if (rc)
617 return rc;
618
619 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
737b758c
SF
620 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
621 PATH_MAX, nls_codepage, remap);
1da177e4
LT
622 name_len++; /* trailing null */
623 name_len *= 2;
09d1db5c 624 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
625 name_len = strnlen(dirName, PATH_MAX);
626 name_len++; /* trailing null */
627 strncpy(pSMB->DirName, dirName, name_len);
628 }
629
630 pSMB->BufferFormat = 0x04;
631 pSMB->hdr.smb_buf_length += name_len + 1;
632 pSMB->ByteCount = cpu_to_le16(name_len + 1);
633 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
634 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
635 if (rc) {
636 cFYI(1, ("Error in RMDir = %d", rc));
637 }
638#ifdef CONFIG_CIFS_STATS
639 else {
640 atomic_inc(&tcon->num_rmdirs);
641 }
642#endif
643
644 cifs_buf_release(pSMB);
645 if (rc == -EAGAIN)
646 goto RmDirRetry;
647 return rc;
648}
649
650int
651CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
737b758c 652 const char *name, const struct nls_table *nls_codepage, int remap)
1da177e4
LT
653{
654 int rc = 0;
655 CREATE_DIRECTORY_REQ *pSMB = NULL;
656 CREATE_DIRECTORY_RSP *pSMBr = NULL;
657 int bytes_returned;
658 int name_len;
659
660 cFYI(1, ("In CIFSSMBMkDir"));
661MkDirRetry:
662 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
663 (void **) &pSMBr);
664 if (rc)
665 return rc;
666
667 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
b1a45695 668 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
737b758c 669 PATH_MAX, nls_codepage, remap);
1da177e4
LT
670 name_len++; /* trailing null */
671 name_len *= 2;
09d1db5c 672 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
673 name_len = strnlen(name, PATH_MAX);
674 name_len++; /* trailing null */
675 strncpy(pSMB->DirName, name, name_len);
676 }
677
678 pSMB->BufferFormat = 0x04;
679 pSMB->hdr.smb_buf_length += name_len + 1;
680 pSMB->ByteCount = cpu_to_le16(name_len + 1);
681 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
683 if (rc) {
684 cFYI(1, ("Error in Mkdir = %d", rc));
685 }
686#ifdef CONFIG_CIFS_STATS
687 else {
688 atomic_inc(&tcon->num_mkdirs);
689 }
690#endif
691 cifs_buf_release(pSMB);
692 if (rc == -EAGAIN)
693 goto MkDirRetry;
694 return rc;
695}
696
697int
698CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
699 const char *fileName, const int openDisposition,
700 const int access_flags, const int create_options, __u16 * netfid,
701 int *pOplock, FILE_ALL_INFO * pfile_info,
737b758c 702 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
703{
704 int rc = -EACCES;
705 OPEN_REQ *pSMB = NULL;
706 OPEN_RSP *pSMBr = NULL;
707 int bytes_returned;
708 int name_len;
709 __u16 count;
710
711openRetry:
712 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
713 (void **) &pSMBr);
714 if (rc)
715 return rc;
716
717 pSMB->AndXCommand = 0xFF; /* none */
718
719 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
720 count = 1; /* account for one byte pad to word boundary */
721 name_len =
b1a45695 722 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
737b758c 723 fileName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
724 name_len++; /* trailing null */
725 name_len *= 2;
726 pSMB->NameLength = cpu_to_le16(name_len);
09d1db5c 727 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
728 count = 0; /* no pad */
729 name_len = strnlen(fileName, PATH_MAX);
730 name_len++; /* trailing null */
731 pSMB->NameLength = cpu_to_le16(name_len);
732 strncpy(pSMB->fileName, fileName, name_len);
733 }
734 if (*pOplock & REQ_OPLOCK)
735 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
736 else if (*pOplock & REQ_BATCHOPLOCK) {
737 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
738 }
739 pSMB->DesiredAccess = cpu_to_le32(access_flags);
740 pSMB->AllocationSize = 0;
eda3c029
SF
741 /* set file as system file if special file such
742 as fifo and server expecting SFU style and
743 no Unix extensions */
744 if(create_options & CREATE_OPTION_SPECIAL)
745 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
746 else
747 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1da177e4
LT
748 /* XP does not handle ATTR_POSIX_SEMANTICS */
749 /* but it helps speed up case sensitive checks for other
750 servers such as Samba */
751 if (tcon->ses->capabilities & CAP_UNIX)
752 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
753
754 /* if ((omode & S_IWUGO) == 0)
755 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
756 /* Above line causes problems due to vfs splitting create into two
757 pieces - need to set mode after file created not while it is
758 being created */
759 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
760 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
eda3c029 761 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
09d1db5c
SF
762 /* BB Expirement with various impersonation levels and verify */
763 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1da177e4
LT
764 pSMB->SecurityFlags =
765 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
766
767 count += name_len;
768 pSMB->hdr.smb_buf_length += count;
769
770 pSMB->ByteCount = cpu_to_le16(count);
771 /* long_op set to 1 to allow for oplock break timeouts */
772 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
773 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
774 if (rc) {
775 cFYI(1, ("Error in Open = %d", rc));
776 } else {
09d1db5c 777 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1da177e4
LT
778 *netfid = pSMBr->Fid; /* cifs fid stays in le */
779 /* Let caller know file was created so we can set the mode. */
780 /* Do we care about the CreateAction in any other cases? */
781 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
782 *pOplock |= CIFS_CREATE_ACTION;
783 if(pfile_info) {
784 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
785 36 /* CreationTime to Attributes */);
786 /* the file_info buf is endian converted by caller */
787 pfile_info->AllocationSize = pSMBr->AllocationSize;
788 pfile_info->EndOfFile = pSMBr->EndOfFile;
789 pfile_info->NumberOfLinks = cpu_to_le32(1);
790 }
791
792#ifdef CONFIG_CIFS_STATS
793 atomic_inc(&tcon->num_opens);
794#endif
795 }
796 cifs_buf_release(pSMB);
797 if (rc == -EAGAIN)
798 goto openRetry;
799 return rc;
800}
801
802/* If no buffer passed in, then caller wants to do the copy
803 as in the case of readpages so the SMB buffer must be
804 freed by the caller */
805
806int
807CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
808 const int netfid, const unsigned int count,
809 const __u64 lseek, unsigned int *nbytes, char **buf)
810{
811 int rc = -EACCES;
812 READ_REQ *pSMB = NULL;
813 READ_RSP *pSMBr = NULL;
814 char *pReadData = NULL;
815 int bytes_returned;
816
817 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
818
819 *nbytes = 0;
820 rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
821 (void **) &pSMBr);
822 if (rc)
823 return rc;
824
825 /* tcon and ses pointer are checked in smb_init */
826 if (tcon->ses->server == NULL)
827 return -ECONNABORTED;
828
829 pSMB->AndXCommand = 0xFF; /* none */
830 pSMB->Fid = netfid;
831 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
832 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
833 pSMB->Remaining = 0;
834 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
835 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
836 pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
837
838 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
839 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
840 if (rc) {
841 cERROR(1, ("Send error in read = %d", rc));
842 } else {
843 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
844 data_length = data_length << 16;
845 data_length += le16_to_cpu(pSMBr->DataLength);
846 *nbytes = data_length;
847
848 /*check that DataLength would not go beyond end of SMB */
849 if ((data_length > CIFSMaxBufSize)
850 || (data_length > count)) {
851 cFYI(1,("bad length %d for count %d",data_length,count));
852 rc = -EIO;
853 *nbytes = 0;
854 } else {
855 pReadData =
856 (char *) (&pSMBr->hdr.Protocol) +
857 le16_to_cpu(pSMBr->DataOffset);
858/* if(rc = copy_to_user(buf, pReadData, data_length)) {
859 cERROR(1,("Faulting on read rc = %d",rc));
860 rc = -EFAULT;
861 }*/ /* can not use copy_to_user when using page cache*/
862 if(*buf)
863 memcpy(*buf,pReadData,data_length);
864 }
865 }
866 if(*buf)
867 cifs_buf_release(pSMB);
868 else
869 *buf = (char *)pSMB;
870
871 /* Note: On -EAGAIN error only caller can retry on handle based calls
872 since file handle passed in no longer valid */
873 return rc;
874}
875
876int
877CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
878 const int netfid, const unsigned int count,
879 const __u64 offset, unsigned int *nbytes, const char *buf,
880 const char __user * ubuf, const int long_op)
881{
882 int rc = -EACCES;
883 WRITE_REQ *pSMB = NULL;
884 WRITE_RSP *pSMBr = NULL;
885 int bytes_returned;
886 __u32 bytes_sent;
887 __u16 byte_count;
888
889 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
890 rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
891 (void **) &pSMBr);
892 if (rc)
893 return rc;
894 /* tcon and ses pointer are checked in smb_init */
895 if (tcon->ses->server == NULL)
896 return -ECONNABORTED;
897
898 pSMB->AndXCommand = 0xFF; /* none */
899 pSMB->Fid = netfid;
900 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
901 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
902 pSMB->Reserved = 0xFFFFFFFF;
903 pSMB->WriteMode = 0;
904 pSMB->Remaining = 0;
905
906 /* Can increase buffer size if buffer is big enough in some cases - ie we
907 can send more if LARGE_WRITE_X capability returned by the server and if
908 our buffer is big enough or if we convert to iovecs on socket writes
909 and eliminate the copy to the CIFS buffer */
910 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
911 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
912 } else {
913 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
914 & ~0xFF;
915 }
916
917 if (bytes_sent > count)
918 bytes_sent = count;
919 pSMB->DataOffset =
920 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
921 if(buf)
922 memcpy(pSMB->Data,buf,bytes_sent);
923 else if(ubuf) {
924 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
925 cifs_buf_release(pSMB);
926 return -EFAULT;
927 }
928 } else {
929 /* No buffer */
930 cifs_buf_release(pSMB);
931 return -EINVAL;
932 }
933
934 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
935 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
936 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
937 pSMB->hdr.smb_buf_length += bytes_sent+1;
938 pSMB->ByteCount = cpu_to_le16(byte_count);
939
940 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
941 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
942 if (rc) {
943 cFYI(1, ("Send error in write = %d", rc));
944 *nbytes = 0;
945 } else {
946 *nbytes = le16_to_cpu(pSMBr->CountHigh);
947 *nbytes = (*nbytes) << 16;
948 *nbytes += le16_to_cpu(pSMBr->Count);
949 }
950
951 cifs_buf_release(pSMB);
952
953 /* Note: On -EAGAIN error only caller can retry on handle based calls
954 since file handle passed in no longer valid */
955
956 return rc;
957}
958
959#ifdef CONFIG_CIFS_EXPERIMENTAL
d6e04ae6
SF
960int
961CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1da177e4 962 const int netfid, const unsigned int count,
d6e04ae6 963 const __u64 offset, unsigned int *nbytes, const char *buf,
1da177e4
LT
964 const int long_op)
965{
966 int rc = -EACCES;
967 WRITE_REQ *pSMB = NULL;
d6e04ae6
SF
968 int bytes_returned;
969 int smb_hdr_len;
970 __u32 bytes_sent;
1da177e4
LT
971 __u16 byte_count;
972
0c0ff093 973 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
1da177e4 974 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
1da177e4
LT
975 if (rc)
976 return rc;
1da177e4
LT
977 /* tcon and ses pointer are checked in smb_init */
978 if (tcon->ses->server == NULL)
979 return -ECONNABORTED;
980
d6e04ae6 981 pSMB->AndXCommand = 0xFF; /* none */
1da177e4
LT
982 pSMB->Fid = netfid;
983 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
984 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
985 pSMB->Reserved = 0xFFFFFFFF;
986 pSMB->WriteMode = 0;
987 pSMB->Remaining = 0;
d6e04ae6
SF
988
989 /* Can increase buffer size if buffer is big enough in some cases - ie
990 can send more if LARGE_WRITE_X capability returned by the server and if
991 our buffer is big enough or if we convert to iovecs on socket writes
992 and eliminate the copy to the CIFS buffer */
993 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
994 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
995 } else {
996 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
997 & ~0xFF;
998 }
999
1da177e4
LT
1000 if (bytes_sent > count)
1001 bytes_sent = count;
1da177e4
LT
1002 pSMB->DataOffset =
1003 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1004
d6e04ae6
SF
1005 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1006 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1007 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1008 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1009 pSMB->hdr.smb_buf_length += bytes_sent+1;
1da177e4
LT
1010 pSMB->ByteCount = cpu_to_le16(byte_count);
1011
d6e04ae6
SF
1012 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1013 buf, bytes_sent, &bytes_returned, long_op);
1da177e4 1014 if (rc) {
d6e04ae6 1015 cFYI(1, ("Send error in write = %d", rc));
1da177e4 1016 *nbytes = 0;
d6e04ae6
SF
1017 } else {
1018 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1019 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1020 *nbytes = (*nbytes) << 16;
1021 *nbytes += le16_to_cpu(pSMBr->Count);
1022 }
1da177e4
LT
1023
1024 cifs_small_buf_release(pSMB);
1025
1026 /* Note: On -EAGAIN error only caller can retry on handle based calls
1027 since file handle passed in no longer valid */
1028
1029 return rc;
1030}
d6e04ae6
SF
1031
1032
1da177e4
LT
1033#endif /* CIFS_EXPERIMENTAL */
1034
1035int
1036CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1037 const __u16 smb_file_id, const __u64 len,
1038 const __u64 offset, const __u32 numUnlock,
1039 const __u32 numLock, const __u8 lockType, const int waitFlag)
1040{
1041 int rc = 0;
1042 LOCK_REQ *pSMB = NULL;
1043 LOCK_RSP *pSMBr = NULL;
1044 int bytes_returned;
1045 int timeout = 0;
1046 __u16 count;
1047
1048 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
46810cbf
SF
1049 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1050
1da177e4
LT
1051 if (rc)
1052 return rc;
1053
46810cbf
SF
1054 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1055
1da177e4
LT
1056 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1057 timeout = -1; /* no response expected */
1058 pSMB->Timeout = 0;
1059 } else if (waitFlag == TRUE) {
1060 timeout = 3; /* blocking operation, no timeout */
1061 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1062 } else {
1063 pSMB->Timeout = 0;
1064 }
1065
1066 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1067 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1068 pSMB->LockType = lockType;
1069 pSMB->AndXCommand = 0xFF; /* none */
1070 pSMB->Fid = smb_file_id; /* netfid stays le */
1071
1072 if((numLock != 0) || (numUnlock != 0)) {
1073 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1074 /* BB where to store pid high? */
1075 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1076 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1077 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1078 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1079 count = sizeof(LOCKING_ANDX_RANGE);
1080 } else {
1081 /* oplock break */
1082 count = 0;
1083 }
1084 pSMB->hdr.smb_buf_length += count;
1085 pSMB->ByteCount = cpu_to_le16(count);
1086
1087 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1088 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1089
1090 if (rc) {
1091 cFYI(1, ("Send error in Lock = %d", rc));
1092 }
46810cbf 1093 cifs_small_buf_release(pSMB);
1da177e4
LT
1094
1095 /* Note: On -EAGAIN error only caller can retry on handle based calls
1096 since file handle passed in no longer valid */
1097 return rc;
1098}
1099
1100int
1101CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1102{
1103 int rc = 0;
1104 CLOSE_REQ *pSMB = NULL;
1105 CLOSE_RSP *pSMBr = NULL;
1106 int bytes_returned;
1107 cFYI(1, ("In CIFSSMBClose"));
1108
1109/* do not retry on dead session on close */
1110 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1111 if(rc == -EAGAIN)
1112 return 0;
1113 if (rc)
1114 return rc;
1115
1116 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1117
1118 pSMB->FileID = (__u16) smb_file_id;
1119 pSMB->LastWriteTime = 0;
1120 pSMB->ByteCount = 0;
1121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1123 if (rc) {
1124 if(rc!=-EINTR) {
1125 /* EINTR is expected when user ctl-c to kill app */
1126 cERROR(1, ("Send error in Close = %d", rc));
1127 }
1128 }
1129
1130 cifs_small_buf_release(pSMB);
1131
1132 /* Since session is dead, file will be closed on server already */
1133 if(rc == -EAGAIN)
1134 rc = 0;
1135
1136 return rc;
1137}
1138
1139int
1140CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1141 const char *fromName, const char *toName,
737b758c 1142 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1143{
1144 int rc = 0;
1145 RENAME_REQ *pSMB = NULL;
1146 RENAME_RSP *pSMBr = NULL;
1147 int bytes_returned;
1148 int name_len, name_len2;
1149 __u16 count;
1150
1151 cFYI(1, ("In CIFSSMBRename"));
1152renameRetry:
1153 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1154 (void **) &pSMBr);
1155 if (rc)
1156 return rc;
1157
1158 pSMB->BufferFormat = 0x04;
1159 pSMB->SearchAttributes =
1160 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1161 ATTR_DIRECTORY);
1162
1163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1164 name_len =
b1a45695 1165 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
737b758c 1166 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1167 name_len++; /* trailing null */
1168 name_len *= 2;
1169 pSMB->OldFileName[name_len] = 0x04; /* pad */
1170 /* protocol requires ASCII signature byte on Unicode string */
1171 pSMB->OldFileName[name_len + 1] = 0x00;
1172 name_len2 =
b1a45695 1173 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
737b758c 1174 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1175 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1176 name_len2 *= 2; /* convert to bytes */
1177 } else { /* BB improve the check for buffer overruns BB */
1178 name_len = strnlen(fromName, PATH_MAX);
1179 name_len++; /* trailing null */
1180 strncpy(pSMB->OldFileName, fromName, name_len);
1181 name_len2 = strnlen(toName, PATH_MAX);
1182 name_len2++; /* trailing null */
1183 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1184 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1185 name_len2++; /* trailing null */
1186 name_len2++; /* signature byte */
1187 }
1188
1189 count = 1 /* 1st signature byte */ + name_len + name_len2;
1190 pSMB->hdr.smb_buf_length += count;
1191 pSMB->ByteCount = cpu_to_le16(count);
1192
1193 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1194 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1195 if (rc) {
1196 cFYI(1, ("Send error in rename = %d", rc));
1197 }
1198
1199#ifdef CONFIG_CIFS_STATS
1200 else {
1201 atomic_inc(&tcon->num_renames);
1202 }
1203#endif
1204
1205 cifs_buf_release(pSMB);
1206
1207 if (rc == -EAGAIN)
1208 goto renameRetry;
1209
1210 return rc;
1211}
1212
1213int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
737b758c
SF
1214 int netfid, char * target_name,
1215 const struct nls_table * nls_codepage, int remap)
1da177e4
LT
1216{
1217 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1218 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1219 struct set_file_rename * rename_info;
1220 char *data_offset;
1221 char dummy_string[30];
1222 int rc = 0;
1223 int bytes_returned = 0;
1224 int len_of_str;
1225 __u16 params, param_offset, offset, count, byte_count;
1226
1227 cFYI(1, ("Rename to File by handle"));
1228 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1229 (void **) &pSMBr);
1230 if (rc)
1231 return rc;
1232
1233 params = 6;
1234 pSMB->MaxSetupCount = 0;
1235 pSMB->Reserved = 0;
1236 pSMB->Flags = 0;
1237 pSMB->Timeout = 0;
1238 pSMB->Reserved2 = 0;
1239 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1240 offset = param_offset + params;
1241
1242 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1243 rename_info = (struct set_file_rename *) data_offset;
1244 pSMB->MaxParameterCount = cpu_to_le16(2);
1245 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1246 pSMB->SetupCount = 1;
1247 pSMB->Reserved3 = 0;
1248 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1249 byte_count = 3 /* pad */ + params;
1250 pSMB->ParameterCount = cpu_to_le16(params);
1251 pSMB->TotalParameterCount = pSMB->ParameterCount;
1252 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1253 pSMB->DataOffset = cpu_to_le16(offset);
1254 /* construct random name ".cifs_tmp<inodenum><mid>" */
1255 rename_info->overwrite = cpu_to_le32(1);
1256 rename_info->root_fid = 0;
1257 /* unicode only call */
1258 if(target_name == NULL) {
1259 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
b1a45695 1260 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
737b758c 1261 dummy_string, 24, nls_codepage, remap);
1da177e4 1262 } else {
b1a45695 1263 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
737b758c 1264 target_name, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1265 }
1266 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1267 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1268 byte_count += count;
1269 pSMB->DataCount = cpu_to_le16(count);
1270 pSMB->TotalDataCount = pSMB->DataCount;
1271 pSMB->Fid = netfid;
1272 pSMB->InformationLevel =
1273 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1274 pSMB->Reserved4 = 0;
1275 pSMB->hdr.smb_buf_length += byte_count;
1276 pSMB->ByteCount = cpu_to_le16(byte_count);
1277 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1278 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1279 if (rc) {
1280 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1281 }
1282#ifdef CONFIG_CIFS_STATS
1283 else {
1284 atomic_inc(&pTcon->num_t2renames);
1285 }
1286#endif
1287 cifs_buf_release(pSMB);
1288
1289 /* Note: On -EAGAIN error only caller can retry on handle based calls
1290 since file handle passed in no longer valid */
1291
1292 return rc;
1293}
1294
1295int
1296CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1297 const __u16 target_tid, const char *toName, const int flags,
737b758c 1298 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1299{
1300 int rc = 0;
1301 COPY_REQ *pSMB = NULL;
1302 COPY_RSP *pSMBr = NULL;
1303 int bytes_returned;
1304 int name_len, name_len2;
1305 __u16 count;
1306
1307 cFYI(1, ("In CIFSSMBCopy"));
1308copyRetry:
1309 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1310 (void **) &pSMBr);
1311 if (rc)
1312 return rc;
1313
1314 pSMB->BufferFormat = 0x04;
1315 pSMB->Tid2 = target_tid;
1316
1317 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1318
1319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
b1a45695 1320 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
737b758c
SF
1321 fromName, PATH_MAX, nls_codepage,
1322 remap);
1da177e4
LT
1323 name_len++; /* trailing null */
1324 name_len *= 2;
1325 pSMB->OldFileName[name_len] = 0x04; /* pad */
1326 /* protocol requires ASCII signature byte on Unicode string */
1327 pSMB->OldFileName[name_len + 1] = 0x00;
b1a45695 1328 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 1329 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1330 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1331 name_len2 *= 2; /* convert to bytes */
1332 } else { /* BB improve the check for buffer overruns BB */
1333 name_len = strnlen(fromName, PATH_MAX);
1334 name_len++; /* trailing null */
1335 strncpy(pSMB->OldFileName, fromName, name_len);
1336 name_len2 = strnlen(toName, PATH_MAX);
1337 name_len2++; /* trailing null */
1338 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1339 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1340 name_len2++; /* trailing null */
1341 name_len2++; /* signature byte */
1342 }
1343
1344 count = 1 /* 1st signature byte */ + name_len + name_len2;
1345 pSMB->hdr.smb_buf_length += count;
1346 pSMB->ByteCount = cpu_to_le16(count);
1347
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1350 if (rc) {
1351 cFYI(1, ("Send error in copy = %d with %d files copied",
1352 rc, le16_to_cpu(pSMBr->CopyCount)));
1353 }
1354 if (pSMB)
1355 cifs_buf_release(pSMB);
1356
1357 if (rc == -EAGAIN)
1358 goto copyRetry;
1359
1360 return rc;
1361}
1362
1363int
1364CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1365 const char *fromName, const char *toName,
1366 const struct nls_table *nls_codepage)
1367{
1368 TRANSACTION2_SPI_REQ *pSMB = NULL;
1369 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1370 char *data_offset;
1371 int name_len;
1372 int name_len_target;
1373 int rc = 0;
1374 int bytes_returned = 0;
1375 __u16 params, param_offset, offset, byte_count;
1376
1377 cFYI(1, ("In Symlink Unix style"));
1378createSymLinkRetry:
1379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1380 (void **) &pSMBr);
1381 if (rc)
1382 return rc;
1383
1384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1385 name_len =
1386 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1387 /* find define for this maxpathcomponent */
1388 , nls_codepage);
1389 name_len++; /* trailing null */
1390 name_len *= 2;
1391
1392 } else { /* BB improve the check for buffer overruns BB */
1393 name_len = strnlen(fromName, PATH_MAX);
1394 name_len++; /* trailing null */
1395 strncpy(pSMB->FileName, fromName, name_len);
1396 }
1397 params = 6 + name_len;
1398 pSMB->MaxSetupCount = 0;
1399 pSMB->Reserved = 0;
1400 pSMB->Flags = 0;
1401 pSMB->Timeout = 0;
1402 pSMB->Reserved2 = 0;
1403 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1404 InformationLevel) - 4;
1405 offset = param_offset + params;
1406
1407 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1408 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1409 name_len_target =
1410 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1411 /* find define for this maxpathcomponent */
1412 , nls_codepage);
1413 name_len_target++; /* trailing null */
1414 name_len_target *= 2;
1415 } else { /* BB improve the check for buffer overruns BB */
1416 name_len_target = strnlen(toName, PATH_MAX);
1417 name_len_target++; /* trailing null */
1418 strncpy(data_offset, toName, name_len_target);
1419 }
1420
1421 pSMB->MaxParameterCount = cpu_to_le16(2);
1422 /* BB find exact max on data count below from sess */
1423 pSMB->MaxDataCount = cpu_to_le16(1000);
1424 pSMB->SetupCount = 1;
1425 pSMB->Reserved3 = 0;
1426 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1427 byte_count = 3 /* pad */ + params + name_len_target;
1428 pSMB->DataCount = cpu_to_le16(name_len_target);
1429 pSMB->ParameterCount = cpu_to_le16(params);
1430 pSMB->TotalDataCount = pSMB->DataCount;
1431 pSMB->TotalParameterCount = pSMB->ParameterCount;
1432 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1433 pSMB->DataOffset = cpu_to_le16(offset);
1434 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1435 pSMB->Reserved4 = 0;
1436 pSMB->hdr.smb_buf_length += byte_count;
1437 pSMB->ByteCount = cpu_to_le16(byte_count);
1438 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1439 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1440 if (rc) {
1441 cFYI(1,
1442 ("Send error in SetPathInfo (create symlink) = %d",
1443 rc));
1444 }
1445
1446 if (pSMB)
1447 cifs_buf_release(pSMB);
1448
1449 if (rc == -EAGAIN)
1450 goto createSymLinkRetry;
1451
1452 return rc;
1453}
1454
1455int
1456CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1457 const char *fromName, const char *toName,
737b758c 1458 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1459{
1460 TRANSACTION2_SPI_REQ *pSMB = NULL;
1461 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1462 char *data_offset;
1463 int name_len;
1464 int name_len_target;
1465 int rc = 0;
1466 int bytes_returned = 0;
1467 __u16 params, param_offset, offset, byte_count;
1468
1469 cFYI(1, ("In Create Hard link Unix style"));
1470createHardLinkRetry:
1471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1472 (void **) &pSMBr);
1473 if (rc)
1474 return rc;
1475
1476 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
b1a45695 1477 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
737b758c 1478 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1479 name_len++; /* trailing null */
1480 name_len *= 2;
1481
1482 } else { /* BB improve the check for buffer overruns BB */
1483 name_len = strnlen(toName, PATH_MAX);
1484 name_len++; /* trailing null */
1485 strncpy(pSMB->FileName, toName, name_len);
1486 }
1487 params = 6 + name_len;
1488 pSMB->MaxSetupCount = 0;
1489 pSMB->Reserved = 0;
1490 pSMB->Flags = 0;
1491 pSMB->Timeout = 0;
1492 pSMB->Reserved2 = 0;
1493 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1494 InformationLevel) - 4;
1495 offset = param_offset + params;
1496
1497 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1498 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1499 name_len_target =
b1a45695 1500 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
737b758c 1501 nls_codepage, remap);
1da177e4
LT
1502 name_len_target++; /* trailing null */
1503 name_len_target *= 2;
1504 } else { /* BB improve the check for buffer overruns BB */
1505 name_len_target = strnlen(fromName, PATH_MAX);
1506 name_len_target++; /* trailing null */
1507 strncpy(data_offset, fromName, name_len_target);
1508 }
1509
1510 pSMB->MaxParameterCount = cpu_to_le16(2);
1511 /* BB find exact max on data count below from sess*/
1512 pSMB->MaxDataCount = cpu_to_le16(1000);
1513 pSMB->SetupCount = 1;
1514 pSMB->Reserved3 = 0;
1515 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1516 byte_count = 3 /* pad */ + params + name_len_target;
1517 pSMB->ParameterCount = cpu_to_le16(params);
1518 pSMB->TotalParameterCount = pSMB->ParameterCount;
1519 pSMB->DataCount = cpu_to_le16(name_len_target);
1520 pSMB->TotalDataCount = pSMB->DataCount;
1521 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1522 pSMB->DataOffset = cpu_to_le16(offset);
1523 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1524 pSMB->Reserved4 = 0;
1525 pSMB->hdr.smb_buf_length += byte_count;
1526 pSMB->ByteCount = cpu_to_le16(byte_count);
1527 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1528 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1529 if (rc) {
1530 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1531 }
1532
1533 cifs_buf_release(pSMB);
1534 if (rc == -EAGAIN)
1535 goto createHardLinkRetry;
1536
1537 return rc;
1538}
1539
1540int
1541CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1542 const char *fromName, const char *toName,
737b758c 1543 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1544{
1545 int rc = 0;
1546 NT_RENAME_REQ *pSMB = NULL;
1547 RENAME_RSP *pSMBr = NULL;
1548 int bytes_returned;
1549 int name_len, name_len2;
1550 __u16 count;
1551
1552 cFYI(1, ("In CIFSCreateHardLink"));
1553winCreateHardLinkRetry:
1554
1555 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1556 (void **) &pSMBr);
1557 if (rc)
1558 return rc;
1559
1560 pSMB->SearchAttributes =
1561 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1562 ATTR_DIRECTORY);
1563 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1564 pSMB->ClusterCount = 0;
1565
1566 pSMB->BufferFormat = 0x04;
1567
1568 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1569 name_len =
b1a45695 1570 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
737b758c 1571 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1572 name_len++; /* trailing null */
1573 name_len *= 2;
1574 pSMB->OldFileName[name_len] = 0; /* pad */
1575 pSMB->OldFileName[name_len + 1] = 0x04;
1576 name_len2 =
b1a45695 1577 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 1578 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1579 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1580 name_len2 *= 2; /* convert to bytes */
1581 } else { /* BB improve the check for buffer overruns BB */
1582 name_len = strnlen(fromName, PATH_MAX);
1583 name_len++; /* trailing null */
1584 strncpy(pSMB->OldFileName, fromName, name_len);
1585 name_len2 = strnlen(toName, PATH_MAX);
1586 name_len2++; /* trailing null */
1587 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1588 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1589 name_len2++; /* trailing null */
1590 name_len2++; /* signature byte */
1591 }
1592
1593 count = 1 /* string type byte */ + name_len + name_len2;
1594 pSMB->hdr.smb_buf_length += count;
1595 pSMB->ByteCount = cpu_to_le16(count);
1596
1597 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1598 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1599 if (rc) {
1600 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1601 }
1602 cifs_buf_release(pSMB);
1603 if (rc == -EAGAIN)
1604 goto winCreateHardLinkRetry;
1605
1606 return rc;
1607}
1608
1609int
1610CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1611 const unsigned char *searchName,
1612 char *symlinkinfo, const int buflen,
1613 const struct nls_table *nls_codepage)
1614{
1615/* SMB_QUERY_FILE_UNIX_LINK */
1616 TRANSACTION2_QPI_REQ *pSMB = NULL;
1617 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1618 int rc = 0;
1619 int bytes_returned;
1620 int name_len;
1621 __u16 params, byte_count;
1622
1623 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1624
1625querySymLinkRetry:
1626 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1627 (void **) &pSMBr);
1628 if (rc)
1629 return rc;
1630
1631 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1632 name_len =
1633 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1634 /* find define for this maxpathcomponent */
1635 , nls_codepage);
1636 name_len++; /* trailing null */
1637 name_len *= 2;
1638 } else { /* BB improve the check for buffer overruns BB */
1639 name_len = strnlen(searchName, PATH_MAX);
1640 name_len++; /* trailing null */
1641 strncpy(pSMB->FileName, searchName, name_len);
1642 }
1643
1644 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1645 pSMB->TotalDataCount = 0;
1646 pSMB->MaxParameterCount = cpu_to_le16(2);
1647 /* BB find exact max data count below from sess structure BB */
1648 pSMB->MaxDataCount = cpu_to_le16(4000);
1649 pSMB->MaxSetupCount = 0;
1650 pSMB->Reserved = 0;
1651 pSMB->Flags = 0;
1652 pSMB->Timeout = 0;
1653 pSMB->Reserved2 = 0;
1654 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1655 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1656 pSMB->DataCount = 0;
1657 pSMB->DataOffset = 0;
1658 pSMB->SetupCount = 1;
1659 pSMB->Reserved3 = 0;
1660 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1661 byte_count = params + 1 /* pad */ ;
1662 pSMB->TotalParameterCount = cpu_to_le16(params);
1663 pSMB->ParameterCount = pSMB->TotalParameterCount;
1664 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1665 pSMB->Reserved4 = 0;
1666 pSMB->hdr.smb_buf_length += byte_count;
1667 pSMB->ByteCount = cpu_to_le16(byte_count);
1668
1669 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1670 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1671 if (rc) {
1672 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1673 } else {
1674 /* decode response */
1675
1676 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1677 if (rc || (pSMBr->ByteCount < 2))
1678 /* BB also check enough total bytes returned */
1679 rc = -EIO; /* bad smb */
1680 else {
1681 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1682 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1683
1684 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1685 name_len = UniStrnlen((wchar_t *) ((char *)
1686 &pSMBr->hdr.Protocol +data_offset),
1687 min_t(const int, buflen,count) / 2);
737b758c 1688 /* BB FIXME investigate remapping reserved chars here */
1da177e4
LT
1689 cifs_strfromUCS_le(symlinkinfo,
1690 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1691 data_offset),
1692 name_len, nls_codepage);
1693 } else {
1694 strncpy(symlinkinfo,
1695 (char *) &pSMBr->hdr.Protocol +
1696 data_offset,
1697 min_t(const int, buflen, count));
1698 }
1699 symlinkinfo[buflen] = 0;
1700 /* just in case so calling code does not go off the end of buffer */
1701 }
1702 }
1703 cifs_buf_release(pSMB);
1704 if (rc == -EAGAIN)
1705 goto querySymLinkRetry;
1706 return rc;
1707}
1708
1709int
1710CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1711 const unsigned char *searchName,
1712 char *symlinkinfo, const int buflen,__u16 fid,
1713 const struct nls_table *nls_codepage)
1714{
1715 int rc = 0;
1716 int bytes_returned;
1717 int name_len;
1718 struct smb_com_transaction_ioctl_req * pSMB;
1719 struct smb_com_transaction_ioctl_rsp * pSMBr;
1720
1721 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1722 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1723 (void **) &pSMBr);
1724 if (rc)
1725 return rc;
1726
1727 pSMB->TotalParameterCount = 0 ;
1728 pSMB->TotalDataCount = 0;
1729 pSMB->MaxParameterCount = cpu_to_le32(2);
1730 /* BB find exact data count max from sess structure BB */
1731 pSMB->MaxDataCount = cpu_to_le32(4000);
1732 pSMB->MaxSetupCount = 4;
1733 pSMB->Reserved = 0;
1734 pSMB->ParameterOffset = 0;
1735 pSMB->DataCount = 0;
1736 pSMB->DataOffset = 0;
1737 pSMB->SetupCount = 4;
1738 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1739 pSMB->ParameterCount = pSMB->TotalParameterCount;
1740 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1741 pSMB->IsFsctl = 1; /* FSCTL */
1742 pSMB->IsRootFlag = 0;
1743 pSMB->Fid = fid; /* file handle always le */
1744 pSMB->ByteCount = 0;
1745
1746 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1747 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1748 if (rc) {
1749 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1750 } else { /* decode response */
1751 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1752 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1753 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1754 /* BB also check enough total bytes returned */
1755 rc = -EIO; /* bad smb */
1756 else {
1757 if(data_count && (data_count < 2048)) {
1758 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1759
1760 struct reparse_data * reparse_buf = (struct reparse_data *)
1761 ((char *)&pSMBr->hdr.Protocol + data_offset);
1762 if((char*)reparse_buf >= end_of_smb) {
1763 rc = -EIO;
1764 goto qreparse_out;
1765 }
1766 if((reparse_buf->LinkNamesBuf +
1767 reparse_buf->TargetNameOffset +
1768 reparse_buf->TargetNameLen) >
1769 end_of_smb) {
1770 cFYI(1,("reparse buf extended beyond SMB"));
1771 rc = -EIO;
1772 goto qreparse_out;
1773 }
1774
1775 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1776 name_len = UniStrnlen((wchar_t *)
1777 (reparse_buf->LinkNamesBuf +
1778 reparse_buf->TargetNameOffset),
1779 min(buflen/2, reparse_buf->TargetNameLen / 2));
1780 cifs_strfromUCS_le(symlinkinfo,
1781 (wchar_t *) (reparse_buf->LinkNamesBuf +
1782 reparse_buf->TargetNameOffset),
1783 name_len, nls_codepage);
1784 } else { /* ASCII names */
1785 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1786 reparse_buf->TargetNameOffset,
1787 min_t(const int, buflen, reparse_buf->TargetNameLen));
1788 }
1789 } else {
1790 rc = -EIO;
1791 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1792 }
1793 symlinkinfo[buflen] = 0; /* just in case so the caller
1794 does not go off the end of the buffer */
1795 cFYI(1,("readlink result - %s ",symlinkinfo));
1796 }
1797 }
1798qreparse_out:
1799 if (pSMB)
1800 cifs_buf_release(pSMB);
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
2523 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2524 /* BB Add code to handle unsupported level rc */
2525 cFYI(1, ("Error in FindFirst = %d", rc));
2526
2527 if (pSMB)
2528 cifs_buf_release(pSMB);
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;
2862
2863 pSMB->hdr.Tid = ses->ipc_tid;
2864 pSMB->hdr.Uid = ses->Suid;
2865 if (ses->capabilities & CAP_STATUS32) {
2866 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2867 }
2868 if (ses->capabilities & CAP_DFS) {
2869 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2870 }
2871
2872 if (ses->capabilities & CAP_UNICODE) {
2873 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2874 name_len =
b1a45695 2875 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
737b758c 2876 searchName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2877 name_len++; /* trailing null */
2878 name_len *= 2;
2879 } else { /* BB improve the check for buffer overruns BB */
2880 name_len = strnlen(searchName, PATH_MAX);
2881 name_len++; /* trailing null */
2882 strncpy(pSMB->RequestFileName, searchName, name_len);
2883 }
2884
2885 params = 2 /* level */ + name_len /*includes null */ ;
2886 pSMB->TotalDataCount = 0;
2887 pSMB->DataCount = 0;
2888 pSMB->DataOffset = 0;
2889 pSMB->MaxParameterCount = 0;
2890 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2891 pSMB->MaxSetupCount = 0;
2892 pSMB->Reserved = 0;
2893 pSMB->Flags = 0;
2894 pSMB->Timeout = 0;
2895 pSMB->Reserved2 = 0;
2896 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2897 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2898 pSMB->SetupCount = 1;
2899 pSMB->Reserved3 = 0;
2900 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2901 byte_count = params + 3 /* pad */ ;
2902 pSMB->ParameterCount = cpu_to_le16(params);
2903 pSMB->TotalParameterCount = pSMB->ParameterCount;
2904 pSMB->MaxReferralLevel = cpu_to_le16(3);
2905 pSMB->hdr.smb_buf_length += byte_count;
2906 pSMB->ByteCount = cpu_to_le16(byte_count);
2907
2908 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2910 if (rc) {
2911 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2912 } else { /* decode response */
2913/* BB Add logic to parse referrals here */
2914 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2915
2916 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
2917 rc = -EIO; /* bad smb */
2918 else {
2919 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2920 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2921
2922 cFYI(1,
2923 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
2924 pSMBr->ByteCount, data_offset));
2925 referrals =
2926 (struct dfs_referral_level_3 *)
2927 (8 /* sizeof start of data block */ +
2928 data_offset +
2929 (char *) &pSMBr->hdr.Protocol);
2930 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",
2931 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)));
2932 /* BB This field is actually two bytes in from start of
2933 data block so we could do safety check that DataBlock
2934 begins at address of pSMBr->NumberOfReferrals */
2935 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2936
2937 /* BB Fix below so can return more than one referral */
2938 if(*number_of_UNC_in_array > 1)
2939 *number_of_UNC_in_array = 1;
2940
2941 /* get the length of the strings describing refs */
2942 name_len = 0;
2943 for(i=0;i<*number_of_UNC_in_array;i++) {
2944 /* make sure that DfsPathOffset not past end */
2945 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2946 if (offset > data_count) {
2947 /* if invalid referral, stop here and do
2948 not try to copy any more */
2949 *number_of_UNC_in_array = i;
2950 break;
2951 }
2952 temp = ((char *)referrals) + offset;
2953
2954 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2955 name_len += UniStrnlen((wchar_t *)temp,data_count);
2956 } else {
2957 name_len += strnlen(temp,data_count);
2958 }
2959 referrals++;
2960 /* BB add check that referral pointer does not fall off end PDU */
2961
2962 }
2963 /* BB add check for name_len bigger than bcc */
2964 *targetUNCs =
2965 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2966 if(*targetUNCs == NULL) {
2967 rc = -ENOMEM;
2968 goto GetDFSRefExit;
2969 }
2970 /* copy the ref strings */
2971 referrals =
2972 (struct dfs_referral_level_3 *)
2973 (8 /* sizeof data hdr */ +
2974 data_offset +
2975 (char *) &pSMBr->hdr.Protocol);
2976
2977 for(i=0;i<*number_of_UNC_in_array;i++) {
2978 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2979 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2980 cifs_strfromUCS_le(*targetUNCs,
2981 (wchar_t *) temp, name_len, nls_codepage);
2982 } else {
2983 strncpy(*targetUNCs,temp,name_len);
2984 }
2985 /* BB update target_uncs pointers */
2986 referrals++;
2987 }
2988 temp = *targetUNCs;
2989 temp[name_len] = 0;
2990 }
2991
2992 }
2993GetDFSRefExit:
2994 if (pSMB)
2995 cifs_buf_release(pSMB);
2996
2997 if (rc == -EAGAIN)
2998 goto getDFSRetry;
2999
3000 return rc;
3001}
3002
3003int
737b758c 3004CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
1da177e4
LT
3005{
3006/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3007 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3008 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3009 FILE_SYSTEM_INFO *response_data;
3010 int rc = 0;
3011 int bytes_returned = 0;
3012 __u16 params, byte_count;
3013
3014 cFYI(1, ("In QFSInfo"));
3015QFSInfoRetry:
3016 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3017 (void **) &pSMBr);
3018 if (rc)
3019 return rc;
3020
3021 params = 2; /* level */
3022 pSMB->TotalDataCount = 0;
3023 pSMB->MaxParameterCount = cpu_to_le16(2);
3024 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3025 pSMB->MaxSetupCount = 0;
3026 pSMB->Reserved = 0;
3027 pSMB->Flags = 0;
3028 pSMB->Timeout = 0;
3029 pSMB->Reserved2 = 0;
3030 byte_count = params + 1 /* pad */ ;
3031 pSMB->TotalParameterCount = cpu_to_le16(params);
3032 pSMB->ParameterCount = pSMB->TotalParameterCount;
3033 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3034 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3035 pSMB->DataCount = 0;
3036 pSMB->DataOffset = 0;
3037 pSMB->SetupCount = 1;
3038 pSMB->Reserved3 = 0;
3039 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3040 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3041 pSMB->hdr.smb_buf_length += byte_count;
3042 pSMB->ByteCount = cpu_to_le16(byte_count);
3043
3044 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3045 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3046 if (rc) {
3047 cERROR(1, ("Send error in QFSInfo = %d", rc));
3048 } else { /* decode response */
3049 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3050
3051 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3052 rc = -EIO; /* bad smb */
3053 else {
3054 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3055 cFYI(1,
3056 ("Decoding qfsinfo response. BCC: %d Offset %d",
3057 pSMBr->ByteCount, data_offset));
3058
3059 response_data =
3060 (FILE_SYSTEM_INFO
3061 *) (((char *) &pSMBr->hdr.Protocol) +
3062 data_offset);
3063 FSData->f_bsize =
3064 le32_to_cpu(response_data->BytesPerSector) *
3065 le32_to_cpu(response_data->
3066 SectorsPerAllocationUnit);
3067 FSData->f_blocks =
3068 le64_to_cpu(response_data->TotalAllocationUnits);
3069 FSData->f_bfree = FSData->f_bavail =
3070 le64_to_cpu(response_data->FreeAllocationUnits);
3071 cFYI(1,
3072 ("Blocks: %lld Free: %lld Block size %ld",
3073 (unsigned long long)FSData->f_blocks,
3074 (unsigned long long)FSData->f_bfree,
3075 FSData->f_bsize));
3076 }
3077 }
3078 cifs_buf_release(pSMB);
3079
3080 if (rc == -EAGAIN)
3081 goto QFSInfoRetry;
3082
3083 return rc;
3084}
3085
3086int
737b758c 3087CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
3088{
3089/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3090 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3091 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3092 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3093 int rc = 0;
3094 int bytes_returned = 0;
3095 __u16 params, byte_count;
3096
3097 cFYI(1, ("In QFSAttributeInfo"));
3098QFSAttributeRetry:
3099 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3100 (void **) &pSMBr);
3101 if (rc)
3102 return rc;
3103
3104 params = 2; /* level */
3105 pSMB->TotalDataCount = 0;
3106 pSMB->MaxParameterCount = cpu_to_le16(2);
3107 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3108 pSMB->MaxSetupCount = 0;
3109 pSMB->Reserved = 0;
3110 pSMB->Flags = 0;
3111 pSMB->Timeout = 0;
3112 pSMB->Reserved2 = 0;
3113 byte_count = params + 1 /* pad */ ;
3114 pSMB->TotalParameterCount = cpu_to_le16(params);
3115 pSMB->ParameterCount = pSMB->TotalParameterCount;
3116 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3117 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3118 pSMB->DataCount = 0;
3119 pSMB->DataOffset = 0;
3120 pSMB->SetupCount = 1;
3121 pSMB->Reserved3 = 0;
3122 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3123 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3124 pSMB->hdr.smb_buf_length += byte_count;
3125 pSMB->ByteCount = cpu_to_le16(byte_count);
3126
3127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3129 if (rc) {
3130 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3131 } else { /* decode response */
3132 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3133
3134 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3135 rc = -EIO; /* bad smb */
3136 } else {
3137 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3138 response_data =
3139 (FILE_SYSTEM_ATTRIBUTE_INFO
3140 *) (((char *) &pSMBr->hdr.Protocol) +
3141 data_offset);
3142 memcpy(&tcon->fsAttrInfo, response_data,
3143 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3144 }
3145 }
3146 cifs_buf_release(pSMB);
3147
3148 if (rc == -EAGAIN)
3149 goto QFSAttributeRetry;
3150
3151 return rc;
3152}
3153
3154int
737b758c 3155CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
3156{
3157/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3158 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3159 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3160 FILE_SYSTEM_DEVICE_INFO *response_data;
3161 int rc = 0;
3162 int bytes_returned = 0;
3163 __u16 params, byte_count;
3164
3165 cFYI(1, ("In QFSDeviceInfo"));
3166QFSDeviceRetry:
3167 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3168 (void **) &pSMBr);
3169 if (rc)
3170 return rc;
3171
3172 params = 2; /* level */
3173 pSMB->TotalDataCount = 0;
3174 pSMB->MaxParameterCount = cpu_to_le16(2);
3175 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3176 pSMB->MaxSetupCount = 0;
3177 pSMB->Reserved = 0;
3178 pSMB->Flags = 0;
3179 pSMB->Timeout = 0;
3180 pSMB->Reserved2 = 0;
3181 byte_count = params + 1 /* pad */ ;
3182 pSMB->TotalParameterCount = cpu_to_le16(params);
3183 pSMB->ParameterCount = pSMB->TotalParameterCount;
3184 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3185 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3186
3187 pSMB->DataCount = 0;
3188 pSMB->DataOffset = 0;
3189 pSMB->SetupCount = 1;
3190 pSMB->Reserved3 = 0;
3191 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3192 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3193 pSMB->hdr.smb_buf_length += byte_count;
3194 pSMB->ByteCount = cpu_to_le16(byte_count);
3195
3196 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3198 if (rc) {
3199 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3200 } else { /* decode response */
3201 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3202
3203 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3204 rc = -EIO; /* bad smb */
3205 else {
3206 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3207 response_data =
737b758c
SF
3208 (FILE_SYSTEM_DEVICE_INFO *)
3209 (((char *) &pSMBr->hdr.Protocol) +
1da177e4
LT
3210 data_offset);
3211 memcpy(&tcon->fsDevInfo, response_data,
3212 sizeof (FILE_SYSTEM_DEVICE_INFO));
3213 }
3214 }
3215 cifs_buf_release(pSMB);
3216
3217 if (rc == -EAGAIN)
3218 goto QFSDeviceRetry;
3219
3220 return rc;
3221}
3222
3223int
737b758c 3224CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
3225{
3226/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3227 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3228 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3229 FILE_SYSTEM_UNIX_INFO *response_data;
3230 int rc = 0;
3231 int bytes_returned = 0;
3232 __u16 params, byte_count;
3233
3234 cFYI(1, ("In QFSUnixInfo"));
3235QFSUnixRetry:
3236 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3237 (void **) &pSMBr);
3238 if (rc)
3239 return rc;
3240
3241 params = 2; /* level */
3242 pSMB->TotalDataCount = 0;
3243 pSMB->DataCount = 0;
3244 pSMB->DataOffset = 0;
3245 pSMB->MaxParameterCount = cpu_to_le16(2);
3246 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3247 pSMB->MaxSetupCount = 0;
3248 pSMB->Reserved = 0;
3249 pSMB->Flags = 0;
3250 pSMB->Timeout = 0;
3251 pSMB->Reserved2 = 0;
3252 byte_count = params + 1 /* pad */ ;
3253 pSMB->ParameterCount = cpu_to_le16(params);
3254 pSMB->TotalParameterCount = pSMB->ParameterCount;
3255 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3256 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3257 pSMB->SetupCount = 1;
3258 pSMB->Reserved3 = 0;
3259 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3260 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3261 pSMB->hdr.smb_buf_length += byte_count;
3262 pSMB->ByteCount = cpu_to_le16(byte_count);
3263
3264 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3265 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3266 if (rc) {
3267 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3268 } else { /* decode response */
3269 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3270
3271 if (rc || (pSMBr->ByteCount < 13)) {
3272 rc = -EIO; /* bad smb */
3273 } else {
3274 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3275 response_data =
3276 (FILE_SYSTEM_UNIX_INFO
3277 *) (((char *) &pSMBr->hdr.Protocol) +
3278 data_offset);
3279 memcpy(&tcon->fsUnixInfo, response_data,
3280 sizeof (FILE_SYSTEM_UNIX_INFO));
3281 }
3282 }
3283 cifs_buf_release(pSMB);
3284
3285 if (rc == -EAGAIN)
3286 goto QFSUnixRetry;
3287
3288
3289 return rc;
3290}
3291
ac67055e 3292int
45abc6ee 3293CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
ac67055e
JA
3294{
3295/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3296 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3297 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3298 int rc = 0;
3299 int bytes_returned = 0;
3300 __u16 params, param_offset, offset, byte_count;
3301
3302 cFYI(1, ("In SETFSUnixInfo"));
3303SETFSUnixRetry:
3304 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3305 (void **) &pSMBr);
3306 if (rc)
3307 return rc;
3308
3309 params = 4; /* 2 bytes zero followed by info level. */
3310 pSMB->MaxSetupCount = 0;
3311 pSMB->Reserved = 0;
3312 pSMB->Flags = 0;
3313 pSMB->Timeout = 0;
3314 pSMB->Reserved2 = 0;
3315 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3316 offset = param_offset + params;
3317
3318 pSMB->MaxParameterCount = cpu_to_le16(4);
3319 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3320 pSMB->SetupCount = 1;
3321 pSMB->Reserved3 = 0;
3322 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3323 byte_count = 1 /* pad */ + params + 12;
3324
3325 pSMB->DataCount = cpu_to_le16(12);
3326 pSMB->ParameterCount = cpu_to_le16(params);
3327 pSMB->TotalDataCount = pSMB->DataCount;
3328 pSMB->TotalParameterCount = pSMB->ParameterCount;
3329 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3330 pSMB->DataOffset = cpu_to_le16(offset);
3331
3332 /* Params. */
3333 pSMB->FileNum = 0;
3334 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3335
3336 /* Data. */
3337 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3338 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3339 pSMB->ClientUnixCap = cpu_to_le64(cap);
3340
3341 pSMB->hdr.smb_buf_length += byte_count;
3342 pSMB->ByteCount = cpu_to_le16(byte_count);
3343
3344 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3345 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3346 if (rc) {
3347 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3348 } else { /* decode response */
3349 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3350 if (rc) {
3351 rc = -EIO; /* bad smb */
3352 }
3353 }
3354 cifs_buf_release(pSMB);
3355
3356 if (rc == -EAGAIN)
3357 goto SETFSUnixRetry;
3358
3359 return rc;
3360}
3361
3362
1da177e4
LT
3363
3364int
3365CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
737b758c 3366 struct kstatfs *FSData)
1da177e4
LT
3367{
3368/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3369 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3370 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3371 FILE_SYSTEM_POSIX_INFO *response_data;
3372 int rc = 0;
3373 int bytes_returned = 0;
3374 __u16 params, byte_count;
3375
3376 cFYI(1, ("In QFSPosixInfo"));
3377QFSPosixRetry:
3378 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3379 (void **) &pSMBr);
3380 if (rc)
3381 return rc;
3382
3383 params = 2; /* level */
3384 pSMB->TotalDataCount = 0;
3385 pSMB->DataCount = 0;
3386 pSMB->DataOffset = 0;
3387 pSMB->MaxParameterCount = cpu_to_le16(2);
3388 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3389 pSMB->MaxSetupCount = 0;
3390 pSMB->Reserved = 0;
3391 pSMB->Flags = 0;
3392 pSMB->Timeout = 0;
3393 pSMB->Reserved2 = 0;
3394 byte_count = params + 1 /* pad */ ;
3395 pSMB->ParameterCount = cpu_to_le16(params);
3396 pSMB->TotalParameterCount = pSMB->ParameterCount;
3397 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3398 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3399 pSMB->SetupCount = 1;
3400 pSMB->Reserved3 = 0;
3401 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3402 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3403 pSMB->hdr.smb_buf_length += byte_count;
3404 pSMB->ByteCount = cpu_to_le16(byte_count);
3405
3406 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3408 if (rc) {
3409 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3410 } else { /* decode response */
3411 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3412
3413 if (rc || (pSMBr->ByteCount < 13)) {
3414 rc = -EIO; /* bad smb */
3415 } else {
3416 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3417 response_data =
3418 (FILE_SYSTEM_POSIX_INFO
3419 *) (((char *) &pSMBr->hdr.Protocol) +
3420 data_offset);
3421 FSData->f_bsize =
3422 le32_to_cpu(response_data->BlockSize);
3423 FSData->f_blocks =
3424 le64_to_cpu(response_data->TotalBlocks);
3425 FSData->f_bfree =
3426 le64_to_cpu(response_data->BlocksAvail);
3427 if(response_data->UserBlocksAvail == -1) {
3428 FSData->f_bavail = FSData->f_bfree;
3429 } else {
3430 FSData->f_bavail =
3431 le64_to_cpu(response_data->UserBlocksAvail);
3432 }
3433 if(response_data->TotalFileNodes != -1)
3434 FSData->f_files =
3435 le64_to_cpu(response_data->TotalFileNodes);
3436 if(response_data->FreeFileNodes != -1)
3437 FSData->f_ffree =
3438 le64_to_cpu(response_data->FreeFileNodes);
3439 }
3440 }
3441 cifs_buf_release(pSMB);
3442
3443 if (rc == -EAGAIN)
3444 goto QFSPosixRetry;
3445
3446 return rc;
3447}
3448
3449
3450/* We can not use write of zero bytes trick to
3451 set file size due to need for large file support. Also note that
3452 this SetPathInfo is preferred to SetFileInfo based method in next
3453 routine which is only needed to work around a sharing violation bug
3454 in Samba which this routine can run into */
3455
3456int
3457CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
737b758c
SF
3458 __u64 size, int SetAllocation,
3459 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3460{
3461 struct smb_com_transaction2_spi_req *pSMB = NULL;
3462 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3463 struct file_end_of_file_info *parm_data;
3464 int name_len;
3465 int rc = 0;
3466 int bytes_returned = 0;
3467 __u16 params, byte_count, data_count, param_offset, offset;
3468
3469 cFYI(1, ("In SetEOF"));
3470SetEOFRetry:
3471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3472 (void **) &pSMBr);
3473 if (rc)
3474 return rc;
3475
3476 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3477 name_len =
b1a45695 3478 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 3479 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3480 name_len++; /* trailing null */
3481 name_len *= 2;
3482 } else { /* BB improve the check for buffer overruns BB */
3483 name_len = strnlen(fileName, PATH_MAX);
3484 name_len++; /* trailing null */
3485 strncpy(pSMB->FileName, fileName, name_len);
3486 }
3487 params = 6 + name_len;
3488 data_count = sizeof (struct file_end_of_file_info);
3489 pSMB->MaxParameterCount = cpu_to_le16(2);
3490 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3491 pSMB->MaxSetupCount = 0;
3492 pSMB->Reserved = 0;
3493 pSMB->Flags = 0;
3494 pSMB->Timeout = 0;
3495 pSMB->Reserved2 = 0;
3496 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3497 InformationLevel) - 4;
3498 offset = param_offset + params;
3499 if(SetAllocation) {
3500 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3501 pSMB->InformationLevel =
3502 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3503 else
3504 pSMB->InformationLevel =
3505 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3506 } else /* Set File Size */ {
3507 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3508 pSMB->InformationLevel =
3509 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3510 else
3511 pSMB->InformationLevel =
3512 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3513 }
3514
3515 parm_data =
3516 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3517 offset);
3518 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3519 pSMB->DataOffset = cpu_to_le16(offset);
3520 pSMB->SetupCount = 1;
3521 pSMB->Reserved3 = 0;
3522 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3523 byte_count = 3 /* pad */ + params + data_count;
3524 pSMB->DataCount = cpu_to_le16(data_count);
3525 pSMB->TotalDataCount = pSMB->DataCount;
3526 pSMB->ParameterCount = cpu_to_le16(params);
3527 pSMB->TotalParameterCount = pSMB->ParameterCount;
3528 pSMB->Reserved4 = 0;
3529 pSMB->hdr.smb_buf_length += byte_count;
3530 parm_data->FileSize = cpu_to_le64(size);
3531 pSMB->ByteCount = cpu_to_le16(byte_count);
3532 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3533 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3534 if (rc) {
3535 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3536 }
3537
3538 cifs_buf_release(pSMB);
3539
3540 if (rc == -EAGAIN)
3541 goto SetEOFRetry;
3542
3543 return rc;
3544}
3545
3546int
3547CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3548 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3549{
3550 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3551 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3552 char *data_offset;
3553 struct file_end_of_file_info *parm_data;
3554 int rc = 0;
3555 int bytes_returned = 0;
3556 __u16 params, param_offset, offset, byte_count, count;
3557
3558 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3559 (long long)size));
cd63499c
SF
3560 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3561
1da177e4
LT
3562 if (rc)
3563 return rc;
3564
cd63499c
SF
3565 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3566
1da177e4
LT
3567 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3568 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3569
3570 params = 6;
3571 pSMB->MaxSetupCount = 0;
3572 pSMB->Reserved = 0;
3573 pSMB->Flags = 0;
3574 pSMB->Timeout = 0;
3575 pSMB->Reserved2 = 0;
3576 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3577 offset = param_offset + params;
3578
3579 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3580
3581 count = sizeof(struct file_end_of_file_info);
3582 pSMB->MaxParameterCount = cpu_to_le16(2);
3583 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3584 pSMB->SetupCount = 1;
3585 pSMB->Reserved3 = 0;
3586 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3587 byte_count = 3 /* pad */ + params + count;
3588 pSMB->DataCount = cpu_to_le16(count);
3589 pSMB->ParameterCount = cpu_to_le16(params);
3590 pSMB->TotalDataCount = pSMB->DataCount;
3591 pSMB->TotalParameterCount = pSMB->ParameterCount;
3592 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3593 parm_data =
3594 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3595 offset);
3596 pSMB->DataOffset = cpu_to_le16(offset);
3597 parm_data->FileSize = cpu_to_le64(size);
3598 pSMB->Fid = fid;
3599 if(SetAllocation) {
3600 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3601 pSMB->InformationLevel =
3602 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3603 else
3604 pSMB->InformationLevel =
3605 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3606 } else /* Set File Size */ {
3607 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3608 pSMB->InformationLevel =
3609 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3610 else
3611 pSMB->InformationLevel =
3612 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3613 }
3614 pSMB->Reserved4 = 0;
3615 pSMB->hdr.smb_buf_length += byte_count;
3616 pSMB->ByteCount = cpu_to_le16(byte_count);
3617 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3618 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3619 if (rc) {
3620 cFYI(1,
3621 ("Send error in SetFileInfo (SetFileSize) = %d",
3622 rc));
3623 }
3624
3625 if (pSMB)
cd63499c 3626 cifs_small_buf_release(pSMB);
1da177e4
LT
3627
3628 /* Note: On -EAGAIN error only caller can retry on handle based calls
3629 since file handle passed in no longer valid */
3630
3631 return rc;
3632}
3633
3634/* Some legacy servers such as NT4 require that the file times be set on
3635 an open handle, rather than by pathname - this is awkward due to
3636 potential access conflicts on the open, but it is unavoidable for these
3637 old servers since the only other choice is to go from 100 nanosecond DCE
3638 time and resort to the original setpathinfo level which takes the ancient
3639 DOS time format with 2 second granularity */
3640int
3641CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3642 __u16 fid)
3643{
3644 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3645 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3646 char *data_offset;
3647 int rc = 0;
3648 int bytes_returned = 0;
3649 __u16 params, param_offset, offset, byte_count, count;
3650
3651 cFYI(1, ("Set Times (via SetFileInfo)"));
cd63499c
SF
3652 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3653
1da177e4
LT
3654 if (rc)
3655 return rc;
3656
cd63499c
SF
3657 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3658
1da177e4
LT
3659 /* At this point there is no need to override the current pid
3660 with the pid of the opener, but that could change if we someday
3661 use an existing handle (rather than opening one on the fly) */
3662 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3663 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3664
3665 params = 6;
3666 pSMB->MaxSetupCount = 0;
3667 pSMB->Reserved = 0;
3668 pSMB->Flags = 0;
3669 pSMB->Timeout = 0;
3670 pSMB->Reserved2 = 0;
3671 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3672 offset = param_offset + params;
3673
3674 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3675
3676 count = sizeof (FILE_BASIC_INFO);
3677 pSMB->MaxParameterCount = cpu_to_le16(2);
3678 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3679 pSMB->SetupCount = 1;
3680 pSMB->Reserved3 = 0;
3681 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3682 byte_count = 3 /* pad */ + params + count;
3683 pSMB->DataCount = cpu_to_le16(count);
3684 pSMB->ParameterCount = cpu_to_le16(params);
3685 pSMB->TotalDataCount = pSMB->DataCount;
3686 pSMB->TotalParameterCount = pSMB->ParameterCount;
3687 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3688 pSMB->DataOffset = cpu_to_le16(offset);
3689 pSMB->Fid = fid;
3690 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3691 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3692 else
3693 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3694 pSMB->Reserved4 = 0;
3695 pSMB->hdr.smb_buf_length += byte_count;
3696 pSMB->ByteCount = cpu_to_le16(byte_count);
3697 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3698 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3699 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3700 if (rc) {
3701 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3702 }
3703
cd63499c 3704 cifs_small_buf_release(pSMB);
1da177e4
LT
3705
3706 /* Note: On -EAGAIN error only caller can retry on handle based calls
3707 since file handle passed in no longer valid */
3708
3709 return rc;
3710}
3711
3712
3713int
3714CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3715 const FILE_BASIC_INFO * data,
737b758c 3716 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3717{
3718 TRANSACTION2_SPI_REQ *pSMB = NULL;
3719 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3720 int name_len;
3721 int rc = 0;
3722 int bytes_returned = 0;
3723 char *data_offset;
3724 __u16 params, param_offset, offset, byte_count, count;
3725
3726 cFYI(1, ("In SetTimes"));
3727
3728SetTimesRetry:
3729 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3730 (void **) &pSMBr);
3731 if (rc)
3732 return rc;
3733
3734 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3735 name_len =
b1a45695 3736 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 3737 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3738 name_len++; /* trailing null */
3739 name_len *= 2;
3740 } else { /* BB improve the check for buffer overruns BB */
3741 name_len = strnlen(fileName, PATH_MAX);
3742 name_len++; /* trailing null */
3743 strncpy(pSMB->FileName, fileName, name_len);
3744 }
3745
3746 params = 6 + name_len;
3747 count = sizeof (FILE_BASIC_INFO);
3748 pSMB->MaxParameterCount = cpu_to_le16(2);
3749 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3750 pSMB->MaxSetupCount = 0;
3751 pSMB->Reserved = 0;
3752 pSMB->Flags = 0;
3753 pSMB->Timeout = 0;
3754 pSMB->Reserved2 = 0;
3755 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3756 InformationLevel) - 4;
3757 offset = param_offset + params;
3758 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3759 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3760 pSMB->DataOffset = cpu_to_le16(offset);
3761 pSMB->SetupCount = 1;
3762 pSMB->Reserved3 = 0;
3763 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3764 byte_count = 3 /* pad */ + params + count;
3765
3766 pSMB->DataCount = cpu_to_le16(count);
3767 pSMB->ParameterCount = cpu_to_le16(params);
3768 pSMB->TotalDataCount = pSMB->DataCount;
3769 pSMB->TotalParameterCount = pSMB->ParameterCount;
3770 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3771 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3772 else
3773 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3774 pSMB->Reserved4 = 0;
3775 pSMB->hdr.smb_buf_length += byte_count;
3776 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3777 pSMB->ByteCount = cpu_to_le16(byte_count);
3778 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3779 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3780 if (rc) {
3781 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3782 }
3783
3784 cifs_buf_release(pSMB);
3785
3786 if (rc == -EAGAIN)
3787 goto SetTimesRetry;
3788
3789 return rc;
3790}
3791
3792/* Can not be used to set time stamps yet (due to old DOS time format) */
3793/* Can be used to set attributes */
3794#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
3795 handling it anyway and NT4 was what we thought it would be needed for
3796 Do not delete it until we prove whether needed for Win9x though */
3797int
3798CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3799 __u16 dos_attrs, const struct nls_table *nls_codepage)
3800{
3801 SETATTR_REQ *pSMB = NULL;
3802 SETATTR_RSP *pSMBr = NULL;
3803 int rc = 0;
3804 int bytes_returned;
3805 int name_len;
3806
3807 cFYI(1, ("In SetAttrLegacy"));
3808
3809SetAttrLgcyRetry:
3810 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3811 (void **) &pSMBr);
3812 if (rc)
3813 return rc;
3814
3815 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3816 name_len =
b1a45695 3817 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
1da177e4
LT
3818 PATH_MAX, nls_codepage);
3819 name_len++; /* trailing null */
3820 name_len *= 2;
3821 } else { /* BB improve the check for buffer overruns BB */
3822 name_len = strnlen(fileName, PATH_MAX);
3823 name_len++; /* trailing null */
3824 strncpy(pSMB->fileName, fileName, name_len);
3825 }
3826 pSMB->attr = cpu_to_le16(dos_attrs);
3827 pSMB->BufferFormat = 0x04;
3828 pSMB->hdr.smb_buf_length += name_len + 1;
3829 pSMB->ByteCount = cpu_to_le16(name_len + 1);
3830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3832 if (rc) {
3833 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3834 }
3835
3836 cifs_buf_release(pSMB);
3837
3838 if (rc == -EAGAIN)
3839 goto SetAttrLgcyRetry;
3840
3841 return rc;
3842}
3843#endif /* temporarily unneeded SetAttr legacy function */
3844
3845int
3846CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
737b758c
SF
3847 char *fileName, __u64 mode, __u64 uid, __u64 gid,
3848 dev_t device, const struct nls_table *nls_codepage,
3849 int remap)
1da177e4
LT
3850{
3851 TRANSACTION2_SPI_REQ *pSMB = NULL;
3852 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3853 int name_len;
3854 int rc = 0;
3855 int bytes_returned = 0;
3856 FILE_UNIX_BASIC_INFO *data_offset;
3857 __u16 params, param_offset, offset, count, byte_count;
3858
3859 cFYI(1, ("In SetUID/GID/Mode"));
3860setPermsRetry:
3861 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3862 (void **) &pSMBr);
3863 if (rc)
3864 return rc;
3865
3866 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3867 name_len =
b1a45695 3868 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 3869 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3870 name_len++; /* trailing null */
3871 name_len *= 2;
3872 } else { /* BB improve the check for buffer overruns BB */
3873 name_len = strnlen(fileName, PATH_MAX);
3874 name_len++; /* trailing null */
3875 strncpy(pSMB->FileName, fileName, name_len);
3876 }
3877
3878 params = 6 + name_len;
3879 count = sizeof (FILE_UNIX_BASIC_INFO);
3880 pSMB->MaxParameterCount = cpu_to_le16(2);
3881 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3882 pSMB->MaxSetupCount = 0;
3883 pSMB->Reserved = 0;
3884 pSMB->Flags = 0;
3885 pSMB->Timeout = 0;
3886 pSMB->Reserved2 = 0;
3887 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3888 InformationLevel) - 4;
3889 offset = param_offset + params;
3890 data_offset =
3891 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3892 offset);
3893 memset(data_offset, 0, count);
3894 pSMB->DataOffset = cpu_to_le16(offset);
3895 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3896 pSMB->SetupCount = 1;
3897 pSMB->Reserved3 = 0;
3898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3899 byte_count = 3 /* pad */ + params + count;
3900 pSMB->ParameterCount = cpu_to_le16(params);
3901 pSMB->DataCount = cpu_to_le16(count);
3902 pSMB->TotalParameterCount = pSMB->ParameterCount;
3903 pSMB->TotalDataCount = pSMB->DataCount;
3904 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3905 pSMB->Reserved4 = 0;
3906 pSMB->hdr.smb_buf_length += byte_count;
3907 data_offset->Uid = cpu_to_le64(uid);
3908 data_offset->Gid = cpu_to_le64(gid);
3909 /* better to leave device as zero when it is */
3910 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3911 data_offset->DevMinor = cpu_to_le64(MINOR(device));
3912 data_offset->Permissions = cpu_to_le64(mode);
3913
3914 if(S_ISREG(mode))
3915 data_offset->Type = cpu_to_le32(UNIX_FILE);
3916 else if(S_ISDIR(mode))
3917 data_offset->Type = cpu_to_le32(UNIX_DIR);
3918 else if(S_ISLNK(mode))
3919 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3920 else if(S_ISCHR(mode))
3921 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3922 else if(S_ISBLK(mode))
3923 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3924 else if(S_ISFIFO(mode))
3925 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3926 else if(S_ISSOCK(mode))
3927 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3928
3929
3930 pSMB->ByteCount = cpu_to_le16(byte_count);
3931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3933 if (rc) {
3934 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3935 }
3936
3937 if (pSMB)
3938 cifs_buf_release(pSMB);
3939 if (rc == -EAGAIN)
3940 goto setPermsRetry;
3941 return rc;
3942}
3943
3944int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
3945 const int notify_subdirs, const __u16 netfid,
3946 __u32 filter, const struct nls_table *nls_codepage)
3947{
3948 int rc = 0;
3949 struct smb_com_transaction_change_notify_req * pSMB = NULL;
3950 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3951 int bytes_returned;
3952
3953 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3954 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3955 (void **) &pSMBr);
3956 if (rc)
3957 return rc;
3958
3959 pSMB->TotalParameterCount = 0 ;
3960 pSMB->TotalDataCount = 0;
3961 pSMB->MaxParameterCount = cpu_to_le32(2);
3962 /* BB find exact data count max from sess structure BB */
3963 pSMB->MaxDataCount = 0; /* same in little endian or be */
3964 pSMB->MaxSetupCount = 4;
3965 pSMB->Reserved = 0;
3966 pSMB->ParameterOffset = 0;
3967 pSMB->DataCount = 0;
3968 pSMB->DataOffset = 0;
3969 pSMB->SetupCount = 4; /* single byte does not need le conversion */
3970 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3971 pSMB->ParameterCount = pSMB->TotalParameterCount;
3972 if(notify_subdirs)
3973 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3974 pSMB->Reserved2 = 0;
3975 pSMB->CompletionFilter = cpu_to_le32(filter);
3976 pSMB->Fid = netfid; /* file handle always le */
3977 pSMB->ByteCount = 0;
3978
3979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3980 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3981 if (rc) {
3982 cFYI(1, ("Error in Notify = %d", rc));
3983 }
3984 cifs_buf_release(pSMB);
3985 return rc;
3986}
3987#ifdef CONFIG_CIFS_XATTR
3988ssize_t
3989CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3990 const unsigned char *searchName,
3991 char * EAData, size_t buf_size,
737b758c 3992 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3993{
3994 /* BB assumes one setup word */
3995 TRANSACTION2_QPI_REQ *pSMB = NULL;
3996 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3997 int rc = 0;
3998 int bytes_returned;
3999 int name_len;
4000 struct fea * temp_fea;
4001 char * temp_ptr;
4002 __u16 params, byte_count;
4003
4004 cFYI(1, ("In Query All EAs path %s", searchName));
4005QAllEAsRetry:
4006 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4007 (void **) &pSMBr);
4008 if (rc)
4009 return rc;
4010
4011 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4012 name_len =
b1a45695 4013 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 4014 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4015 name_len++; /* trailing null */
4016 name_len *= 2;
4017 } else { /* BB improve the check for buffer overruns BB */
4018 name_len = strnlen(searchName, PATH_MAX);
4019 name_len++; /* trailing null */
4020 strncpy(pSMB->FileName, searchName, name_len);
4021 }
4022
4023 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4024 pSMB->TotalDataCount = 0;
4025 pSMB->MaxParameterCount = cpu_to_le16(2);
4026 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4027 pSMB->MaxSetupCount = 0;
4028 pSMB->Reserved = 0;
4029 pSMB->Flags = 0;
4030 pSMB->Timeout = 0;
4031 pSMB->Reserved2 = 0;
4032 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4033 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4034 pSMB->DataCount = 0;
4035 pSMB->DataOffset = 0;
4036 pSMB->SetupCount = 1;
4037 pSMB->Reserved3 = 0;
4038 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4039 byte_count = params + 1 /* pad */ ;
4040 pSMB->TotalParameterCount = cpu_to_le16(params);
4041 pSMB->ParameterCount = pSMB->TotalParameterCount;
4042 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4043 pSMB->Reserved4 = 0;
4044 pSMB->hdr.smb_buf_length += byte_count;
4045 pSMB->ByteCount = cpu_to_le16(byte_count);
4046
4047 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4048 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4049 if (rc) {
4050 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4051 } else { /* decode response */
4052 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4053
4054 /* BB also check enough total bytes returned */
4055 /* BB we need to improve the validity checking
4056 of these trans2 responses */
4057 if (rc || (pSMBr->ByteCount < 4))
4058 rc = -EIO; /* bad smb */
4059 /* else if (pFindData){
4060 memcpy((char *) pFindData,
4061 (char *) &pSMBr->hdr.Protocol +
4062 data_offset, kl);
4063 }*/ else {
4064 /* check that length of list is not more than bcc */
4065 /* check that each entry does not go beyond length
4066 of list */
4067 /* check that each element of each entry does not
4068 go beyond end of list */
4069 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4070 struct fealist * ea_response_data;
4071 rc = 0;
4072 /* validate_trans2_offsets() */
4073 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4074 ea_response_data = (struct fealist *)
4075 (((char *) &pSMBr->hdr.Protocol) +
4076 data_offset);
4077 name_len = le32_to_cpu(ea_response_data->list_len);
4078 cFYI(1,("ea length %d", name_len));
4079 if(name_len <= 8) {
4080 /* returned EA size zeroed at top of function */
4081 cFYI(1,("empty EA list returned from server"));
4082 } else {
4083 /* account for ea list len */
4084 name_len -= 4;
4085 temp_fea = ea_response_data->list;
4086 temp_ptr = (char *)temp_fea;
4087 while(name_len > 0) {
4088 __u16 value_len;
4089 name_len -= 4;
4090 temp_ptr += 4;
4091 rc += temp_fea->name_len;
4092 /* account for prefix user. and trailing null */
4093 rc = rc + 5 + 1;
4094 if(rc<(int)buf_size) {
4095 memcpy(EAData,"user.",5);
4096 EAData+=5;
4097 memcpy(EAData,temp_ptr,temp_fea->name_len);
4098 EAData+=temp_fea->name_len;
4099 /* null terminate name */
4100 *EAData = 0;
4101 EAData = EAData + 1;
4102 } else if(buf_size == 0) {
4103 /* skip copy - calc size only */
4104 } else {
4105 /* stop before overrun buffer */
4106 rc = -ERANGE;
4107 break;
4108 }
4109 name_len -= temp_fea->name_len;
4110 temp_ptr += temp_fea->name_len;
4111 /* account for trailing null */
4112 name_len--;
4113 temp_ptr++;
4114 value_len = le16_to_cpu(temp_fea->value_len);
4115 name_len -= value_len;
4116 temp_ptr += value_len;
4117 /* BB check that temp_ptr is still within smb BB*/
4118 /* no trailing null to account for in value len */
4119 /* go on to next EA */
4120 temp_fea = (struct fea *)temp_ptr;
4121 }
4122 }
4123 }
4124 }
4125 if (pSMB)
4126 cifs_buf_release(pSMB);
4127 if (rc == -EAGAIN)
4128 goto QAllEAsRetry;
4129
4130 return (ssize_t)rc;
4131}
4132
4133ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4134 const unsigned char * searchName,const unsigned char * ea_name,
4135 unsigned char * ea_value, size_t buf_size,
737b758c 4136 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4137{
4138 TRANSACTION2_QPI_REQ *pSMB = NULL;
4139 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4140 int rc = 0;
4141 int bytes_returned;
4142 int name_len;
4143 struct fea * temp_fea;
4144 char * temp_ptr;
4145 __u16 params, byte_count;
4146
4147 cFYI(1, ("In Query EA path %s", searchName));
4148QEARetry:
4149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150 (void **) &pSMBr);
4151 if (rc)
4152 return rc;
4153
4154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4155 name_len =
b1a45695 4156 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 4157 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4158 name_len++; /* trailing null */
4159 name_len *= 2;
4160 } else { /* BB improve the check for buffer overruns BB */
4161 name_len = strnlen(searchName, PATH_MAX);
4162 name_len++; /* trailing null */
4163 strncpy(pSMB->FileName, searchName, name_len);
4164 }
4165
4166 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4167 pSMB->TotalDataCount = 0;
4168 pSMB->MaxParameterCount = cpu_to_le16(2);
4169 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4170 pSMB->MaxSetupCount = 0;
4171 pSMB->Reserved = 0;
4172 pSMB->Flags = 0;
4173 pSMB->Timeout = 0;
4174 pSMB->Reserved2 = 0;
4175 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4176 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4177 pSMB->DataCount = 0;
4178 pSMB->DataOffset = 0;
4179 pSMB->SetupCount = 1;
4180 pSMB->Reserved3 = 0;
4181 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4182 byte_count = params + 1 /* pad */ ;
4183 pSMB->TotalParameterCount = cpu_to_le16(params);
4184 pSMB->ParameterCount = pSMB->TotalParameterCount;
4185 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4186 pSMB->Reserved4 = 0;
4187 pSMB->hdr.smb_buf_length += byte_count;
4188 pSMB->ByteCount = cpu_to_le16(byte_count);
4189
4190 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4191 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4192 if (rc) {
4193 cFYI(1, ("Send error in Query EA = %d", rc));
4194 } else { /* decode response */
4195 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4196
4197 /* BB also check enough total bytes returned */
4198 /* BB we need to improve the validity checking
4199 of these trans2 responses */
4200 if (rc || (pSMBr->ByteCount < 4))
4201 rc = -EIO; /* bad smb */
4202 /* else if (pFindData){
4203 memcpy((char *) pFindData,
4204 (char *) &pSMBr->hdr.Protocol +
4205 data_offset, kl);
4206 }*/ else {
4207 /* check that length of list is not more than bcc */
4208 /* check that each entry does not go beyond length
4209 of list */
4210 /* check that each element of each entry does not
4211 go beyond end of list */
4212 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4213 struct fealist * ea_response_data;
4214 rc = -ENODATA;
4215 /* validate_trans2_offsets() */
4216 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4217 ea_response_data = (struct fealist *)
4218 (((char *) &pSMBr->hdr.Protocol) +
4219 data_offset);
4220 name_len = le32_to_cpu(ea_response_data->list_len);
4221 cFYI(1,("ea length %d", name_len));
4222 if(name_len <= 8) {
4223 /* returned EA size zeroed at top of function */
4224 cFYI(1,("empty EA list returned from server"));
4225 } else {
4226 /* account for ea list len */
4227 name_len -= 4;
4228 temp_fea = ea_response_data->list;
4229 temp_ptr = (char *)temp_fea;
4230 /* loop through checking if we have a matching
4231 name and then return the associated value */
4232 while(name_len > 0) {
4233 __u16 value_len;
4234 name_len -= 4;
4235 temp_ptr += 4;
4236 value_len = le16_to_cpu(temp_fea->value_len);
4237 /* BB validate that value_len falls within SMB,
4238 even though maximum for name_len is 255 */
4239 if(memcmp(temp_fea->name,ea_name,
4240 temp_fea->name_len) == 0) {
4241 /* found a match */
4242 rc = value_len;
4243 /* account for prefix user. and trailing null */
4244 if(rc<=(int)buf_size) {
4245 memcpy(ea_value,
4246 temp_fea->name+temp_fea->name_len+1,
4247 rc);
4248 /* ea values, unlike ea names,
4249 are not null terminated */
4250 } else if(buf_size == 0) {
4251 /* skip copy - calc size only */
4252 } else {
4253 /* stop before overrun buffer */
4254 rc = -ERANGE;
4255 }
4256 break;
4257 }
4258 name_len -= temp_fea->name_len;
4259 temp_ptr += temp_fea->name_len;
4260 /* account for trailing null */
4261 name_len--;
4262 temp_ptr++;
4263 name_len -= value_len;
4264 temp_ptr += value_len;
4265 /* no trailing null to account for in value len */
4266 /* go on to next EA */
4267 temp_fea = (struct fea *)temp_ptr;
4268 }
4269 }
4270 }
4271 }
4272 if (pSMB)
4273 cifs_buf_release(pSMB);
4274 if (rc == -EAGAIN)
4275 goto QEARetry;
4276
4277 return (ssize_t)rc;
4278}
4279
4280int
4281CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4282 const char * ea_name, const void * ea_value,
737b758c
SF
4283 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4284 int remap)
1da177e4
LT
4285{
4286 struct smb_com_transaction2_spi_req *pSMB = NULL;
4287 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4288 struct fealist *parm_data;
4289 int name_len;
4290 int rc = 0;
4291 int bytes_returned = 0;
4292 __u16 params, param_offset, byte_count, offset, count;
4293
4294 cFYI(1, ("In SetEA"));
4295SetEARetry:
4296 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4297 (void **) &pSMBr);
4298 if (rc)
4299 return rc;
4300
4301 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4302 name_len =
b1a45695 4303 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4304 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4305 name_len++; /* trailing null */
4306 name_len *= 2;
4307 } else { /* BB improve the check for buffer overruns BB */
4308 name_len = strnlen(fileName, PATH_MAX);
4309 name_len++; /* trailing null */
4310 strncpy(pSMB->FileName, fileName, name_len);
4311 }
4312
4313 params = 6 + name_len;
4314
4315 /* done calculating parms using name_len of file name,
4316 now use name_len to calculate length of ea name
4317 we are going to create in the inode xattrs */
4318 if(ea_name == NULL)
4319 name_len = 0;
4320 else
4321 name_len = strnlen(ea_name,255);
4322
4323 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4324 pSMB->MaxParameterCount = cpu_to_le16(2);
4325 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4326 pSMB->MaxSetupCount = 0;
4327 pSMB->Reserved = 0;
4328 pSMB->Flags = 0;
4329 pSMB->Timeout = 0;
4330 pSMB->Reserved2 = 0;
4331 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4332 InformationLevel) - 4;
4333 offset = param_offset + params;
4334 pSMB->InformationLevel =
4335 cpu_to_le16(SMB_SET_FILE_EA);
4336
4337 parm_data =
4338 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4339 offset);
4340 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4341 pSMB->DataOffset = cpu_to_le16(offset);
4342 pSMB->SetupCount = 1;
4343 pSMB->Reserved3 = 0;
4344 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4345 byte_count = 3 /* pad */ + params + count;
4346 pSMB->DataCount = cpu_to_le16(count);
4347 parm_data->list_len = cpu_to_le32(count);
4348 parm_data->list[0].EA_flags = 0;
4349 /* we checked above that name len is less than 255 */
4350 parm_data->list[0].name_len = (__u8)name_len;;
4351 /* EA names are always ASCII */
4352 if(ea_name)
4353 strncpy(parm_data->list[0].name,ea_name,name_len);
4354 parm_data->list[0].name[name_len] = 0;
4355 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4356 /* caller ensures that ea_value_len is less than 64K but
4357 we need to ensure that it fits within the smb */
4358
4359 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4360 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4361 if(ea_value_len)
4362 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4363
4364 pSMB->TotalDataCount = pSMB->DataCount;
4365 pSMB->ParameterCount = cpu_to_le16(params);
4366 pSMB->TotalParameterCount = pSMB->ParameterCount;
4367 pSMB->Reserved4 = 0;
4368 pSMB->hdr.smb_buf_length += byte_count;
4369 pSMB->ByteCount = cpu_to_le16(byte_count);
4370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4371 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4372 if (rc) {
4373 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4374 }
4375
4376 cifs_buf_release(pSMB);
4377
4378 if (rc == -EAGAIN)
4379 goto SetEARetry;
4380
4381 return rc;
4382}
4383
4384#endif