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