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