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