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