]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/cifs/cifssmb.c
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[net-next-2.6.git] / fs / cifs / cifssmb.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/cifssmb.c
3 *
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
4b8f930f 1073/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
ec637e3f
SF
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 1276
4b8f930f 1277/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
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
08547b03
SF
1355int
1356CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1357 const __u16 smb_file_id, const int get_flag, const __u64 len,
1358 const __u64 lkoffset, const __u16 lock_type, const int waitFlag)
1359{
1360 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1361 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1362 char *data_offset;
1363 struct cifs_posix_lock *parm_data;
1364 int rc = 0;
1365 int bytes_returned = 0;
1366 __u16 params, param_offset, offset, byte_count, count;
1367
1368 cFYI(1, ("Posix Lock"));
1369 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1370
1371 if (rc)
1372 return rc;
1373
1374 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1375
1376 params = 6;
1377 pSMB->MaxSetupCount = 0;
1378 pSMB->Reserved = 0;
1379 pSMB->Flags = 0;
1380 pSMB->Timeout = 0;
1381 pSMB->Reserved2 = 0;
1382 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1383 offset = param_offset + params;
1384
1385 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1386
1387 count = sizeof(struct cifs_posix_lock);
1388 pSMB->MaxParameterCount = cpu_to_le16(2);
1389 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1390 pSMB->SetupCount = 1;
1391 pSMB->Reserved3 = 0;
1392 if(get_flag)
1393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1394 else
1395 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1396 byte_count = 3 /* pad */ + params + count;
1397 pSMB->DataCount = cpu_to_le16(count);
1398 pSMB->ParameterCount = cpu_to_le16(params);
1399 pSMB->TotalDataCount = pSMB->DataCount;
1400 pSMB->TotalParameterCount = pSMB->ParameterCount;
1401 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1402 parm_data = (struct cifs_posix_lock *)
1403 (((char *) &pSMB->hdr.Protocol) + offset);
1404
1405 parm_data->lock_type = cpu_to_le16(lock_type);
1406 if(waitFlag)
1407 parm_data->lock_flags = 1;
1408 parm_data->pid = cpu_to_le32(current->tgid);
1409 parm_data->start = lkoffset;
1410 parm_data->length = len; /* normalize negative numbers */
1411
1412 pSMB->DataOffset = cpu_to_le16(offset);
f26282c9 1413 pSMB->Fid = smb_file_id;
08547b03
SF
1414 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1415 pSMB->Reserved4 = 0;
1416 pSMB->hdr.smb_buf_length += byte_count;
1417 pSMB->ByteCount = cpu_to_le16(byte_count);
1418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1420 if (rc) {
1421 cFYI(1, ("Send error in Posix Lock = %d", rc));
1422 }
1423
1424 if (pSMB)
1425 cifs_small_buf_release(pSMB);
1426
1427 /* Note: On -EAGAIN error only caller can retry on handle based calls
1428 since file handle passed in no longer valid */
1429
1430 return rc;
1431}
1432
1433
1da177e4
LT
1434int
1435CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1436{
1437 int rc = 0;
1438 CLOSE_REQ *pSMB = NULL;
1439 CLOSE_RSP *pSMBr = NULL;
1440 int bytes_returned;
1441 cFYI(1, ("In CIFSSMBClose"));
1442
1443/* do not retry on dead session on close */
1444 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1445 if(rc == -EAGAIN)
1446 return 0;
1447 if (rc)
1448 return rc;
1449
1450 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1451
1452 pSMB->FileID = (__u16) smb_file_id;
1453 pSMB->LastWriteTime = 0;
1454 pSMB->ByteCount = 0;
1455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1456 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1457 cifs_stats_inc(&tcon->num_closes);
1da177e4
LT
1458 if (rc) {
1459 if(rc!=-EINTR) {
1460 /* EINTR is expected when user ctl-c to kill app */
1461 cERROR(1, ("Send error in Close = %d", rc));
1462 }
1463 }
1464
1465 cifs_small_buf_release(pSMB);
1466
1467 /* Since session is dead, file will be closed on server already */
1468 if(rc == -EAGAIN)
1469 rc = 0;
1470
1471 return rc;
1472}
1473
1474int
1475CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1476 const char *fromName, const char *toName,
737b758c 1477 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1478{
1479 int rc = 0;
1480 RENAME_REQ *pSMB = NULL;
1481 RENAME_RSP *pSMBr = NULL;
1482 int bytes_returned;
1483 int name_len, name_len2;
1484 __u16 count;
1485
1486 cFYI(1, ("In CIFSSMBRename"));
1487renameRetry:
1488 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1489 (void **) &pSMBr);
1490 if (rc)
1491 return rc;
1492
1493 pSMB->BufferFormat = 0x04;
1494 pSMB->SearchAttributes =
1495 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1496 ATTR_DIRECTORY);
1497
1498 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1499 name_len =
b1a45695 1500 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
737b758c 1501 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1502 name_len++; /* trailing null */
1503 name_len *= 2;
1504 pSMB->OldFileName[name_len] = 0x04; /* pad */
1505 /* protocol requires ASCII signature byte on Unicode string */
1506 pSMB->OldFileName[name_len + 1] = 0x00;
1507 name_len2 =
b1a45695 1508 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
737b758c 1509 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1510 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1511 name_len2 *= 2; /* convert to bytes */
1512 } else { /* BB improve the check for buffer overruns BB */
1513 name_len = strnlen(fromName, PATH_MAX);
1514 name_len++; /* trailing null */
1515 strncpy(pSMB->OldFileName, fromName, name_len);
1516 name_len2 = strnlen(toName, PATH_MAX);
1517 name_len2++; /* trailing null */
1518 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1519 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1520 name_len2++; /* trailing null */
1521 name_len2++; /* signature byte */
1522 }
1523
1524 count = 1 /* 1st signature byte */ + name_len + name_len2;
1525 pSMB->hdr.smb_buf_length += count;
1526 pSMB->ByteCount = cpu_to_le16(count);
1527
1528 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1529 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1530 cifs_stats_inc(&tcon->num_renames);
1da177e4
LT
1531 if (rc) {
1532 cFYI(1, ("Send error in rename = %d", rc));
1533 }
1534
1da177e4
LT
1535 cifs_buf_release(pSMB);
1536
1537 if (rc == -EAGAIN)
1538 goto renameRetry;
1539
1540 return rc;
1541}
1542
1543int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
737b758c
SF
1544 int netfid, char * target_name,
1545 const struct nls_table * nls_codepage, int remap)
1da177e4
LT
1546{
1547 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1548 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1549 struct set_file_rename * rename_info;
1550 char *data_offset;
1551 char dummy_string[30];
1552 int rc = 0;
1553 int bytes_returned = 0;
1554 int len_of_str;
1555 __u16 params, param_offset, offset, count, byte_count;
1556
1557 cFYI(1, ("Rename to File by handle"));
1558 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1559 (void **) &pSMBr);
1560 if (rc)
1561 return rc;
1562
1563 params = 6;
1564 pSMB->MaxSetupCount = 0;
1565 pSMB->Reserved = 0;
1566 pSMB->Flags = 0;
1567 pSMB->Timeout = 0;
1568 pSMB->Reserved2 = 0;
1569 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1570 offset = param_offset + params;
1571
1572 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1573 rename_info = (struct set_file_rename *) data_offset;
1574 pSMB->MaxParameterCount = cpu_to_le16(2);
1575 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1576 pSMB->SetupCount = 1;
1577 pSMB->Reserved3 = 0;
1578 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1579 byte_count = 3 /* pad */ + params;
1580 pSMB->ParameterCount = cpu_to_le16(params);
1581 pSMB->TotalParameterCount = pSMB->ParameterCount;
1582 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1583 pSMB->DataOffset = cpu_to_le16(offset);
1584 /* construct random name ".cifs_tmp<inodenum><mid>" */
1585 rename_info->overwrite = cpu_to_le32(1);
1586 rename_info->root_fid = 0;
1587 /* unicode only call */
1588 if(target_name == NULL) {
1589 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
b1a45695 1590 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
737b758c 1591 dummy_string, 24, nls_codepage, remap);
1da177e4 1592 } else {
b1a45695 1593 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
737b758c 1594 target_name, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1595 }
1596 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1597 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1598 byte_count += count;
1599 pSMB->DataCount = cpu_to_le16(count);
1600 pSMB->TotalDataCount = pSMB->DataCount;
1601 pSMB->Fid = netfid;
1602 pSMB->InformationLevel =
1603 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1604 pSMB->Reserved4 = 0;
1605 pSMB->hdr.smb_buf_length += byte_count;
1606 pSMB->ByteCount = cpu_to_le16(byte_count);
1607 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1609 cifs_stats_inc(&pTcon->num_t2renames);
1da177e4
LT
1610 if (rc) {
1611 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1612 }
a5a2b489 1613
1da177e4
LT
1614 cifs_buf_release(pSMB);
1615
1616 /* Note: On -EAGAIN error only caller can retry on handle based calls
1617 since file handle passed in no longer valid */
1618
1619 return rc;
1620}
1621
1622int
1623CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1624 const __u16 target_tid, const char *toName, const int flags,
737b758c 1625 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1626{
1627 int rc = 0;
1628 COPY_REQ *pSMB = NULL;
1629 COPY_RSP *pSMBr = NULL;
1630 int bytes_returned;
1631 int name_len, name_len2;
1632 __u16 count;
1633
1634 cFYI(1, ("In CIFSSMBCopy"));
1635copyRetry:
1636 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1637 (void **) &pSMBr);
1638 if (rc)
1639 return rc;
1640
1641 pSMB->BufferFormat = 0x04;
1642 pSMB->Tid2 = target_tid;
1643
1644 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1645
1646 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
b1a45695 1647 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
737b758c
SF
1648 fromName, PATH_MAX, nls_codepage,
1649 remap);
1da177e4
LT
1650 name_len++; /* trailing null */
1651 name_len *= 2;
1652 pSMB->OldFileName[name_len] = 0x04; /* pad */
1653 /* protocol requires ASCII signature byte on Unicode string */
1654 pSMB->OldFileName[name_len + 1] = 0x00;
b1a45695 1655 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 1656 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1657 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1658 name_len2 *= 2; /* convert to bytes */
1659 } else { /* BB improve the check for buffer overruns BB */
1660 name_len = strnlen(fromName, PATH_MAX);
1661 name_len++; /* trailing null */
1662 strncpy(pSMB->OldFileName, fromName, name_len);
1663 name_len2 = strnlen(toName, PATH_MAX);
1664 name_len2++; /* trailing null */
1665 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1666 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1667 name_len2++; /* trailing null */
1668 name_len2++; /* signature byte */
1669 }
1670
1671 count = 1 /* 1st signature byte */ + name_len + name_len2;
1672 pSMB->hdr.smb_buf_length += count;
1673 pSMB->ByteCount = cpu_to_le16(count);
1674
1675 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1677 if (rc) {
1678 cFYI(1, ("Send error in copy = %d with %d files copied",
1679 rc, le16_to_cpu(pSMBr->CopyCount)));
1680 }
1681 if (pSMB)
1682 cifs_buf_release(pSMB);
1683
1684 if (rc == -EAGAIN)
1685 goto copyRetry;
1686
1687 return rc;
1688}
1689
1690int
1691CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1692 const char *fromName, const char *toName,
1693 const struct nls_table *nls_codepage)
1694{
1695 TRANSACTION2_SPI_REQ *pSMB = NULL;
1696 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1697 char *data_offset;
1698 int name_len;
1699 int name_len_target;
1700 int rc = 0;
1701 int bytes_returned = 0;
1702 __u16 params, param_offset, offset, byte_count;
1703
1704 cFYI(1, ("In Symlink Unix style"));
1705createSymLinkRetry:
1706 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1707 (void **) &pSMBr);
1708 if (rc)
1709 return rc;
1710
1711 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1712 name_len =
e89dc920 1713 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1da177e4
LT
1714 /* find define for this maxpathcomponent */
1715 , nls_codepage);
1716 name_len++; /* trailing null */
1717 name_len *= 2;
1718
1719 } else { /* BB improve the check for buffer overruns BB */
1720 name_len = strnlen(fromName, PATH_MAX);
1721 name_len++; /* trailing null */
1722 strncpy(pSMB->FileName, fromName, name_len);
1723 }
1724 params = 6 + name_len;
1725 pSMB->MaxSetupCount = 0;
1726 pSMB->Reserved = 0;
1727 pSMB->Flags = 0;
1728 pSMB->Timeout = 0;
1729 pSMB->Reserved2 = 0;
1730 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1731 InformationLevel) - 4;
1732 offset = param_offset + params;
1733
1734 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1735 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1736 name_len_target =
e89dc920 1737 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1da177e4
LT
1738 /* find define for this maxpathcomponent */
1739 , nls_codepage);
1740 name_len_target++; /* trailing null */
1741 name_len_target *= 2;
1742 } else { /* BB improve the check for buffer overruns BB */
1743 name_len_target = strnlen(toName, PATH_MAX);
1744 name_len_target++; /* trailing null */
1745 strncpy(data_offset, toName, name_len_target);
1746 }
1747
1748 pSMB->MaxParameterCount = cpu_to_le16(2);
1749 /* BB find exact max on data count below from sess */
1750 pSMB->MaxDataCount = cpu_to_le16(1000);
1751 pSMB->SetupCount = 1;
1752 pSMB->Reserved3 = 0;
1753 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1754 byte_count = 3 /* pad */ + params + name_len_target;
1755 pSMB->DataCount = cpu_to_le16(name_len_target);
1756 pSMB->ParameterCount = cpu_to_le16(params);
1757 pSMB->TotalDataCount = pSMB->DataCount;
1758 pSMB->TotalParameterCount = pSMB->ParameterCount;
1759 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1760 pSMB->DataOffset = cpu_to_le16(offset);
1761 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1762 pSMB->Reserved4 = 0;
1763 pSMB->hdr.smb_buf_length += byte_count;
1764 pSMB->ByteCount = cpu_to_le16(byte_count);
1765 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1766 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1767 cifs_stats_inc(&tcon->num_symlinks);
1da177e4
LT
1768 if (rc) {
1769 cFYI(1,
1770 ("Send error in SetPathInfo (create symlink) = %d",
1771 rc));
1772 }
1773
1774 if (pSMB)
1775 cifs_buf_release(pSMB);
1776
1777 if (rc == -EAGAIN)
1778 goto createSymLinkRetry;
1779
1780 return rc;
1781}
1782
1783int
1784CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1785 const char *fromName, const char *toName,
737b758c 1786 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1787{
1788 TRANSACTION2_SPI_REQ *pSMB = NULL;
1789 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1790 char *data_offset;
1791 int name_len;
1792 int name_len_target;
1793 int rc = 0;
1794 int bytes_returned = 0;
1795 __u16 params, param_offset, offset, byte_count;
1796
1797 cFYI(1, ("In Create Hard link Unix style"));
1798createHardLinkRetry:
1799 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1800 (void **) &pSMBr);
1801 if (rc)
1802 return rc;
1803
1804 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
b1a45695 1805 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
737b758c 1806 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1807 name_len++; /* trailing null */
1808 name_len *= 2;
1809
1810 } else { /* BB improve the check for buffer overruns BB */
1811 name_len = strnlen(toName, PATH_MAX);
1812 name_len++; /* trailing null */
1813 strncpy(pSMB->FileName, toName, name_len);
1814 }
1815 params = 6 + name_len;
1816 pSMB->MaxSetupCount = 0;
1817 pSMB->Reserved = 0;
1818 pSMB->Flags = 0;
1819 pSMB->Timeout = 0;
1820 pSMB->Reserved2 = 0;
1821 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1822 InformationLevel) - 4;
1823 offset = param_offset + params;
1824
1825 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1826 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1827 name_len_target =
b1a45695 1828 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
737b758c 1829 nls_codepage, remap);
1da177e4
LT
1830 name_len_target++; /* trailing null */
1831 name_len_target *= 2;
1832 } else { /* BB improve the check for buffer overruns BB */
1833 name_len_target = strnlen(fromName, PATH_MAX);
1834 name_len_target++; /* trailing null */
1835 strncpy(data_offset, fromName, name_len_target);
1836 }
1837
1838 pSMB->MaxParameterCount = cpu_to_le16(2);
1839 /* BB find exact max on data count below from sess*/
1840 pSMB->MaxDataCount = cpu_to_le16(1000);
1841 pSMB->SetupCount = 1;
1842 pSMB->Reserved3 = 0;
1843 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1844 byte_count = 3 /* pad */ + params + name_len_target;
1845 pSMB->ParameterCount = cpu_to_le16(params);
1846 pSMB->TotalParameterCount = pSMB->ParameterCount;
1847 pSMB->DataCount = cpu_to_le16(name_len_target);
1848 pSMB->TotalDataCount = pSMB->DataCount;
1849 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1850 pSMB->DataOffset = cpu_to_le16(offset);
1851 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1852 pSMB->Reserved4 = 0;
1853 pSMB->hdr.smb_buf_length += byte_count;
1854 pSMB->ByteCount = cpu_to_le16(byte_count);
1855 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1856 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1857 cifs_stats_inc(&tcon->num_hardlinks);
1da177e4
LT
1858 if (rc) {
1859 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1860 }
1861
1862 cifs_buf_release(pSMB);
1863 if (rc == -EAGAIN)
1864 goto createHardLinkRetry;
1865
1866 return rc;
1867}
1868
1869int
1870CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1871 const char *fromName, const char *toName,
737b758c 1872 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1873{
1874 int rc = 0;
1875 NT_RENAME_REQ *pSMB = NULL;
1876 RENAME_RSP *pSMBr = NULL;
1877 int bytes_returned;
1878 int name_len, name_len2;
1879 __u16 count;
1880
1881 cFYI(1, ("In CIFSCreateHardLink"));
1882winCreateHardLinkRetry:
1883
1884 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1885 (void **) &pSMBr);
1886 if (rc)
1887 return rc;
1888
1889 pSMB->SearchAttributes =
1890 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1891 ATTR_DIRECTORY);
1892 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1893 pSMB->ClusterCount = 0;
1894
1895 pSMB->BufferFormat = 0x04;
1896
1897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1898 name_len =
b1a45695 1899 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
737b758c 1900 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1901 name_len++; /* trailing null */
1902 name_len *= 2;
1903 pSMB->OldFileName[name_len] = 0; /* pad */
1904 pSMB->OldFileName[name_len + 1] = 0x04;
1905 name_len2 =
b1a45695 1906 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 1907 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1908 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1909 name_len2 *= 2; /* convert to bytes */
1910 } else { /* BB improve the check for buffer overruns BB */
1911 name_len = strnlen(fromName, PATH_MAX);
1912 name_len++; /* trailing null */
1913 strncpy(pSMB->OldFileName, fromName, name_len);
1914 name_len2 = strnlen(toName, PATH_MAX);
1915 name_len2++; /* trailing null */
1916 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1917 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1918 name_len2++; /* trailing null */
1919 name_len2++; /* signature byte */
1920 }
1921
1922 count = 1 /* string type byte */ + name_len + name_len2;
1923 pSMB->hdr.smb_buf_length += count;
1924 pSMB->ByteCount = cpu_to_le16(count);
1925
1926 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1927 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1928 cifs_stats_inc(&tcon->num_hardlinks);
1da177e4
LT
1929 if (rc) {
1930 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1931 }
1932 cifs_buf_release(pSMB);
1933 if (rc == -EAGAIN)
1934 goto winCreateHardLinkRetry;
1935
1936 return rc;
1937}
1938
1939int
1940CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1941 const unsigned char *searchName,
1942 char *symlinkinfo, const int buflen,
1943 const struct nls_table *nls_codepage)
1944{
1945/* SMB_QUERY_FILE_UNIX_LINK */
1946 TRANSACTION2_QPI_REQ *pSMB = NULL;
1947 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1948 int rc = 0;
1949 int bytes_returned;
1950 int name_len;
1951 __u16 params, byte_count;
1952
1953 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1954
1955querySymLinkRetry:
1956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1957 (void **) &pSMBr);
1958 if (rc)
1959 return rc;
1960
1961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1962 name_len =
e89dc920 1963 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1da177e4
LT
1964 /* find define for this maxpathcomponent */
1965 , nls_codepage);
1966 name_len++; /* trailing null */
1967 name_len *= 2;
1968 } else { /* BB improve the check for buffer overruns BB */
1969 name_len = strnlen(searchName, PATH_MAX);
1970 name_len++; /* trailing null */
1971 strncpy(pSMB->FileName, searchName, name_len);
1972 }
1973
1974 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1975 pSMB->TotalDataCount = 0;
1976 pSMB->MaxParameterCount = cpu_to_le16(2);
1977 /* BB find exact max data count below from sess structure BB */
1978 pSMB->MaxDataCount = cpu_to_le16(4000);
1979 pSMB->MaxSetupCount = 0;
1980 pSMB->Reserved = 0;
1981 pSMB->Flags = 0;
1982 pSMB->Timeout = 0;
1983 pSMB->Reserved2 = 0;
1984 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1985 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1986 pSMB->DataCount = 0;
1987 pSMB->DataOffset = 0;
1988 pSMB->SetupCount = 1;
1989 pSMB->Reserved3 = 0;
1990 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1991 byte_count = params + 1 /* pad */ ;
1992 pSMB->TotalParameterCount = cpu_to_le16(params);
1993 pSMB->ParameterCount = pSMB->TotalParameterCount;
1994 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1995 pSMB->Reserved4 = 0;
1996 pSMB->hdr.smb_buf_length += byte_count;
1997 pSMB->ByteCount = cpu_to_le16(byte_count);
1998
1999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2001 if (rc) {
2002 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2003 } else {
2004 /* decode response */
2005
2006 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2007 if (rc || (pSMBr->ByteCount < 2))
2008 /* BB also check enough total bytes returned */
2009 rc = -EIO; /* bad smb */
2010 else {
2011 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2012 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2013
2014 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2015 name_len = UniStrnlen((wchar_t *) ((char *)
2016 &pSMBr->hdr.Protocol +data_offset),
2017 min_t(const int, buflen,count) / 2);
737b758c 2018 /* BB FIXME investigate remapping reserved chars here */
1da177e4 2019 cifs_strfromUCS_le(symlinkinfo,
e89dc920 2020 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
1da177e4
LT
2021 data_offset),
2022 name_len, nls_codepage);
2023 } else {
2024 strncpy(symlinkinfo,
2025 (char *) &pSMBr->hdr.Protocol +
2026 data_offset,
2027 min_t(const int, buflen, count));
2028 }
2029 symlinkinfo[buflen] = 0;
2030 /* just in case so calling code does not go off the end of buffer */
2031 }
2032 }
2033 cifs_buf_release(pSMB);
2034 if (rc == -EAGAIN)
2035 goto querySymLinkRetry;
2036 return rc;
2037}
2038
0a4b92c0
SF
2039/* Initialize NT TRANSACT SMB into small smb request buffer.
2040 This assumes that all NT TRANSACTS that we init here have
2041 total parm and data under about 400 bytes (to fit in small cifs
2042 buffer size), which is the case so far, it easily fits. NB:
2043 Setup words themselves and ByteCount
2044 MaxSetupCount (size of returned setup area) and
2045 MaxParameterCount (returned parms size) must be set by caller */
2046static int
2047smb_init_ntransact(const __u16 sub_command, const int setup_count,
2048 const int parm_len, struct cifsTconInfo *tcon,
2049 void ** ret_buf)
2050{
2051 int rc;
2052 __u32 temp_offset;
2053 struct smb_com_ntransact_req * pSMB;
2054
2055 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2056 (void **)&pSMB);
2057 if (rc)
2058 return rc;
2059 *ret_buf = (void *)pSMB;
2060 pSMB->Reserved = 0;
2061 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2062 pSMB->TotalDataCount = 0;
2063 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2064 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2065 pSMB->ParameterCount = pSMB->TotalParameterCount;
2066 pSMB->DataCount = pSMB->TotalDataCount;
2067 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2068 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2069 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2070 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2071 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2072 pSMB->SubCommand = cpu_to_le16(sub_command);
2073 return 0;
2074}
2075
2076static int
2077validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2078 int * pdatalen, int * pparmlen)
2079{
2080 char * end_of_smb;
2081 __u32 data_count, data_offset, parm_count, parm_offset;
2082 struct smb_com_ntransact_rsp * pSMBr;
2083
2084 if(buf == NULL)
2085 return -EINVAL;
2086
2087 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2088
2089 /* ByteCount was converted from little endian in SendReceive */
2090 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2091 (char *)&pSMBr->ByteCount;
2092
2093
2094 data_offset = le32_to_cpu(pSMBr->DataOffset);
2095 data_count = le32_to_cpu(pSMBr->DataCount);
2096 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2097 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2098
2099 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2100 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2101
2102 /* should we also check that parm and data areas do not overlap? */
2103 if(*ppparm > end_of_smb) {
2104 cFYI(1,("parms start after end of smb"));
2105 return -EINVAL;
2106 } else if(parm_count + *ppparm > end_of_smb) {
2107 cFYI(1,("parm end after end of smb"));
2108 return -EINVAL;
2109 } else if(*ppdata > end_of_smb) {
2110 cFYI(1,("data starts after end of smb"));
2111 return -EINVAL;
2112 } else if(data_count + *ppdata > end_of_smb) {
2113 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2114 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2115 return -EINVAL;
2116 } else if(parm_count + data_count > pSMBr->ByteCount) {
2117 cFYI(1,("parm count and data count larger than SMB"));
2118 return -EINVAL;
2119 }
2120 return 0;
2121}
2122
1da177e4
LT
2123int
2124CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2125 const unsigned char *searchName,
2126 char *symlinkinfo, const int buflen,__u16 fid,
2127 const struct nls_table *nls_codepage)
2128{
2129 int rc = 0;
2130 int bytes_returned;
2131 int name_len;
2132 struct smb_com_transaction_ioctl_req * pSMB;
2133 struct smb_com_transaction_ioctl_rsp * pSMBr;
2134
2135 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2136 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2137 (void **) &pSMBr);
2138 if (rc)
2139 return rc;
2140
2141 pSMB->TotalParameterCount = 0 ;
2142 pSMB->TotalDataCount = 0;
2143 pSMB->MaxParameterCount = cpu_to_le32(2);
2144 /* BB find exact data count max from sess structure BB */
0a4b92c0
SF
2145 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2146 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1da177e4
LT
2147 pSMB->MaxSetupCount = 4;
2148 pSMB->Reserved = 0;
2149 pSMB->ParameterOffset = 0;
2150 pSMB->DataCount = 0;
2151 pSMB->DataOffset = 0;
2152 pSMB->SetupCount = 4;
2153 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2154 pSMB->ParameterCount = pSMB->TotalParameterCount;
2155 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2156 pSMB->IsFsctl = 1; /* FSCTL */
2157 pSMB->IsRootFlag = 0;
2158 pSMB->Fid = fid; /* file handle always le */
2159 pSMB->ByteCount = 0;
2160
2161 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2163 if (rc) {
2164 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2165 } else { /* decode response */
2166 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2167 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2168 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2169 /* BB also check enough total bytes returned */
2170 rc = -EIO; /* bad smb */
2171 else {
2172 if(data_count && (data_count < 2048)) {
0a4b92c0
SF
2173 char * end_of_smb = 2 /* sizeof byte count */ +
2174 pSMBr->ByteCount +
2175 (char *)&pSMBr->ByteCount;
1da177e4
LT
2176
2177 struct reparse_data * reparse_buf = (struct reparse_data *)
2178 ((char *)&pSMBr->hdr.Protocol + data_offset);
2179 if((char*)reparse_buf >= end_of_smb) {
2180 rc = -EIO;
2181 goto qreparse_out;
2182 }
2183 if((reparse_buf->LinkNamesBuf +
2184 reparse_buf->TargetNameOffset +
2185 reparse_buf->TargetNameLen) >
2186 end_of_smb) {
2187 cFYI(1,("reparse buf extended beyond SMB"));
2188 rc = -EIO;
2189 goto qreparse_out;
2190 }
2191
2192 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2193 name_len = UniStrnlen((wchar_t *)
2194 (reparse_buf->LinkNamesBuf +
2195 reparse_buf->TargetNameOffset),
2196 min(buflen/2, reparse_buf->TargetNameLen / 2));
2197 cifs_strfromUCS_le(symlinkinfo,
e89dc920 2198 (__le16 *) (reparse_buf->LinkNamesBuf +
1da177e4
LT
2199 reparse_buf->TargetNameOffset),
2200 name_len, nls_codepage);
2201 } else { /* ASCII names */
2202 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2203 reparse_buf->TargetNameOffset,
2204 min_t(const int, buflen, reparse_buf->TargetNameLen));
2205 }
2206 } else {
2207 rc = -EIO;
2208 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2209 }
2210 symlinkinfo[buflen] = 0; /* just in case so the caller
2211 does not go off the end of the buffer */
2212 cFYI(1,("readlink result - %s ",symlinkinfo));
2213 }
2214 }
2215qreparse_out:
4a6d87f1 2216 cifs_buf_release(pSMB);
1da177e4
LT
2217
2218 /* Note: On -EAGAIN error only caller can retry on handle based calls
2219 since file handle passed in no longer valid */
2220
2221 return rc;
2222}
2223
2224#ifdef CONFIG_CIFS_POSIX
2225
2226/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2227static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2228{
2229 /* u8 cifs fields do not need le conversion */
ff7feac9
SF
2230 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2231 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2232 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
1da177e4
LT
2233 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2234
2235 return;
2236}
2237
2238/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
737b758c
SF
2239static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2240 const int acl_type,const int size_of_data_area)
1da177e4
LT
2241{
2242 int size = 0;
2243 int i;
2244 __u16 count;
2245 struct cifs_posix_ace * pACE;
2246 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2247 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2248
2249 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2250 return -EOPNOTSUPP;
2251
2252 if(acl_type & ACL_TYPE_ACCESS) {
2253 count = le16_to_cpu(cifs_acl->access_entry_count);
2254 pACE = &cifs_acl->ace_array[0];
2255 size = sizeof(struct cifs_posix_acl);
2256 size += sizeof(struct cifs_posix_ace) * count;
2257 /* check if we would go beyond end of SMB */
2258 if(size_of_data_area < size) {
2259 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2260 return -EINVAL;
2261 }
2262 } else if(acl_type & ACL_TYPE_DEFAULT) {
2263 count = le16_to_cpu(cifs_acl->access_entry_count);
2264 size = sizeof(struct cifs_posix_acl);
2265 size += sizeof(struct cifs_posix_ace) * count;
2266/* skip past access ACEs to get to default ACEs */
2267 pACE = &cifs_acl->ace_array[count];
2268 count = le16_to_cpu(cifs_acl->default_entry_count);
2269 size += sizeof(struct cifs_posix_ace) * count;
2270 /* check if we would go beyond end of SMB */
2271 if(size_of_data_area < size)
2272 return -EINVAL;
2273 } else {
2274 /* illegal type */
2275 return -EINVAL;
2276 }
2277
2278 size = posix_acl_xattr_size(count);
2279 if((buflen == 0) || (local_acl == NULL)) {
2280 /* used to query ACL EA size */
2281 } else if(size > buflen) {
2282 return -ERANGE;
2283 } else /* buffer big enough */ {
ff7feac9 2284 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
1da177e4
LT
2285 for(i = 0;i < count ;i++) {
2286 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2287 pACE ++;
2288 }
2289 }
2290 return size;
2291}
2292
2293static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2294 const posix_acl_xattr_entry * local_ace)
2295{
2296 __u16 rc = 0; /* 0 = ACL converted ok */
2297
ff7feac9
SF
2298 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2299 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
1da177e4 2300 /* BB is there a better way to handle the large uid? */
ff7feac9 2301 if(local_ace->e_id == cpu_to_le32(-1)) {
1da177e4
LT
2302 /* Probably no need to le convert -1 on any arch but can not hurt */
2303 cifs_ace->cifs_uid = cpu_to_le64(-1);
2304 } else
ff7feac9 2305 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
1da177e4
LT
2306 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2307 return rc;
2308}
2309
2310/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2311static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2312 const int acl_type)
2313{
2314 __u16 rc = 0;
2315 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2316 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2317 int count;
2318 int i;
2319
2320 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2321 return 0;
2322
2323 count = posix_acl_xattr_count((size_t)buflen);
2324 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
ff7feac9
SF
2325 count, buflen, le32_to_cpu(local_acl->a_version)));
2326 if(le32_to_cpu(local_acl->a_version) != 2) {
2327 cFYI(1,("unknown POSIX ACL version %d",
2328 le32_to_cpu(local_acl->a_version)));
1da177e4
LT
2329 return 0;
2330 }
2331 cifs_acl->version = cpu_to_le16(1);
2332 if(acl_type == ACL_TYPE_ACCESS)
ff7feac9 2333 cifs_acl->access_entry_count = cpu_to_le16(count);
1da177e4 2334 else if(acl_type == ACL_TYPE_DEFAULT)
ff7feac9 2335 cifs_acl->default_entry_count = cpu_to_le16(count);
1da177e4
LT
2336 else {
2337 cFYI(1,("unknown ACL type %d",acl_type));
2338 return 0;
2339 }
2340 for(i=0;i<count;i++) {
2341 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2342 &local_acl->a_entries[i]);
2343 if(rc != 0) {
2344 /* ACE not converted */
2345 break;
2346 }
2347 }
2348 if(rc == 0) {
2349 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2350 rc += sizeof(struct cifs_posix_acl);
2351 /* BB add check to make sure ACL does not overflow SMB */
2352 }
2353 return rc;
2354}
2355
2356int
2357CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2358 const unsigned char *searchName,
2359 char *acl_inf, const int buflen, const int acl_type,
737b758c 2360 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2361{
2362/* SMB_QUERY_POSIX_ACL */
2363 TRANSACTION2_QPI_REQ *pSMB = NULL;
2364 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2365 int rc = 0;
2366 int bytes_returned;
2367 int name_len;
2368 __u16 params, byte_count;
2369
2370 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2371
2372queryAclRetry:
2373 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2374 (void **) &pSMBr);
2375 if (rc)
2376 return rc;
2377
2378 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2379 name_len =
b1a45695 2380 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 2381 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2382 name_len++; /* trailing null */
2383 name_len *= 2;
2384 pSMB->FileName[name_len] = 0;
2385 pSMB->FileName[name_len+1] = 0;
2386 } else { /* BB improve the check for buffer overruns BB */
2387 name_len = strnlen(searchName, PATH_MAX);
2388 name_len++; /* trailing null */
2389 strncpy(pSMB->FileName, searchName, name_len);
2390 }
2391
2392 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2393 pSMB->TotalDataCount = 0;
2394 pSMB->MaxParameterCount = cpu_to_le16(2);
2395 /* BB find exact max data count below from sess structure BB */
2396 pSMB->MaxDataCount = cpu_to_le16(4000);
2397 pSMB->MaxSetupCount = 0;
2398 pSMB->Reserved = 0;
2399 pSMB->Flags = 0;
2400 pSMB->Timeout = 0;
2401 pSMB->Reserved2 = 0;
2402 pSMB->ParameterOffset = cpu_to_le16(
2403 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2404 pSMB->DataCount = 0;
2405 pSMB->DataOffset = 0;
2406 pSMB->SetupCount = 1;
2407 pSMB->Reserved3 = 0;
2408 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2409 byte_count = params + 1 /* pad */ ;
2410 pSMB->TotalParameterCount = cpu_to_le16(params);
2411 pSMB->ParameterCount = pSMB->TotalParameterCount;
2412 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2413 pSMB->Reserved4 = 0;
2414 pSMB->hdr.smb_buf_length += byte_count;
2415 pSMB->ByteCount = cpu_to_le16(byte_count);
2416
2417 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2418 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
0a4b92c0 2419 cifs_stats_inc(&tcon->num_acl_get);
1da177e4
LT
2420 if (rc) {
2421 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2422 } else {
2423 /* decode response */
2424
2425 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2426 if (rc || (pSMBr->ByteCount < 2))
2427 /* BB also check enough total bytes returned */
2428 rc = -EIO; /* bad smb */
2429 else {
2430 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2431 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2432 rc = cifs_copy_posix_acl(acl_inf,
2433 (char *)&pSMBr->hdr.Protocol+data_offset,
2434 buflen,acl_type,count);
2435 }
2436 }
2437 cifs_buf_release(pSMB);
2438 if (rc == -EAGAIN)
2439 goto queryAclRetry;
2440 return rc;
2441}
2442
2443int
2444CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2445 const unsigned char *fileName,
737b758c
SF
2446 const char *local_acl, const int buflen,
2447 const int acl_type,
2448 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2449{
2450 struct smb_com_transaction2_spi_req *pSMB = NULL;
2451 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2452 char *parm_data;
2453 int name_len;
2454 int rc = 0;
2455 int bytes_returned = 0;
2456 __u16 params, byte_count, data_count, param_offset, offset;
2457
2458 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2459setAclRetry:
2460 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2461 (void **) &pSMBr);
2462 if (rc)
2463 return rc;
2464 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2465 name_len =
b1a45695 2466 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 2467 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2468 name_len++; /* trailing null */
2469 name_len *= 2;
2470 } else { /* BB improve the check for buffer overruns BB */
2471 name_len = strnlen(fileName, PATH_MAX);
2472 name_len++; /* trailing null */
2473 strncpy(pSMB->FileName, fileName, name_len);
2474 }
2475 params = 6 + name_len;
2476 pSMB->MaxParameterCount = cpu_to_le16(2);
2477 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2478 pSMB->MaxSetupCount = 0;
2479 pSMB->Reserved = 0;
2480 pSMB->Flags = 0;
2481 pSMB->Timeout = 0;
2482 pSMB->Reserved2 = 0;
2483 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2484 InformationLevel) - 4;
2485 offset = param_offset + params;
2486 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2487 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2488
2489 /* convert to on the wire format for POSIX ACL */
2490 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2491
2492 if(data_count == 0) {
2493 rc = -EOPNOTSUPP;
2494 goto setACLerrorExit;
2495 }
2496 pSMB->DataOffset = cpu_to_le16(offset);
2497 pSMB->SetupCount = 1;
2498 pSMB->Reserved3 = 0;
2499 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2500 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2501 byte_count = 3 /* pad */ + params + data_count;
2502 pSMB->DataCount = cpu_to_le16(data_count);
2503 pSMB->TotalDataCount = pSMB->DataCount;
2504 pSMB->ParameterCount = cpu_to_le16(params);
2505 pSMB->TotalParameterCount = pSMB->ParameterCount;
2506 pSMB->Reserved4 = 0;
2507 pSMB->hdr.smb_buf_length += byte_count;
2508 pSMB->ByteCount = cpu_to_le16(byte_count);
2509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2511 if (rc) {
2512 cFYI(1, ("Set POSIX ACL returned %d", rc));
2513 }
2514
2515setACLerrorExit:
2516 cifs_buf_release(pSMB);
2517 if (rc == -EAGAIN)
2518 goto setAclRetry;
2519 return rc;
2520}
2521
f654bac2
SF
2522/* BB fix tabs in this function FIXME BB */
2523int
2524CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2525 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2526{
2527 int rc = 0;
2528 struct smb_t2_qfi_req *pSMB = NULL;
2529 struct smb_t2_qfi_rsp *pSMBr = NULL;
2530 int bytes_returned;
2531 __u16 params, byte_count;
2532
2533 cFYI(1,("In GetExtAttr"));
2534 if(tcon == NULL)
2535 return -ENODEV;
2536
2537GetExtAttrRetry:
2538 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2539 (void **) &pSMBr);
2540 if (rc)
2541 return rc;
2542
c67593a0 2543 params = 2 /* level */ +2 /* fid */;
f654bac2 2544 pSMB->t2.TotalDataCount = 0;
c67593a0 2545 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
f654bac2
SF
2546 /* BB find exact max data count below from sess structure BB */
2547 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2548 pSMB->t2.MaxSetupCount = 0;
2549 pSMB->t2.Reserved = 0;
2550 pSMB->t2.Flags = 0;
2551 pSMB->t2.Timeout = 0;
2552 pSMB->t2.Reserved2 = 0;
c67593a0
SF
2553 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2554 Fid) - 4);
f654bac2
SF
2555 pSMB->t2.DataCount = 0;
2556 pSMB->t2.DataOffset = 0;
2557 pSMB->t2.SetupCount = 1;
2558 pSMB->t2.Reserved3 = 0;
2559 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
c67593a0 2560 byte_count = params + 1 /* pad */ ;
f654bac2
SF
2561 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2562 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2563 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
c67593a0 2564 pSMB->Pad = 0;
f654bac2
SF
2565 pSMB->Fid = netfid;
2566 pSMB->hdr.smb_buf_length += byte_count;
2567 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2568
2569 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2570 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2571 if (rc) {
2572 cFYI(1, ("error %d in GetExtAttr", rc));
2573 } else {
2574 /* decode response */
2575 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2576 if (rc || (pSMBr->ByteCount < 2))
2577 /* BB also check enough total bytes returned */
2578 /* If rc should we check for EOPNOSUPP and
2579 disable the srvino flag? or in caller? */
2580 rc = -EIO; /* bad smb */
2581 else {
2582 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2583 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2584 struct file_chattr_info * pfinfo;
2585 /* BB Do we need a cast or hash here ? */
2586 if(count != 16) {
2587 cFYI(1, ("Illegal size ret in GetExtAttr"));
2588 rc = -EIO;
2589 goto GetExtAttrOut;
2590 }
2591 pfinfo = (struct file_chattr_info *)
2592 (data_offset + (char *) &pSMBr->hdr.Protocol);
2593 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2594 *pMask = le64_to_cpu(pfinfo->mask);
2595 }
2596 }
2597GetExtAttrOut:
2598 cifs_buf_release(pSMB);
2599 if (rc == -EAGAIN)
2600 goto GetExtAttrRetry;
2601 return rc;
2602}
2603
2604
2605#endif /* CONFIG_POSIX */
1da177e4 2606
eeac8047
SF
2607
2608/* security id for everyone */
2609const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2610/* group users */
2611const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2612
0a4b92c0 2613/* Convert CIFS ACL to POSIX form */
eeac8047 2614static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
0a4b92c0 2615{
0a4b92c0
SF
2616 return 0;
2617}
2618
2619/* Get Security Descriptor (by handle) from remote server for a file or dir */
2620int
2621CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2622 /* BB fix up return info */ char *acl_inf, const int buflen,
2623 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2624{
2625 int rc = 0;
2626 int buf_type = 0;
2627 QUERY_SEC_DESC_REQ * pSMB;
2628 struct kvec iov[1];
2629
2630 cFYI(1, ("GetCifsACL"));
2631
2632 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2633 8 /* parm len */, tcon, (void **) &pSMB);
2634 if (rc)
2635 return rc;
2636
2637 pSMB->MaxParameterCount = cpu_to_le32(4);
2638 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2639 pSMB->MaxSetupCount = 0;
2640 pSMB->Fid = fid; /* file handle always le */
2641 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2642 CIFS_ACL_DACL);
2643 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2644 pSMB->hdr.smb_buf_length += 11;
2645 iov[0].iov_base = (char *)pSMB;
2646 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2647
2648 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2649 cifs_stats_inc(&tcon->num_acl_get);
2650 if (rc) {
2651 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2652 } else { /* decode response */
d41f084a 2653 struct cifs_sid * psec_desc;
0a4b92c0
SF
2654 __le32 * parm;
2655 int parm_len;
2656 int data_len;
2657 int acl_len;
2658 struct smb_com_ntransact_rsp * pSMBr;
2659
2660/* validate_nttransact */
2661 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2662 (char **)&psec_desc,
2663 &parm_len, &data_len);
2664
2665 if(rc)
2666 goto qsec_out;
2667 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2668
2669 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2670
2671 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2672 rc = -EIO; /* bad smb */
2673 goto qsec_out;
2674 }
2675
2676/* BB check that data area is minimum length and as big as acl_len */
2677
2678 acl_len = le32_to_cpu(*(__le32 *)parm);
2679 /* BB check if(acl_len > bufsize) */
2680
2681 parse_sec_desc(psec_desc, acl_len);
2682 }
2683qsec_out:
2684 if(buf_type == CIFS_SMALL_BUFFER)
2685 cifs_small_buf_release(iov[0].iov_base);
2686 else if(buf_type == CIFS_LARGE_BUFFER)
2687 cifs_buf_release(iov[0].iov_base);
4b8f930f 2688/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
0a4b92c0
SF
2689 return rc;
2690}
2691
2692
6b8edfe0
SF
2693/* Legacy Query Path Information call for lookup to old servers such
2694 as Win9x/WinME */
2695int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2696 const unsigned char *searchName,
2697 FILE_ALL_INFO * pFinfo,
2698 const struct nls_table *nls_codepage, int remap)
2699{
2700 QUERY_INFORMATION_REQ * pSMB;
2701 QUERY_INFORMATION_RSP * pSMBr;
2702 int rc = 0;
2703 int bytes_returned;
2704 int name_len;
2705
2706 cFYI(1, ("In SMBQPath path %s", searchName));
2707QInfRetry:
2708 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2709 (void **) &pSMBr);
2710 if (rc)
2711 return rc;
2712
2713 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2714 name_len =
2715 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2716 PATH_MAX, nls_codepage, remap);
2717 name_len++; /* trailing null */
2718 name_len *= 2;
2719 } else {
2720 name_len = strnlen(searchName, PATH_MAX);
2721 name_len++; /* trailing null */
2722 strncpy(pSMB->FileName, searchName, name_len);
2723 }
2724 pSMB->BufferFormat = 0x04;
2725 name_len++; /* account for buffer type byte */
2726 pSMB->hdr.smb_buf_length += (__u16) name_len;
2727 pSMB->ByteCount = cpu_to_le16(name_len);
2728
2729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2731 if (rc) {
2732 cFYI(1, ("Send error in QueryInfo = %d", rc));
2733 } else if (pFinfo) { /* decode response */
2734 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
70ca734a
SF
2735 pFinfo->AllocationSize =
2736 cpu_to_le64(le32_to_cpu(pSMBr->size));
2737 pFinfo->EndOfFile = pFinfo->AllocationSize;
2738 pFinfo->Attributes =
2739 cpu_to_le32(le16_to_cpu(pSMBr->attr));
6b8edfe0
SF
2740 } else
2741 rc = -EIO; /* bad buffer passed in */
2742
2743 cifs_buf_release(pSMB);
2744
2745 if (rc == -EAGAIN)
2746 goto QInfRetry;
2747
2748 return rc;
2749}
2750
2751
2752
2753
1da177e4
LT
2754int
2755CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2756 const unsigned char *searchName,
2757 FILE_ALL_INFO * pFindData,
737b758c 2758 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2759{
2760/* level 263 SMB_QUERY_FILE_ALL_INFO */
2761 TRANSACTION2_QPI_REQ *pSMB = NULL;
2762 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2763 int rc = 0;
2764 int bytes_returned;
2765 int name_len;
2766 __u16 params, byte_count;
2767
2768/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2769QPathInfoRetry:
2770 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2771 (void **) &pSMBr);
2772 if (rc)
2773 return rc;
2774
2775 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2776 name_len =
b1a45695 2777 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 2778 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2779 name_len++; /* trailing null */
2780 name_len *= 2;
2781 } else { /* BB improve the check for buffer overruns BB */
2782 name_len = strnlen(searchName, PATH_MAX);
2783 name_len++; /* trailing null */
2784 strncpy(pSMB->FileName, searchName, name_len);
2785 }
2786
2787 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2788 pSMB->TotalDataCount = 0;
2789 pSMB->MaxParameterCount = cpu_to_le16(2);
2790 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2791 pSMB->MaxSetupCount = 0;
2792 pSMB->Reserved = 0;
2793 pSMB->Flags = 0;
2794 pSMB->Timeout = 0;
2795 pSMB->Reserved2 = 0;
2796 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2797 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2798 pSMB->DataCount = 0;
2799 pSMB->DataOffset = 0;
2800 pSMB->SetupCount = 1;
2801 pSMB->Reserved3 = 0;
2802 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2803 byte_count = params + 1 /* pad */ ;
2804 pSMB->TotalParameterCount = cpu_to_le16(params);
2805 pSMB->ParameterCount = pSMB->TotalParameterCount;
2806 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2807 pSMB->Reserved4 = 0;
2808 pSMB->hdr.smb_buf_length += byte_count;
2809 pSMB->ByteCount = cpu_to_le16(byte_count);
2810
2811 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2813 if (rc) {
2814 cFYI(1, ("Send error in QPathInfo = %d", rc));
2815 } else { /* decode response */
2816 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2817
2818 if (rc || (pSMBr->ByteCount < 40))
2819 rc = -EIO; /* bad smb */
2820 else if (pFindData){
2821 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2822 memcpy((char *) pFindData,
2823 (char *) &pSMBr->hdr.Protocol +
2824 data_offset, sizeof (FILE_ALL_INFO));
2825 } else
2826 rc = -ENOMEM;
2827 }
2828 cifs_buf_release(pSMB);
2829 if (rc == -EAGAIN)
2830 goto QPathInfoRetry;
2831
2832 return rc;
2833}
2834
2835int
2836CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2837 const unsigned char *searchName,
2838 FILE_UNIX_BASIC_INFO * pFindData,
737b758c 2839 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2840{
2841/* SMB_QUERY_FILE_UNIX_BASIC */
2842 TRANSACTION2_QPI_REQ *pSMB = NULL;
2843 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2844 int rc = 0;
2845 int bytes_returned = 0;
2846 int name_len;
2847 __u16 params, byte_count;
2848
2849 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2850UnixQPathInfoRetry:
2851 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2852 (void **) &pSMBr);
2853 if (rc)
2854 return rc;
2855
2856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2857 name_len =
b1a45695 2858 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 2859 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2860 name_len++; /* trailing null */
2861 name_len *= 2;
2862 } else { /* BB improve the check for buffer overruns BB */
2863 name_len = strnlen(searchName, PATH_MAX);
2864 name_len++; /* trailing null */
2865 strncpy(pSMB->FileName, searchName, name_len);
2866 }
2867
2868 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2869 pSMB->TotalDataCount = 0;
2870 pSMB->MaxParameterCount = cpu_to_le16(2);
2871 /* BB find exact max SMB PDU from sess structure BB */
2872 pSMB->MaxDataCount = cpu_to_le16(4000);
2873 pSMB->MaxSetupCount = 0;
2874 pSMB->Reserved = 0;
2875 pSMB->Flags = 0;
2876 pSMB->Timeout = 0;
2877 pSMB->Reserved2 = 0;
2878 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2879 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2880 pSMB->DataCount = 0;
2881 pSMB->DataOffset = 0;
2882 pSMB->SetupCount = 1;
2883 pSMB->Reserved3 = 0;
2884 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2885 byte_count = params + 1 /* pad */ ;
2886 pSMB->TotalParameterCount = cpu_to_le16(params);
2887 pSMB->ParameterCount = pSMB->TotalParameterCount;
2888 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2889 pSMB->Reserved4 = 0;
2890 pSMB->hdr.smb_buf_length += byte_count;
2891 pSMB->ByteCount = cpu_to_le16(byte_count);
2892
2893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2895 if (rc) {
2896 cFYI(1, ("Send error in QPathInfo = %d", rc));
2897 } else { /* decode response */
2898 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2899
2900 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2901 rc = -EIO; /* bad smb */
2902 } else {
2903 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2904 memcpy((char *) pFindData,
2905 (char *) &pSMBr->hdr.Protocol +
2906 data_offset,
2907 sizeof (FILE_UNIX_BASIC_INFO));
2908 }
2909 }
2910 cifs_buf_release(pSMB);
2911 if (rc == -EAGAIN)
2912 goto UnixQPathInfoRetry;
2913
2914 return rc;
2915}
2916
2917#if 0 /* function unused at present */
2918int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2919 const char *searchName, FILE_ALL_INFO * findData,
2920 const struct nls_table *nls_codepage)
2921{
2922/* level 257 SMB_ */
2923 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2924 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2925 int rc = 0;
2926 int bytes_returned;
2927 int name_len;
2928 __u16 params, byte_count;
2929
2930 cFYI(1, ("In FindUnique"));
2931findUniqueRetry:
2932 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2933 (void **) &pSMBr);
2934 if (rc)
2935 return rc;
2936
2937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2938 name_len =
b1a45695 2939 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
1da177e4
LT
2940 /* find define for this maxpathcomponent */
2941 , nls_codepage);
2942 name_len++; /* trailing null */
2943 name_len *= 2;
2944 } else { /* BB improve the check for buffer overruns BB */
2945 name_len = strnlen(searchName, PATH_MAX);
2946 name_len++; /* trailing null */
2947 strncpy(pSMB->FileName, searchName, name_len);
2948 }
2949
2950 params = 12 + name_len /* includes null */ ;
2951 pSMB->TotalDataCount = 0; /* no EAs */
2952 pSMB->MaxParameterCount = cpu_to_le16(2);
2953 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2954 pSMB->MaxSetupCount = 0;
2955 pSMB->Reserved = 0;
2956 pSMB->Flags = 0;
2957 pSMB->Timeout = 0;
2958 pSMB->Reserved2 = 0;
2959 pSMB->ParameterOffset = cpu_to_le16(
2960 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2961 pSMB->DataCount = 0;
2962 pSMB->DataOffset = 0;
2963 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2964 pSMB->Reserved3 = 0;
2965 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2966 byte_count = params + 1 /* pad */ ;
2967 pSMB->TotalParameterCount = cpu_to_le16(params);
2968 pSMB->ParameterCount = pSMB->TotalParameterCount;
2969 pSMB->SearchAttributes =
2970 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2971 ATTR_DIRECTORY);
2972 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2973 pSMB->SearchFlags = cpu_to_le16(1);
2974 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2975 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2976 pSMB->hdr.smb_buf_length += byte_count;
2977 pSMB->ByteCount = cpu_to_le16(byte_count);
2978
2979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2981
2982 if (rc) {
2983 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2984 } else { /* decode response */
a4544347 2985 cifs_stats_inc(&tcon->num_ffirst);
1da177e4
LT
2986 /* BB fill in */
2987 }
2988
2989 cifs_buf_release(pSMB);
2990 if (rc == -EAGAIN)
2991 goto findUniqueRetry;
2992
2993 return rc;
2994}
2995#endif /* end unused (temporarily) function */
2996
2997/* xid, tcon, searchName and codepage are input parms, rest are returned */
2998int
2999CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3000 const char *searchName,
3001 const struct nls_table *nls_codepage,
3002 __u16 * pnetfid,
ac67055e 3003 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
1da177e4
LT
3004{
3005/* level 257 SMB_ */
3006 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3007 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3008 T2_FFIRST_RSP_PARMS * parms;
3009 int rc = 0;
3010 int bytes_returned = 0;
3011 int name_len;
3012 __u16 params, byte_count;
3013
737b758c 3014 cFYI(1, ("In FindFirst for %s",searchName));
1da177e4
LT
3015
3016findFirstRetry:
3017 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3018 (void **) &pSMBr);
3019 if (rc)
3020 return rc;
3021
3022 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3023 name_len =
b1a45695 3024 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
737b758c
SF
3025 PATH_MAX, nls_codepage, remap);
3026 /* We can not add the asterik earlier in case
3027 it got remapped to 0xF03A as if it were part of the
3028 directory name instead of a wildcard */
1da177e4 3029 name_len *= 2;
ac67055e 3030 pSMB->FileName[name_len] = dirsep;
737b758c
SF
3031 pSMB->FileName[name_len+1] = 0;
3032 pSMB->FileName[name_len+2] = '*';
3033 pSMB->FileName[name_len+3] = 0;
3034 name_len += 4; /* now the trailing null */
1da177e4
LT
3035 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3036 pSMB->FileName[name_len+1] = 0;
737b758c 3037 name_len += 2;
1da177e4
LT
3038 } else { /* BB add check for overrun of SMB buf BB */
3039 name_len = strnlen(searchName, PATH_MAX);
1da177e4
LT
3040/* BB fix here and in unicode clause above ie
3041 if(name_len > buffersize-header)
3042 free buffer exit; BB */
3043 strncpy(pSMB->FileName, searchName, name_len);
ac67055e 3044 pSMB->FileName[name_len] = dirsep;
68575476
SF
3045 pSMB->FileName[name_len+1] = '*';
3046 pSMB->FileName[name_len+2] = 0;
3047 name_len += 3;
1da177e4
LT
3048 }
3049
3050 params = 12 + name_len /* includes null */ ;
3051 pSMB->TotalDataCount = 0; /* no EAs */
3052 pSMB->MaxParameterCount = cpu_to_le16(10);
3053 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3054 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3055 pSMB->MaxSetupCount = 0;
3056 pSMB->Reserved = 0;
3057 pSMB->Flags = 0;
3058 pSMB->Timeout = 0;
3059 pSMB->Reserved2 = 0;
3060 byte_count = params + 1 /* pad */ ;
3061 pSMB->TotalParameterCount = cpu_to_le16(params);
3062 pSMB->ParameterCount = pSMB->TotalParameterCount;
3063 pSMB->ParameterOffset = cpu_to_le16(
3064 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
3065 pSMB->DataCount = 0;
3066 pSMB->DataOffset = 0;
3067 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3068 pSMB->Reserved3 = 0;
3069 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3070 pSMB->SearchAttributes =
3071 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3072 ATTR_DIRECTORY);
3073 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3074 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3075 CIFS_SEARCH_RETURN_RESUME);
3076 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3077
3078 /* BB what should we set StorageType to? Does it matter? BB */
3079 pSMB->SearchStorageType = 0;
3080 pSMB->hdr.smb_buf_length += byte_count;
3081 pSMB->ByteCount = cpu_to_le16(byte_count);
3082
3083 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 3085 cifs_stats_inc(&tcon->num_ffirst);
1da177e4 3086
1982c344 3087 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
1da177e4
LT
3088 /* BB Add code to handle unsupported level rc */
3089 cFYI(1, ("Error in FindFirst = %d", rc));
1982c344
SF
3090
3091 if (pSMB)
3092 cifs_buf_release(pSMB);
1da177e4
LT
3093
3094 /* BB eventually could optimize out free and realloc of buf */
3095 /* for this case */
3096 if (rc == -EAGAIN)
3097 goto findFirstRetry;
3098 } else { /* decode response */
3099 /* BB remember to free buffer if error BB */
3100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3101 if(rc == 0) {
3102 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3103 psrch_inf->unicode = TRUE;
3104 else
3105 psrch_inf->unicode = FALSE;
3106
3107 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
d47d7c1a 3108 psrch_inf->smallBuf = 0;
1da177e4
LT
3109 psrch_inf->srch_entries_start =
3110 (char *) &pSMBr->hdr.Protocol +
3111 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
3112 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3113 le16_to_cpu(pSMBr->t2.ParameterOffset));
3114
3115 if(parms->EndofSearch)
3116 psrch_inf->endOfSearch = TRUE;
3117 else
3118 psrch_inf->endOfSearch = FALSE;
3119
3120 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3121 psrch_inf->index_of_last_entry =
3122 psrch_inf->entries_in_buffer;
1da177e4
LT
3123 *pnetfid = parms->SearchHandle;
3124 } else {
3125 cifs_buf_release(pSMB);
3126 }
3127 }
3128
3129 return rc;
3130}
3131
3132int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3133 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3134{
3135 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3136 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3137 T2_FNEXT_RSP_PARMS * parms;
3138 char *response_data;
3139 int rc = 0;
3140 int bytes_returned, name_len;
3141 __u16 params, byte_count;
3142
3143 cFYI(1, ("In FindNext"));
3144
3145 if(psrch_inf->endOfSearch == TRUE)
3146 return -ENOENT;
3147
3148 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3149 (void **) &pSMBr);
3150 if (rc)
3151 return rc;
3152
3153 params = 14; /* includes 2 bytes of null string, converted to LE below */
3154 byte_count = 0;
3155 pSMB->TotalDataCount = 0; /* no EAs */
3156 pSMB->MaxParameterCount = cpu_to_le16(8);
3157 pSMB->MaxDataCount =
3158 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3159 pSMB->MaxSetupCount = 0;
3160 pSMB->Reserved = 0;
3161 pSMB->Flags = 0;
3162 pSMB->Timeout = 0;
3163 pSMB->Reserved2 = 0;
3164 pSMB->ParameterOffset = cpu_to_le16(
3165 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3166 pSMB->DataCount = 0;
3167 pSMB->DataOffset = 0;
3168 pSMB->SetupCount = 1;
3169 pSMB->Reserved3 = 0;
3170 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3171 pSMB->SearchHandle = searchHandle; /* always kept as le */
3172 pSMB->SearchCount =
3173 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3174 /* test for Unix extensions */
3175/* if (tcon->ses->capabilities & CAP_UNIX) {
3176 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3177 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3178 } else {
3179 pSMB->InformationLevel =
3180 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3181 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3182 } */
3183 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3184 pSMB->ResumeKey = psrch_inf->resume_key;
3185 pSMB->SearchFlags =
3186 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3187
3188 name_len = psrch_inf->resume_name_len;
3189 params += name_len;
3190 if(name_len < PATH_MAX) {
3191 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3192 byte_count += name_len;
ef6724e3
SF
3193 /* 14 byte parm len above enough for 2 byte null terminator */
3194 pSMB->ResumeFileName[name_len] = 0;
3195 pSMB->ResumeFileName[name_len+1] = 0;
1da177e4
LT
3196 } else {
3197 rc = -EINVAL;
3198 goto FNext2_err_exit;
3199 }
3200 byte_count = params + 1 /* pad */ ;
3201 pSMB->TotalParameterCount = cpu_to_le16(params);
3202 pSMB->ParameterCount = pSMB->TotalParameterCount;
3203 pSMB->hdr.smb_buf_length += byte_count;
3204 pSMB->ByteCount = cpu_to_le16(byte_count);
3205
3206 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3207 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 3208 cifs_stats_inc(&tcon->num_fnext);
1da177e4
LT
3209 if (rc) {
3210 if (rc == -EBADF) {
3211 psrch_inf->endOfSearch = TRUE;
3212 rc = 0; /* search probably was closed at end of search above */
3213 } else
3214 cFYI(1, ("FindNext returned = %d", rc));
3215 } else { /* decode response */
3216 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3217
3218 if(rc == 0) {
3219 /* BB fixme add lock for file (srch_info) struct here */
3220 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3221 psrch_inf->unicode = TRUE;
3222 else
3223 psrch_inf->unicode = FALSE;
3224 response_data = (char *) &pSMBr->hdr.Protocol +
3225 le16_to_cpu(pSMBr->t2.ParameterOffset);
3226 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3227 response_data = (char *)&pSMBr->hdr.Protocol +
3228 le16_to_cpu(pSMBr->t2.DataOffset);
d47d7c1a
SF
3229 if(psrch_inf->smallBuf)
3230 cifs_small_buf_release(
3231 psrch_inf->ntwrk_buf_start);
3232 else
3233 cifs_buf_release(psrch_inf->ntwrk_buf_start);
1da177e4
LT
3234 psrch_inf->srch_entries_start = response_data;
3235 psrch_inf->ntwrk_buf_start = (char *)pSMB;
d47d7c1a 3236 psrch_inf->smallBuf = 0;
1da177e4
LT
3237 if(parms->EndofSearch)
3238 psrch_inf->endOfSearch = TRUE;
3239 else
3240 psrch_inf->endOfSearch = FALSE;
3241
3242 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3243 psrch_inf->index_of_last_entry +=
3244 psrch_inf->entries_in_buffer;
3245/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3246
3247 /* BB fixme add unlock here */
3248 }
3249
3250 }
3251
3252 /* BB On error, should we leave previous search buf (and count and
3253 last entry fields) intact or free the previous one? */
3254
3255 /* Note: On -EAGAIN error only caller can retry on handle based calls
3256 since file handle passed in no longer valid */
3257FNext2_err_exit:
3258 if (rc != 0)
3259 cifs_buf_release(pSMB);
3260
3261 return rc;
3262}
3263
3264int
3265CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3266{
3267 int rc = 0;
3268 FINDCLOSE_REQ *pSMB = NULL;
3269 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3270 int bytes_returned;
3271
3272 cFYI(1, ("In CIFSSMBFindClose"));
3273 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3274
3275 /* no sense returning error if session restarted
3276 as file handle has been closed */
3277 if(rc == -EAGAIN)
3278 return 0;
3279 if (rc)
3280 return rc;
3281
3282 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3283 pSMB->FileID = searchHandle;
3284 pSMB->ByteCount = 0;
3285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3287 if (rc) {
3288 cERROR(1, ("Send error in FindClose = %d", rc));
3289 }
a4544347 3290 cifs_stats_inc(&tcon->num_fclose);
1da177e4
LT
3291 cifs_small_buf_release(pSMB);
3292
3293 /* Since session is dead, search handle closed on server already */
3294 if (rc == -EAGAIN)
3295 rc = 0;
3296
3297 return rc;
3298}
3299
1da177e4
LT
3300int
3301CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3302 const unsigned char *searchName,
3303 __u64 * inode_number,
737b758c 3304 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3305{
3306 int rc = 0;
3307 TRANSACTION2_QPI_REQ *pSMB = NULL;
3308 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3309 int name_len, bytes_returned;
3310 __u16 params, byte_count;
3311
3312 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3313 if(tcon == NULL)
3314 return -ENODEV;
3315
3316GetInodeNumberRetry:
3317 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3318 (void **) &pSMBr);
3319 if (rc)
3320 return rc;
3321
3322
3323 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3324 name_len =
b1a45695 3325 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 3326 PATH_MAX,nls_codepage, remap);
1da177e4
LT
3327 name_len++; /* trailing null */
3328 name_len *= 2;
3329 } else { /* BB improve the check for buffer overruns BB */
3330 name_len = strnlen(searchName, PATH_MAX);
3331 name_len++; /* trailing null */
3332 strncpy(pSMB->FileName, searchName, name_len);
3333 }
3334
3335 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3336 pSMB->TotalDataCount = 0;
3337 pSMB->MaxParameterCount = cpu_to_le16(2);
3338 /* BB find exact max data count below from sess structure BB */
3339 pSMB->MaxDataCount = cpu_to_le16(4000);
3340 pSMB->MaxSetupCount = 0;
3341 pSMB->Reserved = 0;
3342 pSMB->Flags = 0;
3343 pSMB->Timeout = 0;
3344 pSMB->Reserved2 = 0;
3345 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3346 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3347 pSMB->DataCount = 0;
3348 pSMB->DataOffset = 0;
3349 pSMB->SetupCount = 1;
3350 pSMB->Reserved3 = 0;
3351 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3352 byte_count = params + 1 /* pad */ ;
3353 pSMB->TotalParameterCount = cpu_to_le16(params);
3354 pSMB->ParameterCount = pSMB->TotalParameterCount;
3355 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3356 pSMB->Reserved4 = 0;
3357 pSMB->hdr.smb_buf_length += byte_count;
3358 pSMB->ByteCount = cpu_to_le16(byte_count);
3359
3360 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3361 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3362 if (rc) {
3363 cFYI(1, ("error %d in QueryInternalInfo", rc));
3364 } else {
3365 /* decode response */
3366 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3367 if (rc || (pSMBr->ByteCount < 2))
3368 /* BB also check enough total bytes returned */
3369 /* If rc should we check for EOPNOSUPP and
3370 disable the srvino flag? or in caller? */
3371 rc = -EIO; /* bad smb */
3372 else {
3373 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3374 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3375 struct file_internal_info * pfinfo;
3376 /* BB Do we need a cast or hash here ? */
3377 if(count < 8) {
3378 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3379 rc = -EIO;
3380 goto GetInodeNumOut;
3381 }
3382 pfinfo = (struct file_internal_info *)
3383 (data_offset + (char *) &pSMBr->hdr.Protocol);
3384 *inode_number = pfinfo->UniqueId;
3385 }
3386 }
3387GetInodeNumOut:
3388 cifs_buf_release(pSMB);
3389 if (rc == -EAGAIN)
3390 goto GetInodeNumberRetry;
3391 return rc;
3392}
1da177e4
LT
3393
3394int
3395CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3396 const unsigned char *searchName,
3397 unsigned char **targetUNCs,
3398 unsigned int *number_of_UNC_in_array,
737b758c 3399 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3400{
3401/* TRANS2_GET_DFS_REFERRAL */
3402 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3403 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3404 struct dfs_referral_level_3 * referrals = NULL;
3405 int rc = 0;
3406 int bytes_returned;
3407 int name_len;
3408 unsigned int i;
3409 char * temp;
3410 __u16 params, byte_count;
3411 *number_of_UNC_in_array = 0;
3412 *targetUNCs = NULL;
3413
3414 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3415 if (ses == NULL)
3416 return -ENODEV;
3417getDFSRetry:
3418 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3419 (void **) &pSMBr);
3420 if (rc)
3421 return rc;
1982c344
SF
3422
3423 /* server pointer checked in called function,
3424 but should never be null here anyway */
3425 pSMB->hdr.Mid = GetNextMid(ses->server);
1da177e4
LT
3426 pSMB->hdr.Tid = ses->ipc_tid;
3427 pSMB->hdr.Uid = ses->Suid;
3428 if (ses->capabilities & CAP_STATUS32) {
3429 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3430 }
3431 if (ses->capabilities & CAP_DFS) {
3432 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3433 }
3434
3435 if (ses->capabilities & CAP_UNICODE) {
3436 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3437 name_len =
b1a45695 3438 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
737b758c 3439 searchName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
3440 name_len++; /* trailing null */
3441 name_len *= 2;
3442 } else { /* BB improve the check for buffer overruns BB */
3443 name_len = strnlen(searchName, PATH_MAX);
3444 name_len++; /* trailing null */
3445 strncpy(pSMB->RequestFileName, searchName, name_len);
3446 }
3447
3448 params = 2 /* level */ + name_len /*includes null */ ;
3449 pSMB->TotalDataCount = 0;
3450 pSMB->DataCount = 0;
3451 pSMB->DataOffset = 0;
3452 pSMB->MaxParameterCount = 0;
3453 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3454 pSMB->MaxSetupCount = 0;
3455 pSMB->Reserved = 0;
3456 pSMB->Flags = 0;
3457 pSMB->Timeout = 0;
3458 pSMB->Reserved2 = 0;
3459 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3460 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3461 pSMB->SetupCount = 1;
3462 pSMB->Reserved3 = 0;
3463 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3464 byte_count = params + 3 /* pad */ ;
3465 pSMB->ParameterCount = cpu_to_le16(params);
3466 pSMB->TotalParameterCount = pSMB->ParameterCount;
3467 pSMB->MaxReferralLevel = cpu_to_le16(3);
3468 pSMB->hdr.smb_buf_length += byte_count;
3469 pSMB->ByteCount = cpu_to_le16(byte_count);
3470
3471 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3472 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3473 if (rc) {
3474 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3475 } else { /* decode response */
3476/* BB Add logic to parse referrals here */
3477 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3478
3479 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3480 rc = -EIO; /* bad smb */
3481 else {
3482 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3483 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3484
3485 cFYI(1,
3486 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3487 pSMBr->ByteCount, data_offset));
3488 referrals =
3489 (struct dfs_referral_level_3 *)
3490 (8 /* sizeof start of data block */ +
3491 data_offset +
3492 (char *) &pSMBr->hdr.Protocol);
3493 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",
3494 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)));
3495 /* BB This field is actually two bytes in from start of
3496 data block so we could do safety check that DataBlock
3497 begins at address of pSMBr->NumberOfReferrals */
3498 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3499
3500 /* BB Fix below so can return more than one referral */
3501 if(*number_of_UNC_in_array > 1)
3502 *number_of_UNC_in_array = 1;
3503
3504 /* get the length of the strings describing refs */
3505 name_len = 0;
3506 for(i=0;i<*number_of_UNC_in_array;i++) {
3507 /* make sure that DfsPathOffset not past end */
3508 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3509 if (offset > data_count) {
3510 /* if invalid referral, stop here and do
3511 not try to copy any more */
3512 *number_of_UNC_in_array = i;
3513 break;
3514 }
3515 temp = ((char *)referrals) + offset;
3516
3517 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3518 name_len += UniStrnlen((wchar_t *)temp,data_count);
3519 } else {
3520 name_len += strnlen(temp,data_count);
3521 }
3522 referrals++;
3523 /* BB add check that referral pointer does not fall off end PDU */
3524
3525 }
3526 /* BB add check for name_len bigger than bcc */
3527 *targetUNCs =
3528 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3529 if(*targetUNCs == NULL) {
3530 rc = -ENOMEM;
3531 goto GetDFSRefExit;
3532 }
3533 /* copy the ref strings */
3534 referrals =
3535 (struct dfs_referral_level_3 *)
3536 (8 /* sizeof data hdr */ +
3537 data_offset +
3538 (char *) &pSMBr->hdr.Protocol);
3539
3540 for(i=0;i<*number_of_UNC_in_array;i++) {
3541 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3542 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3543 cifs_strfromUCS_le(*targetUNCs,
e89dc920 3544 (__le16 *) temp, name_len, nls_codepage);
1da177e4
LT
3545 } else {
3546 strncpy(*targetUNCs,temp,name_len);
3547 }
3548 /* BB update target_uncs pointers */
3549 referrals++;
3550 }
3551 temp = *targetUNCs;
3552 temp[name_len] = 0;
3553 }
3554
3555 }
3556GetDFSRefExit:
3557 if (pSMB)
3558 cifs_buf_release(pSMB);
3559
3560 if (rc == -EAGAIN)
3561 goto getDFSRetry;
3562
3563 return rc;
3564}
3565
20962438
SF
3566/* Query File System Info such as free space to old servers such as Win 9x */
3567int
3568SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3569{
3570/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3571 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3572 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3573 FILE_SYSTEM_ALLOC_INFO *response_data;
3574 int rc = 0;
3575 int bytes_returned = 0;
3576 __u16 params, byte_count;
3577
3578 cFYI(1, ("OldQFSInfo"));
3579oldQFSInfoRetry:
3580 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3581 (void **) &pSMBr);
3582 if (rc)
3583 return rc;
3584 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3585 (void **) &pSMBr);
3586 if (rc)
3587 return rc;
3588
3589 params = 2; /* level */
3590 pSMB->TotalDataCount = 0;
3591 pSMB->MaxParameterCount = cpu_to_le16(2);
3592 pSMB->MaxDataCount = cpu_to_le16(1000);
3593 pSMB->MaxSetupCount = 0;
3594 pSMB->Reserved = 0;
3595 pSMB->Flags = 0;
3596 pSMB->Timeout = 0;
3597 pSMB->Reserved2 = 0;
3598 byte_count = params + 1 /* pad */ ;
3599 pSMB->TotalParameterCount = cpu_to_le16(params);
3600 pSMB->ParameterCount = pSMB->TotalParameterCount;
3601 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3602 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3603 pSMB->DataCount = 0;
3604 pSMB->DataOffset = 0;
3605 pSMB->SetupCount = 1;
3606 pSMB->Reserved3 = 0;
3607 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3608 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3609 pSMB->hdr.smb_buf_length += byte_count;
3610 pSMB->ByteCount = cpu_to_le16(byte_count);
3611
3612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3614 if (rc) {
3615 cFYI(1, ("Send error in QFSInfo = %d", rc));
3616 } else { /* decode response */
3617 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3618
3619 if (rc || (pSMBr->ByteCount < 18))
3620 rc = -EIO; /* bad smb */
3621 else {
3622 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3623 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3624 pSMBr->ByteCount, data_offset));
3625
3626 response_data =
3627 (FILE_SYSTEM_ALLOC_INFO *)
3628 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3629 FSData->f_bsize =
3630 le16_to_cpu(response_data->BytesPerSector) *
3631 le32_to_cpu(response_data->
3632 SectorsPerAllocationUnit);
3633 FSData->f_blocks =
3634 le32_to_cpu(response_data->TotalAllocationUnits);
3635 FSData->f_bfree = FSData->f_bavail =
3636 le32_to_cpu(response_data->FreeAllocationUnits);
3637 cFYI(1,
3638 ("Blocks: %lld Free: %lld Block size %ld",
3639 (unsigned long long)FSData->f_blocks,
3640 (unsigned long long)FSData->f_bfree,
3641 FSData->f_bsize));
3642 }
3643 }
3644 cifs_buf_release(pSMB);
3645
3646 if (rc == -EAGAIN)
3647 goto oldQFSInfoRetry;
3648
3649 return rc;
3650}
3651
1da177e4 3652int
737b758c 3653CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
1da177e4
LT
3654{
3655/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3656 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3657 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3658 FILE_SYSTEM_INFO *response_data;
3659 int rc = 0;
3660 int bytes_returned = 0;
3661 __u16 params, byte_count;
3662
3663 cFYI(1, ("In QFSInfo"));
3664QFSInfoRetry:
3665 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3666 (void **) &pSMBr);
3667 if (rc)
3668 return rc;
3669
3670 params = 2; /* level */
3671 pSMB->TotalDataCount = 0;
3672 pSMB->MaxParameterCount = cpu_to_le16(2);
20962438 3673 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
3674 pSMB->MaxSetupCount = 0;
3675 pSMB->Reserved = 0;
3676 pSMB->Flags = 0;
3677 pSMB->Timeout = 0;
3678 pSMB->Reserved2 = 0;
3679 byte_count = params + 1 /* pad */ ;
3680 pSMB->TotalParameterCount = cpu_to_le16(params);
3681 pSMB->ParameterCount = pSMB->TotalParameterCount;
3682 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3683 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3684 pSMB->DataCount = 0;
3685 pSMB->DataOffset = 0;
3686 pSMB->SetupCount = 1;
3687 pSMB->Reserved3 = 0;
3688 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3689 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3690 pSMB->hdr.smb_buf_length += byte_count;
3691 pSMB->ByteCount = cpu_to_le16(byte_count);
3692
3693 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3694 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3695 if (rc) {
20962438 3696 cFYI(1, ("Send error in QFSInfo = %d", rc));
1da177e4
LT
3697 } else { /* decode response */
3698 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3699
20962438 3700 if (rc || (pSMBr->ByteCount < 24))
1da177e4
LT
3701 rc = -EIO; /* bad smb */
3702 else {
3703 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
3704
3705 response_data =
3706 (FILE_SYSTEM_INFO
3707 *) (((char *) &pSMBr->hdr.Protocol) +
3708 data_offset);
3709 FSData->f_bsize =
3710 le32_to_cpu(response_data->BytesPerSector) *
3711 le32_to_cpu(response_data->
3712 SectorsPerAllocationUnit);
3713 FSData->f_blocks =
3714 le64_to_cpu(response_data->TotalAllocationUnits);
3715 FSData->f_bfree = FSData->f_bavail =
3716 le64_to_cpu(response_data->FreeAllocationUnits);
3717 cFYI(1,
3718 ("Blocks: %lld Free: %lld Block size %ld",
3719 (unsigned long long)FSData->f_blocks,
3720 (unsigned long long)FSData->f_bfree,
3721 FSData->f_bsize));
3722 }
3723 }
3724 cifs_buf_release(pSMB);
3725
3726 if (rc == -EAGAIN)
3727 goto QFSInfoRetry;
3728
3729 return rc;
3730}
3731
3732int
737b758c 3733CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
3734{
3735/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3736 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3737 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3738 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3739 int rc = 0;
3740 int bytes_returned = 0;
3741 __u16 params, byte_count;
3742
3743 cFYI(1, ("In QFSAttributeInfo"));
3744QFSAttributeRetry:
3745 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3746 (void **) &pSMBr);
3747 if (rc)
3748 return rc;
3749
3750 params = 2; /* level */
3751 pSMB->TotalDataCount = 0;
3752 pSMB->MaxParameterCount = cpu_to_le16(2);
3753 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3754 pSMB->MaxSetupCount = 0;
3755 pSMB->Reserved = 0;
3756 pSMB->Flags = 0;
3757 pSMB->Timeout = 0;
3758 pSMB->Reserved2 = 0;
3759 byte_count = params + 1 /* pad */ ;
3760 pSMB->TotalParameterCount = cpu_to_le16(params);
3761 pSMB->ParameterCount = pSMB->TotalParameterCount;
3762 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3763 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3764 pSMB->DataCount = 0;
3765 pSMB->DataOffset = 0;
3766 pSMB->SetupCount = 1;
3767 pSMB->Reserved3 = 0;
3768 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3769 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3770 pSMB->hdr.smb_buf_length += byte_count;
3771 pSMB->ByteCount = cpu_to_le16(byte_count);
3772
3773 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3774 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3775 if (rc) {
3776 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3777 } else { /* decode response */
3778 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3779
3780 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3781 rc = -EIO; /* bad smb */
3782 } else {
3783 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3784 response_data =
3785 (FILE_SYSTEM_ATTRIBUTE_INFO
3786 *) (((char *) &pSMBr->hdr.Protocol) +
3787 data_offset);
3788 memcpy(&tcon->fsAttrInfo, response_data,
3789 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3790 }
3791 }
3792 cifs_buf_release(pSMB);
3793
3794 if (rc == -EAGAIN)
3795 goto QFSAttributeRetry;
3796
3797 return rc;
3798}
3799
3800int
737b758c 3801CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
3802{
3803/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3804 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3805 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3806 FILE_SYSTEM_DEVICE_INFO *response_data;
3807 int rc = 0;
3808 int bytes_returned = 0;
3809 __u16 params, byte_count;
3810
3811 cFYI(1, ("In QFSDeviceInfo"));
3812QFSDeviceRetry:
3813 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3814 (void **) &pSMBr);
3815 if (rc)
3816 return rc;
3817
3818 params = 2; /* level */
3819 pSMB->TotalDataCount = 0;
3820 pSMB->MaxParameterCount = cpu_to_le16(2);
3821 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3822 pSMB->MaxSetupCount = 0;
3823 pSMB->Reserved = 0;
3824 pSMB->Flags = 0;
3825 pSMB->Timeout = 0;
3826 pSMB->Reserved2 = 0;
3827 byte_count = params + 1 /* pad */ ;
3828 pSMB->TotalParameterCount = cpu_to_le16(params);
3829 pSMB->ParameterCount = pSMB->TotalParameterCount;
3830 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3831 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3832
3833 pSMB->DataCount = 0;
3834 pSMB->DataOffset = 0;
3835 pSMB->SetupCount = 1;
3836 pSMB->Reserved3 = 0;
3837 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3838 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3839 pSMB->hdr.smb_buf_length += byte_count;
3840 pSMB->ByteCount = cpu_to_le16(byte_count);
3841
3842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3844 if (rc) {
3845 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3846 } else { /* decode response */
3847 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3848
3849 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3850 rc = -EIO; /* bad smb */
3851 else {
3852 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3853 response_data =
737b758c
SF
3854 (FILE_SYSTEM_DEVICE_INFO *)
3855 (((char *) &pSMBr->hdr.Protocol) +
1da177e4
LT
3856 data_offset);
3857 memcpy(&tcon->fsDevInfo, response_data,
3858 sizeof (FILE_SYSTEM_DEVICE_INFO));
3859 }
3860 }
3861 cifs_buf_release(pSMB);
3862
3863 if (rc == -EAGAIN)
3864 goto QFSDeviceRetry;
3865
3866 return rc;
3867}
3868
3869int
737b758c 3870CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
3871{
3872/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3873 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3874 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3875 FILE_SYSTEM_UNIX_INFO *response_data;
3876 int rc = 0;
3877 int bytes_returned = 0;
3878 __u16 params, byte_count;
3879
3880 cFYI(1, ("In QFSUnixInfo"));
3881QFSUnixRetry:
3882 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3883 (void **) &pSMBr);
3884 if (rc)
3885 return rc;
3886
3887 params = 2; /* level */
3888 pSMB->TotalDataCount = 0;
3889 pSMB->DataCount = 0;
3890 pSMB->DataOffset = 0;
3891 pSMB->MaxParameterCount = cpu_to_le16(2);
3892 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3893 pSMB->MaxSetupCount = 0;
3894 pSMB->Reserved = 0;
3895 pSMB->Flags = 0;
3896 pSMB->Timeout = 0;
3897 pSMB->Reserved2 = 0;
3898 byte_count = params + 1 /* pad */ ;
3899 pSMB->ParameterCount = cpu_to_le16(params);
3900 pSMB->TotalParameterCount = pSMB->ParameterCount;
3901 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3902 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3903 pSMB->SetupCount = 1;
3904 pSMB->Reserved3 = 0;
3905 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3906 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3907 pSMB->hdr.smb_buf_length += byte_count;
3908 pSMB->ByteCount = cpu_to_le16(byte_count);
3909
3910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3912 if (rc) {
3913 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3914 } else { /* decode response */
3915 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3916
3917 if (rc || (pSMBr->ByteCount < 13)) {
3918 rc = -EIO; /* bad smb */
3919 } else {
3920 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3921 response_data =
3922 (FILE_SYSTEM_UNIX_INFO
3923 *) (((char *) &pSMBr->hdr.Protocol) +
3924 data_offset);
3925 memcpy(&tcon->fsUnixInfo, response_data,
3926 sizeof (FILE_SYSTEM_UNIX_INFO));
3927 }
3928 }
3929 cifs_buf_release(pSMB);
3930
3931 if (rc == -EAGAIN)
3932 goto QFSUnixRetry;
3933
3934
3935 return rc;
3936}
3937
ac67055e 3938int
45abc6ee 3939CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
ac67055e
JA
3940{
3941/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3942 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3943 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3944 int rc = 0;
3945 int bytes_returned = 0;
3946 __u16 params, param_offset, offset, byte_count;
3947
3948 cFYI(1, ("In SETFSUnixInfo"));
3949SETFSUnixRetry:
f26282c9 3950 /* BB switch to small buf init to save memory */
ac67055e
JA
3951 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3952 (void **) &pSMBr);
3953 if (rc)
3954 return rc;
3955
3956 params = 4; /* 2 bytes zero followed by info level. */
3957 pSMB->MaxSetupCount = 0;
3958 pSMB->Reserved = 0;
3959 pSMB->Flags = 0;
3960 pSMB->Timeout = 0;
3961 pSMB->Reserved2 = 0;
3962 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3963 offset = param_offset + params;
3964
3965 pSMB->MaxParameterCount = cpu_to_le16(4);
3966 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3967 pSMB->SetupCount = 1;
3968 pSMB->Reserved3 = 0;
3969 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3970 byte_count = 1 /* pad */ + params + 12;
3971
3972 pSMB->DataCount = cpu_to_le16(12);
3973 pSMB->ParameterCount = cpu_to_le16(params);
3974 pSMB->TotalDataCount = pSMB->DataCount;
3975 pSMB->TotalParameterCount = pSMB->ParameterCount;
3976 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3977 pSMB->DataOffset = cpu_to_le16(offset);
3978
3979 /* Params. */
3980 pSMB->FileNum = 0;
3981 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3982
3983 /* Data. */
3984 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3985 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3986 pSMB->ClientUnixCap = cpu_to_le64(cap);
3987
3988 pSMB->hdr.smb_buf_length += byte_count;
3989 pSMB->ByteCount = cpu_to_le16(byte_count);
3990
3991 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3992 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3993 if (rc) {
3994 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3995 } else { /* decode response */
3996 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3997 if (rc) {
3998 rc = -EIO; /* bad smb */
3999 }
4000 }
4001 cifs_buf_release(pSMB);
4002
4003 if (rc == -EAGAIN)
4004 goto SETFSUnixRetry;
4005
4006 return rc;
4007}
4008
4009
1da177e4
LT
4010
4011int
4012CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
737b758c 4013 struct kstatfs *FSData)
1da177e4
LT
4014{
4015/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4016 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4017 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4018 FILE_SYSTEM_POSIX_INFO *response_data;
4019 int rc = 0;
4020 int bytes_returned = 0;
4021 __u16 params, byte_count;
4022
4023 cFYI(1, ("In QFSPosixInfo"));
4024QFSPosixRetry:
4025 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4026 (void **) &pSMBr);
4027 if (rc)
4028 return rc;
4029
4030 params = 2; /* level */
4031 pSMB->TotalDataCount = 0;
4032 pSMB->DataCount = 0;
4033 pSMB->DataOffset = 0;
4034 pSMB->MaxParameterCount = cpu_to_le16(2);
4035 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4036 pSMB->MaxSetupCount = 0;
4037 pSMB->Reserved = 0;
4038 pSMB->Flags = 0;
4039 pSMB->Timeout = 0;
4040 pSMB->Reserved2 = 0;
4041 byte_count = params + 1 /* pad */ ;
4042 pSMB->ParameterCount = cpu_to_le16(params);
4043 pSMB->TotalParameterCount = pSMB->ParameterCount;
4044 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4045 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4046 pSMB->SetupCount = 1;
4047 pSMB->Reserved3 = 0;
4048 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4049 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4050 pSMB->hdr.smb_buf_length += byte_count;
4051 pSMB->ByteCount = cpu_to_le16(byte_count);
4052
4053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4055 if (rc) {
4056 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4057 } else { /* decode response */
4058 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4059
4060 if (rc || (pSMBr->ByteCount < 13)) {
4061 rc = -EIO; /* bad smb */
4062 } else {
4063 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4064 response_data =
4065 (FILE_SYSTEM_POSIX_INFO
4066 *) (((char *) &pSMBr->hdr.Protocol) +
4067 data_offset);
4068 FSData->f_bsize =
4069 le32_to_cpu(response_data->BlockSize);
4070 FSData->f_blocks =
4071 le64_to_cpu(response_data->TotalBlocks);
4072 FSData->f_bfree =
4073 le64_to_cpu(response_data->BlocksAvail);
70ca734a 4074 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
1da177e4
LT
4075 FSData->f_bavail = FSData->f_bfree;
4076 } else {
4077 FSData->f_bavail =
4078 le64_to_cpu(response_data->UserBlocksAvail);
4079 }
70ca734a 4080 if(response_data->TotalFileNodes != cpu_to_le64(-1))
1da177e4
LT
4081 FSData->f_files =
4082 le64_to_cpu(response_data->TotalFileNodes);
70ca734a 4083 if(response_data->FreeFileNodes != cpu_to_le64(-1))
1da177e4
LT
4084 FSData->f_ffree =
4085 le64_to_cpu(response_data->FreeFileNodes);
4086 }
4087 }
4088 cifs_buf_release(pSMB);
4089
4090 if (rc == -EAGAIN)
4091 goto QFSPosixRetry;
4092
4093 return rc;
4094}
4095
4096
4097/* We can not use write of zero bytes trick to
4098 set file size due to need for large file support. Also note that
4099 this SetPathInfo is preferred to SetFileInfo based method in next
4100 routine which is only needed to work around a sharing violation bug
4101 in Samba which this routine can run into */
4102
4103int
4104CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
737b758c
SF
4105 __u64 size, int SetAllocation,
4106 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4107{
4108 struct smb_com_transaction2_spi_req *pSMB = NULL;
4109 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4110 struct file_end_of_file_info *parm_data;
4111 int name_len;
4112 int rc = 0;
4113 int bytes_returned = 0;
4114 __u16 params, byte_count, data_count, param_offset, offset;
4115
4116 cFYI(1, ("In SetEOF"));
4117SetEOFRetry:
4118 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4119 (void **) &pSMBr);
4120 if (rc)
4121 return rc;
4122
4123 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4124 name_len =
b1a45695 4125 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4126 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4127 name_len++; /* trailing null */
4128 name_len *= 2;
3e87d803 4129 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4130 name_len = strnlen(fileName, PATH_MAX);
4131 name_len++; /* trailing null */
4132 strncpy(pSMB->FileName, fileName, name_len);
4133 }
4134 params = 6 + name_len;
4135 data_count = sizeof (struct file_end_of_file_info);
4136 pSMB->MaxParameterCount = cpu_to_le16(2);
3e87d803 4137 pSMB->MaxDataCount = cpu_to_le16(4100);
1da177e4
LT
4138 pSMB->MaxSetupCount = 0;
4139 pSMB->Reserved = 0;
4140 pSMB->Flags = 0;
4141 pSMB->Timeout = 0;
4142 pSMB->Reserved2 = 0;
4143 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4144 InformationLevel) - 4;
4145 offset = param_offset + params;
4146 if(SetAllocation) {
4147 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4148 pSMB->InformationLevel =
4149 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4150 else
4151 pSMB->InformationLevel =
4152 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4153 } else /* Set File Size */ {
4154 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4155 pSMB->InformationLevel =
4156 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4157 else
4158 pSMB->InformationLevel =
4159 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4160 }
4161
4162 parm_data =
4163 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4164 offset);
4165 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4166 pSMB->DataOffset = cpu_to_le16(offset);
4167 pSMB->SetupCount = 1;
4168 pSMB->Reserved3 = 0;
4169 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4170 byte_count = 3 /* pad */ + params + data_count;
4171 pSMB->DataCount = cpu_to_le16(data_count);
4172 pSMB->TotalDataCount = pSMB->DataCount;
4173 pSMB->ParameterCount = cpu_to_le16(params);
4174 pSMB->TotalParameterCount = pSMB->ParameterCount;
4175 pSMB->Reserved4 = 0;
4176 pSMB->hdr.smb_buf_length += byte_count;
4177 parm_data->FileSize = cpu_to_le64(size);
4178 pSMB->ByteCount = cpu_to_le16(byte_count);
4179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4180 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4181 if (rc) {
4182 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4183 }
4184
4185 cifs_buf_release(pSMB);
4186
4187 if (rc == -EAGAIN)
4188 goto SetEOFRetry;
4189
4190 return rc;
4191}
4192
4193int
4194CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4195 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4196{
4197 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4198 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4199 char *data_offset;
4200 struct file_end_of_file_info *parm_data;
4201 int rc = 0;
4202 int bytes_returned = 0;
4203 __u16 params, param_offset, offset, byte_count, count;
4204
4205 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4206 (long long)size));
cd63499c
SF
4207 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4208
1da177e4
LT
4209 if (rc)
4210 return rc;
4211
cd63499c
SF
4212 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4213
1da177e4
LT
4214 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4215 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4216
4217 params = 6;
4218 pSMB->MaxSetupCount = 0;
4219 pSMB->Reserved = 0;
4220 pSMB->Flags = 0;
4221 pSMB->Timeout = 0;
4222 pSMB->Reserved2 = 0;
4223 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4224 offset = param_offset + params;
4225
4226 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4227
4228 count = sizeof(struct file_end_of_file_info);
4229 pSMB->MaxParameterCount = cpu_to_le16(2);
4230 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4231 pSMB->SetupCount = 1;
4232 pSMB->Reserved3 = 0;
4233 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4234 byte_count = 3 /* pad */ + params + count;
4235 pSMB->DataCount = cpu_to_le16(count);
4236 pSMB->ParameterCount = cpu_to_le16(params);
4237 pSMB->TotalDataCount = pSMB->DataCount;
4238 pSMB->TotalParameterCount = pSMB->ParameterCount;
4239 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4240 parm_data =
4241 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4242 offset);
4243 pSMB->DataOffset = cpu_to_le16(offset);
4244 parm_data->FileSize = cpu_to_le64(size);
4245 pSMB->Fid = fid;
4246 if(SetAllocation) {
4247 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4248 pSMB->InformationLevel =
4249 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4250 else
4251 pSMB->InformationLevel =
4252 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4253 } else /* Set File Size */ {
4254 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4255 pSMB->InformationLevel =
4256 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4257 else
4258 pSMB->InformationLevel =
4259 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4260 }
4261 pSMB->Reserved4 = 0;
4262 pSMB->hdr.smb_buf_length += byte_count;
4263 pSMB->ByteCount = cpu_to_le16(byte_count);
4264 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4265 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4266 if (rc) {
4267 cFYI(1,
4268 ("Send error in SetFileInfo (SetFileSize) = %d",
4269 rc));
4270 }
4271
4272 if (pSMB)
cd63499c 4273 cifs_small_buf_release(pSMB);
1da177e4
LT
4274
4275 /* Note: On -EAGAIN error only caller can retry on handle based calls
4276 since file handle passed in no longer valid */
4277
4278 return rc;
4279}
4280
4281/* Some legacy servers such as NT4 require that the file times be set on
4282 an open handle, rather than by pathname - this is awkward due to
4283 potential access conflicts on the open, but it is unavoidable for these
4284 old servers since the only other choice is to go from 100 nanosecond DCE
4285 time and resort to the original setpathinfo level which takes the ancient
4286 DOS time format with 2 second granularity */
4287int
4288CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4289 __u16 fid)
4290{
4291 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4292 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4293 char *data_offset;
4294 int rc = 0;
4295 int bytes_returned = 0;
4296 __u16 params, param_offset, offset, byte_count, count;
4297
4298 cFYI(1, ("Set Times (via SetFileInfo)"));
cd63499c
SF
4299 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4300
1da177e4
LT
4301 if (rc)
4302 return rc;
4303
cd63499c
SF
4304 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4305
1da177e4
LT
4306 /* At this point there is no need to override the current pid
4307 with the pid of the opener, but that could change if we someday
4308 use an existing handle (rather than opening one on the fly) */
4309 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4310 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4311
4312 params = 6;
4313 pSMB->MaxSetupCount = 0;
4314 pSMB->Reserved = 0;
4315 pSMB->Flags = 0;
4316 pSMB->Timeout = 0;
4317 pSMB->Reserved2 = 0;
4318 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4319 offset = param_offset + params;
4320
4321 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4322
4323 count = sizeof (FILE_BASIC_INFO);
4324 pSMB->MaxParameterCount = cpu_to_le16(2);
4325 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4326 pSMB->SetupCount = 1;
4327 pSMB->Reserved3 = 0;
4328 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4329 byte_count = 3 /* pad */ + params + count;
4330 pSMB->DataCount = cpu_to_le16(count);
4331 pSMB->ParameterCount = cpu_to_le16(params);
4332 pSMB->TotalDataCount = pSMB->DataCount;
4333 pSMB->TotalParameterCount = pSMB->ParameterCount;
4334 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4335 pSMB->DataOffset = cpu_to_le16(offset);
4336 pSMB->Fid = fid;
4337 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4338 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4339 else
4340 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4341 pSMB->Reserved4 = 0;
4342 pSMB->hdr.smb_buf_length += byte_count;
4343 pSMB->ByteCount = cpu_to_le16(byte_count);
4344 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4347 if (rc) {
4348 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4349 }
4350
cd63499c 4351 cifs_small_buf_release(pSMB);
1da177e4
LT
4352
4353 /* Note: On -EAGAIN error only caller can retry on handle based calls
4354 since file handle passed in no longer valid */
4355
4356 return rc;
4357}
4358
4359
4360int
4361CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4362 const FILE_BASIC_INFO * data,
737b758c 4363 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4364{
4365 TRANSACTION2_SPI_REQ *pSMB = NULL;
4366 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4367 int name_len;
4368 int rc = 0;
4369 int bytes_returned = 0;
4370 char *data_offset;
4371 __u16 params, param_offset, offset, byte_count, count;
4372
4373 cFYI(1, ("In SetTimes"));
4374
4375SetTimesRetry:
4376 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4377 (void **) &pSMBr);
4378 if (rc)
4379 return rc;
4380
4381 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4382 name_len =
b1a45695 4383 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4384 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4385 name_len++; /* trailing null */
4386 name_len *= 2;
4387 } else { /* BB improve the check for buffer overruns BB */
4388 name_len = strnlen(fileName, PATH_MAX);
4389 name_len++; /* trailing null */
4390 strncpy(pSMB->FileName, fileName, name_len);
4391 }
4392
4393 params = 6 + name_len;
4394 count = sizeof (FILE_BASIC_INFO);
4395 pSMB->MaxParameterCount = cpu_to_le16(2);
4396 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4397 pSMB->MaxSetupCount = 0;
4398 pSMB->Reserved = 0;
4399 pSMB->Flags = 0;
4400 pSMB->Timeout = 0;
4401 pSMB->Reserved2 = 0;
4402 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4403 InformationLevel) - 4;
4404 offset = param_offset + params;
4405 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4406 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4407 pSMB->DataOffset = cpu_to_le16(offset);
4408 pSMB->SetupCount = 1;
4409 pSMB->Reserved3 = 0;
4410 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4411 byte_count = 3 /* pad */ + params + count;
4412
4413 pSMB->DataCount = cpu_to_le16(count);
4414 pSMB->ParameterCount = cpu_to_le16(params);
4415 pSMB->TotalDataCount = pSMB->DataCount;
4416 pSMB->TotalParameterCount = pSMB->ParameterCount;
4417 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4418 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4419 else
4420 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4421 pSMB->Reserved4 = 0;
4422 pSMB->hdr.smb_buf_length += byte_count;
4423 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4424 pSMB->ByteCount = cpu_to_le16(byte_count);
4425 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4427 if (rc) {
4428 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4429 }
4430
4431 cifs_buf_release(pSMB);
4432
4433 if (rc == -EAGAIN)
4434 goto SetTimesRetry;
4435
4436 return rc;
4437}
4438
4439/* Can not be used to set time stamps yet (due to old DOS time format) */
4440/* Can be used to set attributes */
4441#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4442 handling it anyway and NT4 was what we thought it would be needed for
4443 Do not delete it until we prove whether needed for Win9x though */
4444int
4445CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4446 __u16 dos_attrs, const struct nls_table *nls_codepage)
4447{
4448 SETATTR_REQ *pSMB = NULL;
4449 SETATTR_RSP *pSMBr = NULL;
4450 int rc = 0;
4451 int bytes_returned;
4452 int name_len;
4453
4454 cFYI(1, ("In SetAttrLegacy"));
4455
4456SetAttrLgcyRetry:
4457 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4458 (void **) &pSMBr);
4459 if (rc)
4460 return rc;
4461
4462 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4463 name_len =
b1a45695 4464 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
1da177e4
LT
4465 PATH_MAX, nls_codepage);
4466 name_len++; /* trailing null */
4467 name_len *= 2;
4468 } else { /* BB improve the check for buffer overruns BB */
4469 name_len = strnlen(fileName, PATH_MAX);
4470 name_len++; /* trailing null */
4471 strncpy(pSMB->fileName, fileName, name_len);
4472 }
4473 pSMB->attr = cpu_to_le16(dos_attrs);
4474 pSMB->BufferFormat = 0x04;
4475 pSMB->hdr.smb_buf_length += name_len + 1;
4476 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4477 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4478 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4479 if (rc) {
4480 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4481 }
4482
4483 cifs_buf_release(pSMB);
4484
4485 if (rc == -EAGAIN)
4486 goto SetAttrLgcyRetry;
4487
4488 return rc;
4489}
4490#endif /* temporarily unneeded SetAttr legacy function */
4491
4492int
4493CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
737b758c
SF
4494 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4495 dev_t device, const struct nls_table *nls_codepage,
4496 int remap)
1da177e4
LT
4497{
4498 TRANSACTION2_SPI_REQ *pSMB = NULL;
4499 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4500 int name_len;
4501 int rc = 0;
4502 int bytes_returned = 0;
4503 FILE_UNIX_BASIC_INFO *data_offset;
4504 __u16 params, param_offset, offset, count, byte_count;
4505
4506 cFYI(1, ("In SetUID/GID/Mode"));
4507setPermsRetry:
4508 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4509 (void **) &pSMBr);
4510 if (rc)
4511 return rc;
4512
4513 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4514 name_len =
b1a45695 4515 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4516 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4517 name_len++; /* trailing null */
4518 name_len *= 2;
3e87d803 4519 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4520 name_len = strnlen(fileName, PATH_MAX);
4521 name_len++; /* trailing null */
4522 strncpy(pSMB->FileName, fileName, name_len);
4523 }
4524
4525 params = 6 + name_len;
4526 count = sizeof (FILE_UNIX_BASIC_INFO);
4527 pSMB->MaxParameterCount = cpu_to_le16(2);
4528 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4529 pSMB->MaxSetupCount = 0;
4530 pSMB->Reserved = 0;
4531 pSMB->Flags = 0;
4532 pSMB->Timeout = 0;
4533 pSMB->Reserved2 = 0;
4534 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4535 InformationLevel) - 4;
4536 offset = param_offset + params;
4537 data_offset =
4538 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4539 offset);
4540 memset(data_offset, 0, count);
4541 pSMB->DataOffset = cpu_to_le16(offset);
4542 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4543 pSMB->SetupCount = 1;
4544 pSMB->Reserved3 = 0;
4545 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4546 byte_count = 3 /* pad */ + params + count;
4547 pSMB->ParameterCount = cpu_to_le16(params);
4548 pSMB->DataCount = cpu_to_le16(count);
4549 pSMB->TotalParameterCount = pSMB->ParameterCount;
4550 pSMB->TotalDataCount = pSMB->DataCount;
4551 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4552 pSMB->Reserved4 = 0;
4553 pSMB->hdr.smb_buf_length += byte_count;
4554 data_offset->Uid = cpu_to_le64(uid);
4555 data_offset->Gid = cpu_to_le64(gid);
4556 /* better to leave device as zero when it is */
4557 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4558 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4559 data_offset->Permissions = cpu_to_le64(mode);
4560
4561 if(S_ISREG(mode))
4562 data_offset->Type = cpu_to_le32(UNIX_FILE);
4563 else if(S_ISDIR(mode))
4564 data_offset->Type = cpu_to_le32(UNIX_DIR);
4565 else if(S_ISLNK(mode))
4566 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4567 else if(S_ISCHR(mode))
4568 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4569 else if(S_ISBLK(mode))
4570 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4571 else if(S_ISFIFO(mode))
4572 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4573 else if(S_ISSOCK(mode))
4574 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4575
4576
4577 pSMB->ByteCount = cpu_to_le16(byte_count);
4578 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4579 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4580 if (rc) {
4581 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4582 }
4583
4584 if (pSMB)
4585 cifs_buf_release(pSMB);
4586 if (rc == -EAGAIN)
4587 goto setPermsRetry;
4588 return rc;
4589}
4590
4591int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
167a251a
SF
4592 const int notify_subdirs, const __u16 netfid,
4593 __u32 filter, struct file * pfile, int multishot,
4594 const struct nls_table *nls_codepage)
1da177e4
LT
4595{
4596 int rc = 0;
4597 struct smb_com_transaction_change_notify_req * pSMB = NULL;
0a4b92c0 4598 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
abb15b8a 4599 struct dir_notify_req *dnotify_req;
1da177e4
LT
4600 int bytes_returned;
4601
4602 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4603 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4604 (void **) &pSMBr);
4605 if (rc)
4606 return rc;
4607
4608 pSMB->TotalParameterCount = 0 ;
4609 pSMB->TotalDataCount = 0;
4610 pSMB->MaxParameterCount = cpu_to_le32(2);
4611 /* BB find exact data count max from sess structure BB */
4612 pSMB->MaxDataCount = 0; /* same in little endian or be */
0a4b92c0
SF
4613/* BB VERIFY verify which is correct for above BB */
4614 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4615 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4616
1da177e4
LT
4617 pSMB->MaxSetupCount = 4;
4618 pSMB->Reserved = 0;
4619 pSMB->ParameterOffset = 0;
4620 pSMB->DataCount = 0;
4621 pSMB->DataOffset = 0;
4622 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4623 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4624 pSMB->ParameterCount = pSMB->TotalParameterCount;
4625 if(notify_subdirs)
4626 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4627 pSMB->Reserved2 = 0;
4628 pSMB->CompletionFilter = cpu_to_le32(filter);
4629 pSMB->Fid = netfid; /* file handle always le */
4630 pSMB->ByteCount = 0;
4631
4632 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4633 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4634 if (rc) {
4635 cFYI(1, ("Error in Notify = %d", rc));
ff5dbd9e
SF
4636 } else {
4637 /* Add file to outstanding requests */
47c786e7 4638 /* BB change to kmem cache alloc */
ff5dbd9e 4639 dnotify_req = (struct dir_notify_req *) kmalloc(
47c786e7
SF
4640 sizeof(struct dir_notify_req),
4641 GFP_KERNEL);
4642 if(dnotify_req) {
4643 dnotify_req->Pid = pSMB->hdr.Pid;
4644 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4645 dnotify_req->Mid = pSMB->hdr.Mid;
4646 dnotify_req->Tid = pSMB->hdr.Tid;
4647 dnotify_req->Uid = pSMB->hdr.Uid;
4648 dnotify_req->netfid = netfid;
4649 dnotify_req->pfile = pfile;
4650 dnotify_req->filter = filter;
4651 dnotify_req->multishot = multishot;
4652 spin_lock(&GlobalMid_Lock);
4653 list_add_tail(&dnotify_req->lhead,
4654 &GlobalDnotifyReqList);
4655 spin_unlock(&GlobalMid_Lock);
4656 } else
4657 rc = -ENOMEM;
1da177e4
LT
4658 }
4659 cifs_buf_release(pSMB);
4660 return rc;
4661}
4662#ifdef CONFIG_CIFS_XATTR
4663ssize_t
4664CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4665 const unsigned char *searchName,
4666 char * EAData, size_t buf_size,
737b758c 4667 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4668{
4669 /* BB assumes one setup word */
4670 TRANSACTION2_QPI_REQ *pSMB = NULL;
4671 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4672 int rc = 0;
4673 int bytes_returned;
4674 int name_len;
4675 struct fea * temp_fea;
4676 char * temp_ptr;
4677 __u16 params, byte_count;
4678
4679 cFYI(1, ("In Query All EAs path %s", searchName));
4680QAllEAsRetry:
4681 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4682 (void **) &pSMBr);
4683 if (rc)
4684 return rc;
4685
4686 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4687 name_len =
b1a45695 4688 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 4689 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4690 name_len++; /* trailing null */
4691 name_len *= 2;
4692 } else { /* BB improve the check for buffer overruns BB */
4693 name_len = strnlen(searchName, PATH_MAX);
4694 name_len++; /* trailing null */
4695 strncpy(pSMB->FileName, searchName, name_len);
4696 }
4697
4698 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4699 pSMB->TotalDataCount = 0;
4700 pSMB->MaxParameterCount = cpu_to_le16(2);
4701 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4702 pSMB->MaxSetupCount = 0;
4703 pSMB->Reserved = 0;
4704 pSMB->Flags = 0;
4705 pSMB->Timeout = 0;
4706 pSMB->Reserved2 = 0;
4707 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4708 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4709 pSMB->DataCount = 0;
4710 pSMB->DataOffset = 0;
4711 pSMB->SetupCount = 1;
4712 pSMB->Reserved3 = 0;
4713 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4714 byte_count = params + 1 /* pad */ ;
4715 pSMB->TotalParameterCount = cpu_to_le16(params);
4716 pSMB->ParameterCount = pSMB->TotalParameterCount;
4717 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4718 pSMB->Reserved4 = 0;
4719 pSMB->hdr.smb_buf_length += byte_count;
4720 pSMB->ByteCount = cpu_to_le16(byte_count);
4721
4722 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4723 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4724 if (rc) {
4725 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4726 } else { /* decode response */
4727 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4728
4729 /* BB also check enough total bytes returned */
4730 /* BB we need to improve the validity checking
4731 of these trans2 responses */
4732 if (rc || (pSMBr->ByteCount < 4))
4733 rc = -EIO; /* bad smb */
4734 /* else if (pFindData){
4735 memcpy((char *) pFindData,
4736 (char *) &pSMBr->hdr.Protocol +
4737 data_offset, kl);
4738 }*/ else {
4739 /* check that length of list is not more than bcc */
4740 /* check that each entry does not go beyond length
4741 of list */
4742 /* check that each element of each entry does not
4743 go beyond end of list */
4744 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4745 struct fealist * ea_response_data;
4746 rc = 0;
4747 /* validate_trans2_offsets() */
4748 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4749 ea_response_data = (struct fealist *)
4750 (((char *) &pSMBr->hdr.Protocol) +
4751 data_offset);
4752 name_len = le32_to_cpu(ea_response_data->list_len);
4753 cFYI(1,("ea length %d", name_len));
4754 if(name_len <= 8) {
4755 /* returned EA size zeroed at top of function */
4756 cFYI(1,("empty EA list returned from server"));
4757 } else {
4758 /* account for ea list len */
4759 name_len -= 4;
4760 temp_fea = ea_response_data->list;
4761 temp_ptr = (char *)temp_fea;
4762 while(name_len > 0) {
4763 __u16 value_len;
4764 name_len -= 4;
4765 temp_ptr += 4;
4766 rc += temp_fea->name_len;
4767 /* account for prefix user. and trailing null */
4768 rc = rc + 5 + 1;
4769 if(rc<(int)buf_size) {
4770 memcpy(EAData,"user.",5);
4771 EAData+=5;
4772 memcpy(EAData,temp_ptr,temp_fea->name_len);
4773 EAData+=temp_fea->name_len;
4774 /* null terminate name */
4775 *EAData = 0;
4776 EAData = EAData + 1;
4777 } else if(buf_size == 0) {
4778 /* skip copy - calc size only */
4779 } else {
4780 /* stop before overrun buffer */
4781 rc = -ERANGE;
4782 break;
4783 }
4784 name_len -= temp_fea->name_len;
4785 temp_ptr += temp_fea->name_len;
4786 /* account for trailing null */
4787 name_len--;
4788 temp_ptr++;
4789 value_len = le16_to_cpu(temp_fea->value_len);
4790 name_len -= value_len;
4791 temp_ptr += value_len;
4792 /* BB check that temp_ptr is still within smb BB*/
4793 /* no trailing null to account for in value len */
4794 /* go on to next EA */
4795 temp_fea = (struct fea *)temp_ptr;
4796 }
4797 }
4798 }
4799 }
4800 if (pSMB)
4801 cifs_buf_release(pSMB);
4802 if (rc == -EAGAIN)
4803 goto QAllEAsRetry;
4804
4805 return (ssize_t)rc;
4806}
4807
4808ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4809 const unsigned char * searchName,const unsigned char * ea_name,
4810 unsigned char * ea_value, size_t buf_size,
737b758c 4811 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4812{
4813 TRANSACTION2_QPI_REQ *pSMB = NULL;
4814 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4815 int rc = 0;
4816 int bytes_returned;
4817 int name_len;
4818 struct fea * temp_fea;
4819 char * temp_ptr;
4820 __u16 params, byte_count;
4821
4822 cFYI(1, ("In Query EA path %s", searchName));
4823QEARetry:
4824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4825 (void **) &pSMBr);
4826 if (rc)
4827 return rc;
4828
4829 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4830 name_len =
b1a45695 4831 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 4832 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4833 name_len++; /* trailing null */
4834 name_len *= 2;
4835 } else { /* BB improve the check for buffer overruns BB */
4836 name_len = strnlen(searchName, PATH_MAX);
4837 name_len++; /* trailing null */
4838 strncpy(pSMB->FileName, searchName, name_len);
4839 }
4840
4841 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4842 pSMB->TotalDataCount = 0;
4843 pSMB->MaxParameterCount = cpu_to_le16(2);
4844 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4845 pSMB->MaxSetupCount = 0;
4846 pSMB->Reserved = 0;
4847 pSMB->Flags = 0;
4848 pSMB->Timeout = 0;
4849 pSMB->Reserved2 = 0;
4850 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4851 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4852 pSMB->DataCount = 0;
4853 pSMB->DataOffset = 0;
4854 pSMB->SetupCount = 1;
4855 pSMB->Reserved3 = 0;
4856 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4857 byte_count = params + 1 /* pad */ ;
4858 pSMB->TotalParameterCount = cpu_to_le16(params);
4859 pSMB->ParameterCount = pSMB->TotalParameterCount;
4860 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4861 pSMB->Reserved4 = 0;
4862 pSMB->hdr.smb_buf_length += byte_count;
4863 pSMB->ByteCount = cpu_to_le16(byte_count);
4864
4865 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4866 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4867 if (rc) {
4868 cFYI(1, ("Send error in Query EA = %d", rc));
4869 } else { /* decode response */
4870 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4871
4872 /* BB also check enough total bytes returned */
4873 /* BB we need to improve the validity checking
4874 of these trans2 responses */
4875 if (rc || (pSMBr->ByteCount < 4))
4876 rc = -EIO; /* bad smb */
4877 /* else if (pFindData){
4878 memcpy((char *) pFindData,
4879 (char *) &pSMBr->hdr.Protocol +
4880 data_offset, kl);
4881 }*/ else {
4882 /* check that length of list is not more than bcc */
4883 /* check that each entry does not go beyond length
4884 of list */
4885 /* check that each element of each entry does not
4886 go beyond end of list */
4887 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4888 struct fealist * ea_response_data;
4889 rc = -ENODATA;
4890 /* validate_trans2_offsets() */
4891 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4892 ea_response_data = (struct fealist *)
4893 (((char *) &pSMBr->hdr.Protocol) +
4894 data_offset);
4895 name_len = le32_to_cpu(ea_response_data->list_len);
4896 cFYI(1,("ea length %d", name_len));
4897 if(name_len <= 8) {
4898 /* returned EA size zeroed at top of function */
4899 cFYI(1,("empty EA list returned from server"));
4900 } else {
4901 /* account for ea list len */
4902 name_len -= 4;
4903 temp_fea = ea_response_data->list;
4904 temp_ptr = (char *)temp_fea;
4905 /* loop through checking if we have a matching
4906 name and then return the associated value */
4907 while(name_len > 0) {
4908 __u16 value_len;
4909 name_len -= 4;
4910 temp_ptr += 4;
4911 value_len = le16_to_cpu(temp_fea->value_len);
4912 /* BB validate that value_len falls within SMB,
4913 even though maximum for name_len is 255 */
4914 if(memcmp(temp_fea->name,ea_name,
4915 temp_fea->name_len) == 0) {
4916 /* found a match */
4917 rc = value_len;
4918 /* account for prefix user. and trailing null */
4919 if(rc<=(int)buf_size) {
4920 memcpy(ea_value,
4921 temp_fea->name+temp_fea->name_len+1,
4922 rc);
4923 /* ea values, unlike ea names,
4924 are not null terminated */
4925 } else if(buf_size == 0) {
4926 /* skip copy - calc size only */
4927 } else {
4928 /* stop before overrun buffer */
4929 rc = -ERANGE;
4930 }
4931 break;
4932 }
4933 name_len -= temp_fea->name_len;
4934 temp_ptr += temp_fea->name_len;
4935 /* account for trailing null */
4936 name_len--;
4937 temp_ptr++;
4938 name_len -= value_len;
4939 temp_ptr += value_len;
4940 /* no trailing null to account for in value len */
4941 /* go on to next EA */
4942 temp_fea = (struct fea *)temp_ptr;
4943 }
4944 }
4945 }
4946 }
4947 if (pSMB)
4948 cifs_buf_release(pSMB);
4949 if (rc == -EAGAIN)
4950 goto QEARetry;
4951
4952 return (ssize_t)rc;
4953}
4954
4955int
4956CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4957 const char * ea_name, const void * ea_value,
737b758c
SF
4958 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4959 int remap)
1da177e4
LT
4960{
4961 struct smb_com_transaction2_spi_req *pSMB = NULL;
4962 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4963 struct fealist *parm_data;
4964 int name_len;
4965 int rc = 0;
4966 int bytes_returned = 0;
4967 __u16 params, param_offset, byte_count, offset, count;
4968
4969 cFYI(1, ("In SetEA"));
4970SetEARetry:
4971 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4972 (void **) &pSMBr);
4973 if (rc)
4974 return rc;
4975
4976 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4977 name_len =
b1a45695 4978 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4979 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4980 name_len++; /* trailing null */
4981 name_len *= 2;
4982 } else { /* BB improve the check for buffer overruns BB */
4983 name_len = strnlen(fileName, PATH_MAX);
4984 name_len++; /* trailing null */
4985 strncpy(pSMB->FileName, fileName, name_len);
4986 }
4987
4988 params = 6 + name_len;
4989
4990 /* done calculating parms using name_len of file name,
4991 now use name_len to calculate length of ea name
4992 we are going to create in the inode xattrs */
4993 if(ea_name == NULL)
4994 name_len = 0;
4995 else
4996 name_len = strnlen(ea_name,255);
4997
4998 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4999 pSMB->MaxParameterCount = cpu_to_le16(2);
5000 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5001 pSMB->MaxSetupCount = 0;
5002 pSMB->Reserved = 0;
5003 pSMB->Flags = 0;
5004 pSMB->Timeout = 0;
5005 pSMB->Reserved2 = 0;
5006 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5007 InformationLevel) - 4;
5008 offset = param_offset + params;
5009 pSMB->InformationLevel =
5010 cpu_to_le16(SMB_SET_FILE_EA);
5011
5012 parm_data =
5013 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5014 offset);
5015 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5016 pSMB->DataOffset = cpu_to_le16(offset);
5017 pSMB->SetupCount = 1;
5018 pSMB->Reserved3 = 0;
5019 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5020 byte_count = 3 /* pad */ + params + count;
5021 pSMB->DataCount = cpu_to_le16(count);
5022 parm_data->list_len = cpu_to_le32(count);
5023 parm_data->list[0].EA_flags = 0;
5024 /* we checked above that name len is less than 255 */
5025 parm_data->list[0].name_len = (__u8)name_len;;
5026 /* EA names are always ASCII */
5027 if(ea_name)
5028 strncpy(parm_data->list[0].name,ea_name,name_len);
5029 parm_data->list[0].name[name_len] = 0;
5030 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5031 /* caller ensures that ea_value_len is less than 64K but
5032 we need to ensure that it fits within the smb */
5033
5034 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5035 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5036 if(ea_value_len)
5037 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5038
5039 pSMB->TotalDataCount = pSMB->DataCount;
5040 pSMB->ParameterCount = cpu_to_le16(params);
5041 pSMB->TotalParameterCount = pSMB->ParameterCount;
5042 pSMB->Reserved4 = 0;
5043 pSMB->hdr.smb_buf_length += byte_count;
5044 pSMB->ByteCount = cpu_to_le16(byte_count);
5045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5047 if (rc) {
5048 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5049 }
5050
5051 cifs_buf_release(pSMB);
5052
5053 if (rc == -EAGAIN)
5054 goto SetEARetry;
5055
5056 return rc;
5057}
5058
5059#endif