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