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