blob: b4f7b9859e3bedeb895a62d21ed44eda58354de8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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);
Steve French09d1db52005-04-28 22:41:08 -070078 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
79 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
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) {
Steve French31ca3bc2005-04-28 22:41:11 -070093 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
94 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 struct nls_table *nls_codepage;
96 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -070097 reconnect, should be greater than cifs socket
98 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 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;
Steve French09d1db52005-04-28 22:41:08 -0700108 } /* else "hard" mount - keep retrying
109 until process is killed or server
110 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 } 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)
Steve French09d1db52005-04-28 22:41:08 -0700121 rc = cifs_setup_session(0, tcon->ses,
122 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
124 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700125 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
126 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 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 -
Steve French09d1db52005-04-28 22:41:08 -0700133 it is safer (and faster) to reopen files
134 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
136 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700137 know whether we can continue or not without
138 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 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) {
Steve French31ca3bc2005-04-28 22:41:11 -0700189 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
190 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700192 /* Give Demultiplex thread up to 10 seconds to
193 reconnect, should be greater than cifs socket
194 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
196 wait_event_interruptible_timeout(tcon->ses->server->response_q,
197 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700198 if(tcon->ses->server->tcpStatus ==
199 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 /* 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;
Steve French09d1db52005-04-28 22:41:08 -0700205 } /* else "hard" mount - keep retrying
206 until process is killed or server
207 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 } 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)
Steve French09d1db52005-04-28 22:41:08 -0700218 rc = cifs_setup_session(0, tcon->ses,
219 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
221 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700222 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
223 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 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 -
Steve French09d1db52005-04-28 22:41:08 -0700230 it is safer (and faster) to reopen files
231 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700234 know whether we can continue or not without
235 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 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 */
Steve French09d1db52005-04-28 22:41:08 -0700297 pBCC = (pSMB->hdr.WordCount * 2) +
298 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 (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;
Steve French09d1db52005-04-28 22:41:08 -0700349 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 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,
Steve French09d1db52005-04-28 22:41:08 -0700388 ("UID of server does not match previous connection to same ip address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 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 }
Steve French09d1db52005-04-28 22:41:08 -0700468 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
469 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 if (rc) {
471 up(&tcon->tconSem);
472 return rc;
473 } else {
474 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
477 &length, 0);
478 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700479 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
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
Steve French737b7582005-04-28 22:41:06 -0700553CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
554 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
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 =
Steve Frenchb1a45692005-05-17 16:07:23 -0500570 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700571 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 name_len++; /* trailing null */
573 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700574 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 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
Steve French737b7582005-04-28 22:41:06 -0700603CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
604 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
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) {
Steve French737b7582005-04-28 22:41:06 -0700620 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
621 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 name_len++; /* trailing null */
623 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700624 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 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,
Steve French737b7582005-04-28 22:41:06 -0700652 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653{
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) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500668 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700669 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 name_len++; /* trailing null */
671 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700672 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 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,
Steve French737b7582005-04-28 22:41:06 -0700702 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
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 =
Steve Frenchb1a45692005-05-17 16:07:23 -0500722 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700723 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 name_len++; /* trailing null */
725 name_len *= 2;
726 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700727 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 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);
Steve French09d1db52005-04-28 22:41:08 -0700756 /* BB Expirement with various impersonation levels and verify */
757 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 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 {
Steve French09d1db52005-04-28 22:41:08 -0700771 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 *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
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500954int
955CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 const int netfid, const unsigned int count,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500957 const __u64 offset, unsigned int *nbytes, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 const int long_op)
959{
960 int rc = -EACCES;
961 WRITE_REQ *pSMB = NULL;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500962 int bytes_returned;
963 int smb_hdr_len;
964 __u32 bytes_sent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 __u16 byte_count;
966
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500967 cERROR(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if (rc)
970 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 /* tcon and ses pointer are checked in smb_init */
972 if (tcon->ses->server == NULL)
973 return -ECONNABORTED;
974
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500975 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 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;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500982
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 if (bytes_sent > count)
995 bytes_sent = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 pSMB->DataOffset =
997 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
998
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500999 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 pSMB->ByteCount = cpu_to_le16(byte_count);
1005
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001006 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1007 buf, bytes_sent, &bytes_returned, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 if (rc) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001009 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001011 } 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
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}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001025
1026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027#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));
Steve French46810cb2005-04-28 22:41:09 -07001043 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1044
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 if (rc)
1046 return rc;
1047
Steve French46810cb2005-04-28 22:41:09 -07001048 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 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 }
Steve French46810cb2005-04-28 22:41:09 -07001087 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
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,
Steve French737b7582005-04-28 22:41:06 -07001136 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137{
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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001159 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001160 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001167 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001168 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 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,
Steve French737b7582005-04-28 22:41:06 -07001208 int netfid, char * target_name,
1209 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210{
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);
Steve Frenchb1a45692005-05-17 16:07:23 -05001254 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001255 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001257 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001258 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
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,
Steve French737b7582005-04-28 22:41:06 -07001292 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293{
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) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001314 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001315 fromName, PATH_MAX, nls_codepage,
1316 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 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;
Steve Frenchb1a45692005-05-17 16:07:23 -05001322 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001323 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 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,
Steve French737b7582005-04-28 22:41:06 -07001452 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453{
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) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001471 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001472 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001494 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001495 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 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,
Steve French737b7582005-04-28 22:41:06 -07001537 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538{
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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001564 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001565 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001571 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001572 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 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);
Steve French737b7582005-04-28 22:41:06 -07001682 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 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 */
Steve French737b7582005-04-28 22:41:06 -07001817static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1818 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819{
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,
Steve French737b7582005-04-28 22:41:06 -07001937 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938{
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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001957 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07001958 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 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,
Steve French737b7582005-04-28 22:41:06 -07002022 const char *local_acl, const int buflen,
2023 const int acl_type,
2024 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025{
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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002042 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002043 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 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
Steve Frenchf654bac2005-04-28 22:41:04 -07002098/* 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
Steve Frenchc67593a2005-04-28 22:41:04 -07002119 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002120 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002121 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002122 /* 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;
Steve Frenchc67593a2005-04-28 22:41:04 -07002129 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2130 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002131 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);
Steve Frenchc67593a2005-04-28 22:41:04 -07002136 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002137 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2138 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2139 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002140 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002141 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
2183int
2184CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2185 const unsigned char *searchName,
2186 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002187 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188{
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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002206 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002207 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 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,
Steve French737b7582005-04-28 22:41:06 -07002268 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269{
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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002287 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002288 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 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 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002368 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 /* 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 */
2414
2415 /* BB fill in */
2416 }
2417
2418 cifs_buf_release(pSMB);
2419 if (rc == -EAGAIN)
2420 goto findUniqueRetry;
2421
2422 return rc;
2423}
2424#endif /* end unused (temporarily) function */
2425
2426/* xid, tcon, searchName and codepage are input parms, rest are returned */
2427int
2428CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2429 const char *searchName,
2430 const struct nls_table *nls_codepage,
2431 __u16 * pnetfid,
Steve French737b7582005-04-28 22:41:06 -07002432 struct cifs_search_info * psrch_inf, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433{
2434/* level 257 SMB_ */
2435 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2436 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2437 T2_FFIRST_RSP_PARMS * parms;
2438 int rc = 0;
2439 int bytes_returned = 0;
2440 int name_len;
2441 __u16 params, byte_count;
2442
Steve French737b7582005-04-28 22:41:06 -07002443 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
2445findFirstRetry:
2446 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2447 (void **) &pSMBr);
2448 if (rc)
2449 return rc;
2450
2451 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2452 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002453 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002454 PATH_MAX, nls_codepage, remap);
2455 /* We can not add the asterik earlier in case
2456 it got remapped to 0xF03A as if it were part of the
2457 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 name_len *= 2;
Steve French737b7582005-04-28 22:41:06 -07002459 pSMB->FileName[name_len] = '\\';
2460 pSMB->FileName[name_len+1] = 0;
2461 pSMB->FileName[name_len+2] = '*';
2462 pSMB->FileName[name_len+3] = 0;
2463 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2465 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002466 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 } else { /* BB add check for overrun of SMB buf BB */
2468 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469/* BB fix here and in unicode clause above ie
2470 if(name_len > buffersize-header)
2471 free buffer exit; BB */
2472 strncpy(pSMB->FileName, searchName, name_len);
Steve French68575472005-04-30 11:10:57 -07002473 pSMB->FileName[name_len] = '\\';
2474 pSMB->FileName[name_len+1] = '*';
2475 pSMB->FileName[name_len+2] = 0;
2476 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 }
2478
2479 params = 12 + name_len /* includes null */ ;
2480 pSMB->TotalDataCount = 0; /* no EAs */
2481 pSMB->MaxParameterCount = cpu_to_le16(10);
2482 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2483 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2484 pSMB->MaxSetupCount = 0;
2485 pSMB->Reserved = 0;
2486 pSMB->Flags = 0;
2487 pSMB->Timeout = 0;
2488 pSMB->Reserved2 = 0;
2489 byte_count = params + 1 /* pad */ ;
2490 pSMB->TotalParameterCount = cpu_to_le16(params);
2491 pSMB->ParameterCount = pSMB->TotalParameterCount;
2492 pSMB->ParameterOffset = cpu_to_le16(
2493 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2494 pSMB->DataCount = 0;
2495 pSMB->DataOffset = 0;
2496 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2497 pSMB->Reserved3 = 0;
2498 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2499 pSMB->SearchAttributes =
2500 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2501 ATTR_DIRECTORY);
2502 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2503 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2504 CIFS_SEARCH_RETURN_RESUME);
2505 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2506
2507 /* BB what should we set StorageType to? Does it matter? BB */
2508 pSMB->SearchStorageType = 0;
2509 pSMB->hdr.smb_buf_length += byte_count;
2510 pSMB->ByteCount = cpu_to_le16(byte_count);
2511
2512 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2513 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2514
2515 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2516 /* BB Add code to handle unsupported level rc */
2517 cFYI(1, ("Error in FindFirst = %d", rc));
2518
2519 if (pSMB)
2520 cifs_buf_release(pSMB);
2521
2522 /* BB eventually could optimize out free and realloc of buf */
2523 /* for this case */
2524 if (rc == -EAGAIN)
2525 goto findFirstRetry;
2526 } else { /* decode response */
2527 /* BB remember to free buffer if error BB */
2528 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2529 if(rc == 0) {
2530 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2531 psrch_inf->unicode = TRUE;
2532 else
2533 psrch_inf->unicode = FALSE;
2534
2535 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2536 psrch_inf->srch_entries_start =
2537 (char *) &pSMBr->hdr.Protocol +
2538 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2540 le16_to_cpu(pSMBr->t2.ParameterOffset));
2541
2542 if(parms->EndofSearch)
2543 psrch_inf->endOfSearch = TRUE;
2544 else
2545 psrch_inf->endOfSearch = FALSE;
2546
2547 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2548 psrch_inf->index_of_last_entry =
2549 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 *pnetfid = parms->SearchHandle;
2551 } else {
2552 cifs_buf_release(pSMB);
2553 }
2554 }
2555
2556 return rc;
2557}
2558
2559int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2560 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2561{
2562 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2563 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2564 T2_FNEXT_RSP_PARMS * parms;
2565 char *response_data;
2566 int rc = 0;
2567 int bytes_returned, name_len;
2568 __u16 params, byte_count;
2569
2570 cFYI(1, ("In FindNext"));
2571
2572 if(psrch_inf->endOfSearch == TRUE)
2573 return -ENOENT;
2574
2575 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2576 (void **) &pSMBr);
2577 if (rc)
2578 return rc;
2579
2580 params = 14; /* includes 2 bytes of null string, converted to LE below */
2581 byte_count = 0;
2582 pSMB->TotalDataCount = 0; /* no EAs */
2583 pSMB->MaxParameterCount = cpu_to_le16(8);
2584 pSMB->MaxDataCount =
2585 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2586 pSMB->MaxSetupCount = 0;
2587 pSMB->Reserved = 0;
2588 pSMB->Flags = 0;
2589 pSMB->Timeout = 0;
2590 pSMB->Reserved2 = 0;
2591 pSMB->ParameterOffset = cpu_to_le16(
2592 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2593 pSMB->DataCount = 0;
2594 pSMB->DataOffset = 0;
2595 pSMB->SetupCount = 1;
2596 pSMB->Reserved3 = 0;
2597 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2598 pSMB->SearchHandle = searchHandle; /* always kept as le */
2599 pSMB->SearchCount =
2600 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2601 /* test for Unix extensions */
2602/* if (tcon->ses->capabilities & CAP_UNIX) {
2603 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2604 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2605 } else {
2606 pSMB->InformationLevel =
2607 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2608 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2609 } */
2610 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2611 pSMB->ResumeKey = psrch_inf->resume_key;
2612 pSMB->SearchFlags =
2613 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2614
2615 name_len = psrch_inf->resume_name_len;
2616 params += name_len;
2617 if(name_len < PATH_MAX) {
2618 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2619 byte_count += name_len;
2620 } else {
2621 rc = -EINVAL;
2622 goto FNext2_err_exit;
2623 }
2624 byte_count = params + 1 /* pad */ ;
2625 pSMB->TotalParameterCount = cpu_to_le16(params);
2626 pSMB->ParameterCount = pSMB->TotalParameterCount;
2627 pSMB->hdr.smb_buf_length += byte_count;
2628 pSMB->ByteCount = cpu_to_le16(byte_count);
2629
2630 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2631 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2632
2633 if (rc) {
2634 if (rc == -EBADF) {
2635 psrch_inf->endOfSearch = TRUE;
2636 rc = 0; /* search probably was closed at end of search above */
2637 } else
2638 cFYI(1, ("FindNext returned = %d", rc));
2639 } else { /* decode response */
2640 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2641
2642 if(rc == 0) {
2643 /* BB fixme add lock for file (srch_info) struct here */
2644 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2645 psrch_inf->unicode = TRUE;
2646 else
2647 psrch_inf->unicode = FALSE;
2648 response_data = (char *) &pSMBr->hdr.Protocol +
2649 le16_to_cpu(pSMBr->t2.ParameterOffset);
2650 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2651 response_data = (char *)&pSMBr->hdr.Protocol +
2652 le16_to_cpu(pSMBr->t2.DataOffset);
2653 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2654 psrch_inf->srch_entries_start = response_data;
2655 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2656 if(parms->EndofSearch)
2657 psrch_inf->endOfSearch = TRUE;
2658 else
2659 psrch_inf->endOfSearch = FALSE;
2660
2661 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2662 psrch_inf->index_of_last_entry +=
2663 psrch_inf->entries_in_buffer;
2664/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2665
2666 /* BB fixme add unlock here */
2667 }
2668
2669 }
2670
2671 /* BB On error, should we leave previous search buf (and count and
2672 last entry fields) intact or free the previous one? */
2673
2674 /* Note: On -EAGAIN error only caller can retry on handle based calls
2675 since file handle passed in no longer valid */
2676FNext2_err_exit:
2677 if (rc != 0)
2678 cifs_buf_release(pSMB);
2679
2680 return rc;
2681}
2682
2683int
2684CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2685{
2686 int rc = 0;
2687 FINDCLOSE_REQ *pSMB = NULL;
2688 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2689 int bytes_returned;
2690
2691 cFYI(1, ("In CIFSSMBFindClose"));
2692 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2693
2694 /* no sense returning error if session restarted
2695 as file handle has been closed */
2696 if(rc == -EAGAIN)
2697 return 0;
2698 if (rc)
2699 return rc;
2700
2701 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2702 pSMB->FileID = searchHandle;
2703 pSMB->ByteCount = 0;
2704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2706 if (rc) {
2707 cERROR(1, ("Send error in FindClose = %d", rc));
2708 }
2709 cifs_small_buf_release(pSMB);
2710
2711 /* Since session is dead, search handle closed on server already */
2712 if (rc == -EAGAIN)
2713 rc = 0;
2714
2715 return rc;
2716}
2717
2718#ifdef CONFIG_CIFS_EXPERIMENTAL
2719int
2720CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2721 const unsigned char *searchName,
2722 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002723 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724{
2725 int rc = 0;
2726 TRANSACTION2_QPI_REQ *pSMB = NULL;
2727 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2728 int name_len, bytes_returned;
2729 __u16 params, byte_count;
2730
2731 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2732 if(tcon == NULL)
2733 return -ENODEV;
2734
2735GetInodeNumberRetry:
2736 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2737 (void **) &pSMBr);
2738 if (rc)
2739 return rc;
2740
2741
2742 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2743 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002744 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002745 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 name_len++; /* trailing null */
2747 name_len *= 2;
2748 } else { /* BB improve the check for buffer overruns BB */
2749 name_len = strnlen(searchName, PATH_MAX);
2750 name_len++; /* trailing null */
2751 strncpy(pSMB->FileName, searchName, name_len);
2752 }
2753
2754 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2755 pSMB->TotalDataCount = 0;
2756 pSMB->MaxParameterCount = cpu_to_le16(2);
2757 /* BB find exact max data count below from sess structure BB */
2758 pSMB->MaxDataCount = cpu_to_le16(4000);
2759 pSMB->MaxSetupCount = 0;
2760 pSMB->Reserved = 0;
2761 pSMB->Flags = 0;
2762 pSMB->Timeout = 0;
2763 pSMB->Reserved2 = 0;
2764 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2765 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2766 pSMB->DataCount = 0;
2767 pSMB->DataOffset = 0;
2768 pSMB->SetupCount = 1;
2769 pSMB->Reserved3 = 0;
2770 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2771 byte_count = params + 1 /* pad */ ;
2772 pSMB->TotalParameterCount = cpu_to_le16(params);
2773 pSMB->ParameterCount = pSMB->TotalParameterCount;
2774 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2775 pSMB->Reserved4 = 0;
2776 pSMB->hdr.smb_buf_length += byte_count;
2777 pSMB->ByteCount = cpu_to_le16(byte_count);
2778
2779 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2780 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2781 if (rc) {
2782 cFYI(1, ("error %d in QueryInternalInfo", rc));
2783 } else {
2784 /* decode response */
2785 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2786 if (rc || (pSMBr->ByteCount < 2))
2787 /* BB also check enough total bytes returned */
2788 /* If rc should we check for EOPNOSUPP and
2789 disable the srvino flag? or in caller? */
2790 rc = -EIO; /* bad smb */
2791 else {
2792 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2793 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2794 struct file_internal_info * pfinfo;
2795 /* BB Do we need a cast or hash here ? */
2796 if(count < 8) {
2797 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2798 rc = -EIO;
2799 goto GetInodeNumOut;
2800 }
2801 pfinfo = (struct file_internal_info *)
2802 (data_offset + (char *) &pSMBr->hdr.Protocol);
2803 *inode_number = pfinfo->UniqueId;
2804 }
2805 }
2806GetInodeNumOut:
2807 cifs_buf_release(pSMB);
2808 if (rc == -EAGAIN)
2809 goto GetInodeNumberRetry;
2810 return rc;
2811}
2812#endif /* CIFS_EXPERIMENTAL */
2813
2814int
2815CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2816 const unsigned char *searchName,
2817 unsigned char **targetUNCs,
2818 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07002819 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820{
2821/* TRANS2_GET_DFS_REFERRAL */
2822 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2823 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2824 struct dfs_referral_level_3 * referrals = NULL;
2825 int rc = 0;
2826 int bytes_returned;
2827 int name_len;
2828 unsigned int i;
2829 char * temp;
2830 __u16 params, byte_count;
2831 *number_of_UNC_in_array = 0;
2832 *targetUNCs = NULL;
2833
2834 cFYI(1, ("In GetDFSRefer the path %s", searchName));
2835 if (ses == NULL)
2836 return -ENODEV;
2837getDFSRetry:
2838 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2839 (void **) &pSMBr);
2840 if (rc)
2841 return rc;
2842
2843 pSMB->hdr.Tid = ses->ipc_tid;
2844 pSMB->hdr.Uid = ses->Suid;
2845 if (ses->capabilities & CAP_STATUS32) {
2846 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2847 }
2848 if (ses->capabilities & CAP_DFS) {
2849 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2850 }
2851
2852 if (ses->capabilities & CAP_UNICODE) {
2853 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2854 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002855 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07002856 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 name_len++; /* trailing null */
2858 name_len *= 2;
2859 } else { /* BB improve the check for buffer overruns BB */
2860 name_len = strnlen(searchName, PATH_MAX);
2861 name_len++; /* trailing null */
2862 strncpy(pSMB->RequestFileName, searchName, name_len);
2863 }
2864
2865 params = 2 /* level */ + name_len /*includes null */ ;
2866 pSMB->TotalDataCount = 0;
2867 pSMB->DataCount = 0;
2868 pSMB->DataOffset = 0;
2869 pSMB->MaxParameterCount = 0;
2870 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2871 pSMB->MaxSetupCount = 0;
2872 pSMB->Reserved = 0;
2873 pSMB->Flags = 0;
2874 pSMB->Timeout = 0;
2875 pSMB->Reserved2 = 0;
2876 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2877 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2878 pSMB->SetupCount = 1;
2879 pSMB->Reserved3 = 0;
2880 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2881 byte_count = params + 3 /* pad */ ;
2882 pSMB->ParameterCount = cpu_to_le16(params);
2883 pSMB->TotalParameterCount = pSMB->ParameterCount;
2884 pSMB->MaxReferralLevel = cpu_to_le16(3);
2885 pSMB->hdr.smb_buf_length += byte_count;
2886 pSMB->ByteCount = cpu_to_le16(byte_count);
2887
2888 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2889 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2890 if (rc) {
2891 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2892 } else { /* decode response */
2893/* BB Add logic to parse referrals here */
2894 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2895
2896 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
2897 rc = -EIO; /* bad smb */
2898 else {
2899 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2900 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2901
2902 cFYI(1,
2903 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
2904 pSMBr->ByteCount, data_offset));
2905 referrals =
2906 (struct dfs_referral_level_3 *)
2907 (8 /* sizeof start of data block */ +
2908 data_offset +
2909 (char *) &pSMBr->hdr.Protocol);
2910 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",
2911 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)));
2912 /* BB This field is actually two bytes in from start of
2913 data block so we could do safety check that DataBlock
2914 begins at address of pSMBr->NumberOfReferrals */
2915 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2916
2917 /* BB Fix below so can return more than one referral */
2918 if(*number_of_UNC_in_array > 1)
2919 *number_of_UNC_in_array = 1;
2920
2921 /* get the length of the strings describing refs */
2922 name_len = 0;
2923 for(i=0;i<*number_of_UNC_in_array;i++) {
2924 /* make sure that DfsPathOffset not past end */
2925 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2926 if (offset > data_count) {
2927 /* if invalid referral, stop here and do
2928 not try to copy any more */
2929 *number_of_UNC_in_array = i;
2930 break;
2931 }
2932 temp = ((char *)referrals) + offset;
2933
2934 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2935 name_len += UniStrnlen((wchar_t *)temp,data_count);
2936 } else {
2937 name_len += strnlen(temp,data_count);
2938 }
2939 referrals++;
2940 /* BB add check that referral pointer does not fall off end PDU */
2941
2942 }
2943 /* BB add check for name_len bigger than bcc */
2944 *targetUNCs =
2945 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2946 if(*targetUNCs == NULL) {
2947 rc = -ENOMEM;
2948 goto GetDFSRefExit;
2949 }
2950 /* copy the ref strings */
2951 referrals =
2952 (struct dfs_referral_level_3 *)
2953 (8 /* sizeof data hdr */ +
2954 data_offset +
2955 (char *) &pSMBr->hdr.Protocol);
2956
2957 for(i=0;i<*number_of_UNC_in_array;i++) {
2958 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2959 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2960 cifs_strfromUCS_le(*targetUNCs,
2961 (wchar_t *) temp, name_len, nls_codepage);
2962 } else {
2963 strncpy(*targetUNCs,temp,name_len);
2964 }
2965 /* BB update target_uncs pointers */
2966 referrals++;
2967 }
2968 temp = *targetUNCs;
2969 temp[name_len] = 0;
2970 }
2971
2972 }
2973GetDFSRefExit:
2974 if (pSMB)
2975 cifs_buf_release(pSMB);
2976
2977 if (rc == -EAGAIN)
2978 goto getDFSRetry;
2979
2980 return rc;
2981}
2982
2983int
Steve French737b7582005-04-28 22:41:06 -07002984CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985{
2986/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
2987 TRANSACTION2_QFSI_REQ *pSMB = NULL;
2988 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2989 FILE_SYSTEM_INFO *response_data;
2990 int rc = 0;
2991 int bytes_returned = 0;
2992 __u16 params, byte_count;
2993
2994 cFYI(1, ("In QFSInfo"));
2995QFSInfoRetry:
2996 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2997 (void **) &pSMBr);
2998 if (rc)
2999 return rc;
3000
3001 params = 2; /* level */
3002 pSMB->TotalDataCount = 0;
3003 pSMB->MaxParameterCount = cpu_to_le16(2);
3004 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3005 pSMB->MaxSetupCount = 0;
3006 pSMB->Reserved = 0;
3007 pSMB->Flags = 0;
3008 pSMB->Timeout = 0;
3009 pSMB->Reserved2 = 0;
3010 byte_count = params + 1 /* pad */ ;
3011 pSMB->TotalParameterCount = cpu_to_le16(params);
3012 pSMB->ParameterCount = pSMB->TotalParameterCount;
3013 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3014 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3015 pSMB->DataCount = 0;
3016 pSMB->DataOffset = 0;
3017 pSMB->SetupCount = 1;
3018 pSMB->Reserved3 = 0;
3019 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3020 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3021 pSMB->hdr.smb_buf_length += byte_count;
3022 pSMB->ByteCount = cpu_to_le16(byte_count);
3023
3024 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3026 if (rc) {
3027 cERROR(1, ("Send error in QFSInfo = %d", rc));
3028 } else { /* decode response */
3029 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3030
3031 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3032 rc = -EIO; /* bad smb */
3033 else {
3034 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3035 cFYI(1,
3036 ("Decoding qfsinfo response. BCC: %d Offset %d",
3037 pSMBr->ByteCount, data_offset));
3038
3039 response_data =
3040 (FILE_SYSTEM_INFO
3041 *) (((char *) &pSMBr->hdr.Protocol) +
3042 data_offset);
3043 FSData->f_bsize =
3044 le32_to_cpu(response_data->BytesPerSector) *
3045 le32_to_cpu(response_data->
3046 SectorsPerAllocationUnit);
3047 FSData->f_blocks =
3048 le64_to_cpu(response_data->TotalAllocationUnits);
3049 FSData->f_bfree = FSData->f_bavail =
3050 le64_to_cpu(response_data->FreeAllocationUnits);
3051 cFYI(1,
3052 ("Blocks: %lld Free: %lld Block size %ld",
3053 (unsigned long long)FSData->f_blocks,
3054 (unsigned long long)FSData->f_bfree,
3055 FSData->f_bsize));
3056 }
3057 }
3058 cifs_buf_release(pSMB);
3059
3060 if (rc == -EAGAIN)
3061 goto QFSInfoRetry;
3062
3063 return rc;
3064}
3065
3066int
Steve French737b7582005-04-28 22:41:06 -07003067CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068{
3069/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3070 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3071 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3072 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3073 int rc = 0;
3074 int bytes_returned = 0;
3075 __u16 params, byte_count;
3076
3077 cFYI(1, ("In QFSAttributeInfo"));
3078QFSAttributeRetry:
3079 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3080 (void **) &pSMBr);
3081 if (rc)
3082 return rc;
3083
3084 params = 2; /* level */
3085 pSMB->TotalDataCount = 0;
3086 pSMB->MaxParameterCount = cpu_to_le16(2);
3087 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3088 pSMB->MaxSetupCount = 0;
3089 pSMB->Reserved = 0;
3090 pSMB->Flags = 0;
3091 pSMB->Timeout = 0;
3092 pSMB->Reserved2 = 0;
3093 byte_count = params + 1 /* pad */ ;
3094 pSMB->TotalParameterCount = cpu_to_le16(params);
3095 pSMB->ParameterCount = pSMB->TotalParameterCount;
3096 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3097 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3098 pSMB->DataCount = 0;
3099 pSMB->DataOffset = 0;
3100 pSMB->SetupCount = 1;
3101 pSMB->Reserved3 = 0;
3102 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3103 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3104 pSMB->hdr.smb_buf_length += byte_count;
3105 pSMB->ByteCount = cpu_to_le16(byte_count);
3106
3107 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3108 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3109 if (rc) {
3110 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3111 } else { /* decode response */
3112 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3113
3114 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3115 rc = -EIO; /* bad smb */
3116 } else {
3117 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3118 response_data =
3119 (FILE_SYSTEM_ATTRIBUTE_INFO
3120 *) (((char *) &pSMBr->hdr.Protocol) +
3121 data_offset);
3122 memcpy(&tcon->fsAttrInfo, response_data,
3123 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3124 }
3125 }
3126 cifs_buf_release(pSMB);
3127
3128 if (rc == -EAGAIN)
3129 goto QFSAttributeRetry;
3130
3131 return rc;
3132}
3133
3134int
Steve French737b7582005-04-28 22:41:06 -07003135CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136{
3137/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3138 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3139 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3140 FILE_SYSTEM_DEVICE_INFO *response_data;
3141 int rc = 0;
3142 int bytes_returned = 0;
3143 __u16 params, byte_count;
3144
3145 cFYI(1, ("In QFSDeviceInfo"));
3146QFSDeviceRetry:
3147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3148 (void **) &pSMBr);
3149 if (rc)
3150 return rc;
3151
3152 params = 2; /* level */
3153 pSMB->TotalDataCount = 0;
3154 pSMB->MaxParameterCount = cpu_to_le16(2);
3155 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3156 pSMB->MaxSetupCount = 0;
3157 pSMB->Reserved = 0;
3158 pSMB->Flags = 0;
3159 pSMB->Timeout = 0;
3160 pSMB->Reserved2 = 0;
3161 byte_count = params + 1 /* pad */ ;
3162 pSMB->TotalParameterCount = cpu_to_le16(params);
3163 pSMB->ParameterCount = pSMB->TotalParameterCount;
3164 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3165 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3166
3167 pSMB->DataCount = 0;
3168 pSMB->DataOffset = 0;
3169 pSMB->SetupCount = 1;
3170 pSMB->Reserved3 = 0;
3171 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3172 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3173 pSMB->hdr.smb_buf_length += byte_count;
3174 pSMB->ByteCount = cpu_to_le16(byte_count);
3175
3176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3178 if (rc) {
3179 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3180 } else { /* decode response */
3181 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3182
3183 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3184 rc = -EIO; /* bad smb */
3185 else {
3186 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3187 response_data =
Steve French737b7582005-04-28 22:41:06 -07003188 (FILE_SYSTEM_DEVICE_INFO *)
3189 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 data_offset);
3191 memcpy(&tcon->fsDevInfo, response_data,
3192 sizeof (FILE_SYSTEM_DEVICE_INFO));
3193 }
3194 }
3195 cifs_buf_release(pSMB);
3196
3197 if (rc == -EAGAIN)
3198 goto QFSDeviceRetry;
3199
3200 return rc;
3201}
3202
3203int
Steve French737b7582005-04-28 22:41:06 -07003204CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205{
3206/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3207 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3208 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3209 FILE_SYSTEM_UNIX_INFO *response_data;
3210 int rc = 0;
3211 int bytes_returned = 0;
3212 __u16 params, byte_count;
3213
3214 cFYI(1, ("In QFSUnixInfo"));
3215QFSUnixRetry:
3216 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3217 (void **) &pSMBr);
3218 if (rc)
3219 return rc;
3220
3221 params = 2; /* level */
3222 pSMB->TotalDataCount = 0;
3223 pSMB->DataCount = 0;
3224 pSMB->DataOffset = 0;
3225 pSMB->MaxParameterCount = cpu_to_le16(2);
3226 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3227 pSMB->MaxSetupCount = 0;
3228 pSMB->Reserved = 0;
3229 pSMB->Flags = 0;
3230 pSMB->Timeout = 0;
3231 pSMB->Reserved2 = 0;
3232 byte_count = params + 1 /* pad */ ;
3233 pSMB->ParameterCount = cpu_to_le16(params);
3234 pSMB->TotalParameterCount = pSMB->ParameterCount;
3235 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3236 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3237 pSMB->SetupCount = 1;
3238 pSMB->Reserved3 = 0;
3239 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3240 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3241 pSMB->hdr.smb_buf_length += byte_count;
3242 pSMB->ByteCount = cpu_to_le16(byte_count);
3243
3244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3246 if (rc) {
3247 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3248 } else { /* decode response */
3249 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3250
3251 if (rc || (pSMBr->ByteCount < 13)) {
3252 rc = -EIO; /* bad smb */
3253 } else {
3254 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3255 response_data =
3256 (FILE_SYSTEM_UNIX_INFO
3257 *) (((char *) &pSMBr->hdr.Protocol) +
3258 data_offset);
3259 memcpy(&tcon->fsUnixInfo, response_data,
3260 sizeof (FILE_SYSTEM_UNIX_INFO));
3261 }
3262 }
3263 cifs_buf_release(pSMB);
3264
3265 if (rc == -EAGAIN)
3266 goto QFSUnixRetry;
3267
3268
3269 return rc;
3270}
3271
3272
3273int
3274CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003275 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276{
3277/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3278 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3279 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3280 FILE_SYSTEM_POSIX_INFO *response_data;
3281 int rc = 0;
3282 int bytes_returned = 0;
3283 __u16 params, byte_count;
3284
3285 cFYI(1, ("In QFSPosixInfo"));
3286QFSPosixRetry:
3287 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3288 (void **) &pSMBr);
3289 if (rc)
3290 return rc;
3291
3292 params = 2; /* level */
3293 pSMB->TotalDataCount = 0;
3294 pSMB->DataCount = 0;
3295 pSMB->DataOffset = 0;
3296 pSMB->MaxParameterCount = cpu_to_le16(2);
3297 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3298 pSMB->MaxSetupCount = 0;
3299 pSMB->Reserved = 0;
3300 pSMB->Flags = 0;
3301 pSMB->Timeout = 0;
3302 pSMB->Reserved2 = 0;
3303 byte_count = params + 1 /* pad */ ;
3304 pSMB->ParameterCount = cpu_to_le16(params);
3305 pSMB->TotalParameterCount = pSMB->ParameterCount;
3306 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3307 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3308 pSMB->SetupCount = 1;
3309 pSMB->Reserved3 = 0;
3310 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3311 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3312 pSMB->hdr.smb_buf_length += byte_count;
3313 pSMB->ByteCount = cpu_to_le16(byte_count);
3314
3315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3317 if (rc) {
3318 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3319 } else { /* decode response */
3320 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3321
3322 if (rc || (pSMBr->ByteCount < 13)) {
3323 rc = -EIO; /* bad smb */
3324 } else {
3325 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3326 response_data =
3327 (FILE_SYSTEM_POSIX_INFO
3328 *) (((char *) &pSMBr->hdr.Protocol) +
3329 data_offset);
3330 FSData->f_bsize =
3331 le32_to_cpu(response_data->BlockSize);
3332 FSData->f_blocks =
3333 le64_to_cpu(response_data->TotalBlocks);
3334 FSData->f_bfree =
3335 le64_to_cpu(response_data->BlocksAvail);
3336 if(response_data->UserBlocksAvail == -1) {
3337 FSData->f_bavail = FSData->f_bfree;
3338 } else {
3339 FSData->f_bavail =
3340 le64_to_cpu(response_data->UserBlocksAvail);
3341 }
3342 if(response_data->TotalFileNodes != -1)
3343 FSData->f_files =
3344 le64_to_cpu(response_data->TotalFileNodes);
3345 if(response_data->FreeFileNodes != -1)
3346 FSData->f_ffree =
3347 le64_to_cpu(response_data->FreeFileNodes);
3348 }
3349 }
3350 cifs_buf_release(pSMB);
3351
3352 if (rc == -EAGAIN)
3353 goto QFSPosixRetry;
3354
3355 return rc;
3356}
3357
3358
3359/* We can not use write of zero bytes trick to
3360 set file size due to need for large file support. Also note that
3361 this SetPathInfo is preferred to SetFileInfo based method in next
3362 routine which is only needed to work around a sharing violation bug
3363 in Samba which this routine can run into */
3364
3365int
3366CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003367 __u64 size, int SetAllocation,
3368 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369{
3370 struct smb_com_transaction2_spi_req *pSMB = NULL;
3371 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3372 struct file_end_of_file_info *parm_data;
3373 int name_len;
3374 int rc = 0;
3375 int bytes_returned = 0;
3376 __u16 params, byte_count, data_count, param_offset, offset;
3377
3378 cFYI(1, ("In SetEOF"));
3379SetEOFRetry:
3380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3381 (void **) &pSMBr);
3382 if (rc)
3383 return rc;
3384
3385 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3386 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003387 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003388 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 name_len++; /* trailing null */
3390 name_len *= 2;
3391 } else { /* BB improve the check for buffer overruns BB */
3392 name_len = strnlen(fileName, PATH_MAX);
3393 name_len++; /* trailing null */
3394 strncpy(pSMB->FileName, fileName, name_len);
3395 }
3396 params = 6 + name_len;
3397 data_count = sizeof (struct file_end_of_file_info);
3398 pSMB->MaxParameterCount = cpu_to_le16(2);
3399 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3400 pSMB->MaxSetupCount = 0;
3401 pSMB->Reserved = 0;
3402 pSMB->Flags = 0;
3403 pSMB->Timeout = 0;
3404 pSMB->Reserved2 = 0;
3405 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3406 InformationLevel) - 4;
3407 offset = param_offset + params;
3408 if(SetAllocation) {
3409 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3410 pSMB->InformationLevel =
3411 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3412 else
3413 pSMB->InformationLevel =
3414 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3415 } else /* Set File Size */ {
3416 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3417 pSMB->InformationLevel =
3418 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3419 else
3420 pSMB->InformationLevel =
3421 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3422 }
3423
3424 parm_data =
3425 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3426 offset);
3427 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3428 pSMB->DataOffset = cpu_to_le16(offset);
3429 pSMB->SetupCount = 1;
3430 pSMB->Reserved3 = 0;
3431 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3432 byte_count = 3 /* pad */ + params + data_count;
3433 pSMB->DataCount = cpu_to_le16(data_count);
3434 pSMB->TotalDataCount = pSMB->DataCount;
3435 pSMB->ParameterCount = cpu_to_le16(params);
3436 pSMB->TotalParameterCount = pSMB->ParameterCount;
3437 pSMB->Reserved4 = 0;
3438 pSMB->hdr.smb_buf_length += byte_count;
3439 parm_data->FileSize = cpu_to_le64(size);
3440 pSMB->ByteCount = cpu_to_le16(byte_count);
3441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3443 if (rc) {
3444 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3445 }
3446
3447 cifs_buf_release(pSMB);
3448
3449 if (rc == -EAGAIN)
3450 goto SetEOFRetry;
3451
3452 return rc;
3453}
3454
3455int
3456CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3457 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3458{
3459 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3460 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3461 char *data_offset;
3462 struct file_end_of_file_info *parm_data;
3463 int rc = 0;
3464 int bytes_returned = 0;
3465 __u16 params, param_offset, offset, byte_count, count;
3466
3467 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3468 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003469 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3470
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 if (rc)
3472 return rc;
3473
Steve Frenchcd634992005-04-28 22:41:10 -07003474 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3475
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3477 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3478
3479 params = 6;
3480 pSMB->MaxSetupCount = 0;
3481 pSMB->Reserved = 0;
3482 pSMB->Flags = 0;
3483 pSMB->Timeout = 0;
3484 pSMB->Reserved2 = 0;
3485 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3486 offset = param_offset + params;
3487
3488 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3489
3490 count = sizeof(struct file_end_of_file_info);
3491 pSMB->MaxParameterCount = cpu_to_le16(2);
3492 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3493 pSMB->SetupCount = 1;
3494 pSMB->Reserved3 = 0;
3495 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3496 byte_count = 3 /* pad */ + params + count;
3497 pSMB->DataCount = cpu_to_le16(count);
3498 pSMB->ParameterCount = cpu_to_le16(params);
3499 pSMB->TotalDataCount = pSMB->DataCount;
3500 pSMB->TotalParameterCount = pSMB->ParameterCount;
3501 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3502 parm_data =
3503 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3504 offset);
3505 pSMB->DataOffset = cpu_to_le16(offset);
3506 parm_data->FileSize = cpu_to_le64(size);
3507 pSMB->Fid = fid;
3508 if(SetAllocation) {
3509 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3510 pSMB->InformationLevel =
3511 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3512 else
3513 pSMB->InformationLevel =
3514 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3515 } else /* Set File Size */ {
3516 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3517 pSMB->InformationLevel =
3518 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3519 else
3520 pSMB->InformationLevel =
3521 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3522 }
3523 pSMB->Reserved4 = 0;
3524 pSMB->hdr.smb_buf_length += byte_count;
3525 pSMB->ByteCount = cpu_to_le16(byte_count);
3526 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3527 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3528 if (rc) {
3529 cFYI(1,
3530 ("Send error in SetFileInfo (SetFileSize) = %d",
3531 rc));
3532 }
3533
3534 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003535 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536
3537 /* Note: On -EAGAIN error only caller can retry on handle based calls
3538 since file handle passed in no longer valid */
3539
3540 return rc;
3541}
3542
3543/* Some legacy servers such as NT4 require that the file times be set on
3544 an open handle, rather than by pathname - this is awkward due to
3545 potential access conflicts on the open, but it is unavoidable for these
3546 old servers since the only other choice is to go from 100 nanosecond DCE
3547 time and resort to the original setpathinfo level which takes the ancient
3548 DOS time format with 2 second granularity */
3549int
3550CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3551 __u16 fid)
3552{
3553 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3554 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3555 char *data_offset;
3556 int rc = 0;
3557 int bytes_returned = 0;
3558 __u16 params, param_offset, offset, byte_count, count;
3559
3560 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003561 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3562
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 if (rc)
3564 return rc;
3565
Steve Frenchcd634992005-04-28 22:41:10 -07003566 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3567
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 /* At this point there is no need to override the current pid
3569 with the pid of the opener, but that could change if we someday
3570 use an existing handle (rather than opening one on the fly) */
3571 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3572 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3573
3574 params = 6;
3575 pSMB->MaxSetupCount = 0;
3576 pSMB->Reserved = 0;
3577 pSMB->Flags = 0;
3578 pSMB->Timeout = 0;
3579 pSMB->Reserved2 = 0;
3580 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3581 offset = param_offset + params;
3582
3583 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3584
3585 count = sizeof (FILE_BASIC_INFO);
3586 pSMB->MaxParameterCount = cpu_to_le16(2);
3587 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3588 pSMB->SetupCount = 1;
3589 pSMB->Reserved3 = 0;
3590 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3591 byte_count = 3 /* pad */ + params + count;
3592 pSMB->DataCount = cpu_to_le16(count);
3593 pSMB->ParameterCount = cpu_to_le16(params);
3594 pSMB->TotalDataCount = pSMB->DataCount;
3595 pSMB->TotalParameterCount = pSMB->ParameterCount;
3596 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3597 pSMB->DataOffset = cpu_to_le16(offset);
3598 pSMB->Fid = fid;
3599 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3600 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3601 else
3602 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3603 pSMB->Reserved4 = 0;
3604 pSMB->hdr.smb_buf_length += byte_count;
3605 pSMB->ByteCount = cpu_to_le16(byte_count);
3606 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3607 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3609 if (rc) {
3610 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3611 }
3612
Steve Frenchcd634992005-04-28 22:41:10 -07003613 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614
3615 /* Note: On -EAGAIN error only caller can retry on handle based calls
3616 since file handle passed in no longer valid */
3617
3618 return rc;
3619}
3620
3621
3622int
3623CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3624 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07003625 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626{
3627 TRANSACTION2_SPI_REQ *pSMB = NULL;
3628 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3629 int name_len;
3630 int rc = 0;
3631 int bytes_returned = 0;
3632 char *data_offset;
3633 __u16 params, param_offset, offset, byte_count, count;
3634
3635 cFYI(1, ("In SetTimes"));
3636
3637SetTimesRetry:
3638 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3639 (void **) &pSMBr);
3640 if (rc)
3641 return rc;
3642
3643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3644 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003645 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003646 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 name_len++; /* trailing null */
3648 name_len *= 2;
3649 } else { /* BB improve the check for buffer overruns BB */
3650 name_len = strnlen(fileName, PATH_MAX);
3651 name_len++; /* trailing null */
3652 strncpy(pSMB->FileName, fileName, name_len);
3653 }
3654
3655 params = 6 + name_len;
3656 count = sizeof (FILE_BASIC_INFO);
3657 pSMB->MaxParameterCount = cpu_to_le16(2);
3658 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3659 pSMB->MaxSetupCount = 0;
3660 pSMB->Reserved = 0;
3661 pSMB->Flags = 0;
3662 pSMB->Timeout = 0;
3663 pSMB->Reserved2 = 0;
3664 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3665 InformationLevel) - 4;
3666 offset = param_offset + params;
3667 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3668 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3669 pSMB->DataOffset = cpu_to_le16(offset);
3670 pSMB->SetupCount = 1;
3671 pSMB->Reserved3 = 0;
3672 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3673 byte_count = 3 /* pad */ + params + count;
3674
3675 pSMB->DataCount = cpu_to_le16(count);
3676 pSMB->ParameterCount = cpu_to_le16(params);
3677 pSMB->TotalDataCount = pSMB->DataCount;
3678 pSMB->TotalParameterCount = pSMB->ParameterCount;
3679 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3680 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3681 else
3682 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3683 pSMB->Reserved4 = 0;
3684 pSMB->hdr.smb_buf_length += byte_count;
3685 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3686 pSMB->ByteCount = cpu_to_le16(byte_count);
3687 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3688 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3689 if (rc) {
3690 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3691 }
3692
3693 cifs_buf_release(pSMB);
3694
3695 if (rc == -EAGAIN)
3696 goto SetTimesRetry;
3697
3698 return rc;
3699}
3700
3701/* Can not be used to set time stamps yet (due to old DOS time format) */
3702/* Can be used to set attributes */
3703#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
3704 handling it anyway and NT4 was what we thought it would be needed for
3705 Do not delete it until we prove whether needed for Win9x though */
3706int
3707CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3708 __u16 dos_attrs, const struct nls_table *nls_codepage)
3709{
3710 SETATTR_REQ *pSMB = NULL;
3711 SETATTR_RSP *pSMBr = NULL;
3712 int rc = 0;
3713 int bytes_returned;
3714 int name_len;
3715
3716 cFYI(1, ("In SetAttrLegacy"));
3717
3718SetAttrLgcyRetry:
3719 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3720 (void **) &pSMBr);
3721 if (rc)
3722 return rc;
3723
3724 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3725 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003726 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 PATH_MAX, nls_codepage);
3728 name_len++; /* trailing null */
3729 name_len *= 2;
3730 } else { /* BB improve the check for buffer overruns BB */
3731 name_len = strnlen(fileName, PATH_MAX);
3732 name_len++; /* trailing null */
3733 strncpy(pSMB->fileName, fileName, name_len);
3734 }
3735 pSMB->attr = cpu_to_le16(dos_attrs);
3736 pSMB->BufferFormat = 0x04;
3737 pSMB->hdr.smb_buf_length += name_len + 1;
3738 pSMB->ByteCount = cpu_to_le16(name_len + 1);
3739 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3740 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3741 if (rc) {
3742 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3743 }
3744
3745 cifs_buf_release(pSMB);
3746
3747 if (rc == -EAGAIN)
3748 goto SetAttrLgcyRetry;
3749
3750 return rc;
3751}
3752#endif /* temporarily unneeded SetAttr legacy function */
3753
3754int
3755CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003756 char *fileName, __u64 mode, __u64 uid, __u64 gid,
3757 dev_t device, const struct nls_table *nls_codepage,
3758 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759{
3760 TRANSACTION2_SPI_REQ *pSMB = NULL;
3761 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3762 int name_len;
3763 int rc = 0;
3764 int bytes_returned = 0;
3765 FILE_UNIX_BASIC_INFO *data_offset;
3766 __u16 params, param_offset, offset, count, byte_count;
3767
3768 cFYI(1, ("In SetUID/GID/Mode"));
3769setPermsRetry:
3770 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3771 (void **) &pSMBr);
3772 if (rc)
3773 return rc;
3774
3775 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3776 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003777 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003778 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 name_len++; /* trailing null */
3780 name_len *= 2;
3781 } else { /* BB improve the check for buffer overruns BB */
3782 name_len = strnlen(fileName, PATH_MAX);
3783 name_len++; /* trailing null */
3784 strncpy(pSMB->FileName, fileName, name_len);
3785 }
3786
3787 params = 6 + name_len;
3788 count = sizeof (FILE_UNIX_BASIC_INFO);
3789 pSMB->MaxParameterCount = cpu_to_le16(2);
3790 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3791 pSMB->MaxSetupCount = 0;
3792 pSMB->Reserved = 0;
3793 pSMB->Flags = 0;
3794 pSMB->Timeout = 0;
3795 pSMB->Reserved2 = 0;
3796 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3797 InformationLevel) - 4;
3798 offset = param_offset + params;
3799 data_offset =
3800 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3801 offset);
3802 memset(data_offset, 0, count);
3803 pSMB->DataOffset = cpu_to_le16(offset);
3804 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3805 pSMB->SetupCount = 1;
3806 pSMB->Reserved3 = 0;
3807 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3808 byte_count = 3 /* pad */ + params + count;
3809 pSMB->ParameterCount = cpu_to_le16(params);
3810 pSMB->DataCount = cpu_to_le16(count);
3811 pSMB->TotalParameterCount = pSMB->ParameterCount;
3812 pSMB->TotalDataCount = pSMB->DataCount;
3813 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3814 pSMB->Reserved4 = 0;
3815 pSMB->hdr.smb_buf_length += byte_count;
3816 data_offset->Uid = cpu_to_le64(uid);
3817 data_offset->Gid = cpu_to_le64(gid);
3818 /* better to leave device as zero when it is */
3819 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3820 data_offset->DevMinor = cpu_to_le64(MINOR(device));
3821 data_offset->Permissions = cpu_to_le64(mode);
3822
3823 if(S_ISREG(mode))
3824 data_offset->Type = cpu_to_le32(UNIX_FILE);
3825 else if(S_ISDIR(mode))
3826 data_offset->Type = cpu_to_le32(UNIX_DIR);
3827 else if(S_ISLNK(mode))
3828 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3829 else if(S_ISCHR(mode))
3830 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3831 else if(S_ISBLK(mode))
3832 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3833 else if(S_ISFIFO(mode))
3834 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3835 else if(S_ISSOCK(mode))
3836 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3837
3838
3839 pSMB->ByteCount = cpu_to_le16(byte_count);
3840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3842 if (rc) {
3843 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3844 }
3845
3846 if (pSMB)
3847 cifs_buf_release(pSMB);
3848 if (rc == -EAGAIN)
3849 goto setPermsRetry;
3850 return rc;
3851}
3852
3853int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
3854 const int notify_subdirs, const __u16 netfid,
3855 __u32 filter, const struct nls_table *nls_codepage)
3856{
3857 int rc = 0;
3858 struct smb_com_transaction_change_notify_req * pSMB = NULL;
3859 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3860 int bytes_returned;
3861
3862 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3863 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3864 (void **) &pSMBr);
3865 if (rc)
3866 return rc;
3867
3868 pSMB->TotalParameterCount = 0 ;
3869 pSMB->TotalDataCount = 0;
3870 pSMB->MaxParameterCount = cpu_to_le32(2);
3871 /* BB find exact data count max from sess structure BB */
3872 pSMB->MaxDataCount = 0; /* same in little endian or be */
3873 pSMB->MaxSetupCount = 4;
3874 pSMB->Reserved = 0;
3875 pSMB->ParameterOffset = 0;
3876 pSMB->DataCount = 0;
3877 pSMB->DataOffset = 0;
3878 pSMB->SetupCount = 4; /* single byte does not need le conversion */
3879 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3880 pSMB->ParameterCount = pSMB->TotalParameterCount;
3881 if(notify_subdirs)
3882 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3883 pSMB->Reserved2 = 0;
3884 pSMB->CompletionFilter = cpu_to_le32(filter);
3885 pSMB->Fid = netfid; /* file handle always le */
3886 pSMB->ByteCount = 0;
3887
3888 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3889 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3890 if (rc) {
3891 cFYI(1, ("Error in Notify = %d", rc));
3892 }
3893 cifs_buf_release(pSMB);
3894 return rc;
3895}
3896#ifdef CONFIG_CIFS_XATTR
3897ssize_t
3898CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3899 const unsigned char *searchName,
3900 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07003901 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902{
3903 /* BB assumes one setup word */
3904 TRANSACTION2_QPI_REQ *pSMB = NULL;
3905 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3906 int rc = 0;
3907 int bytes_returned;
3908 int name_len;
3909 struct fea * temp_fea;
3910 char * temp_ptr;
3911 __u16 params, byte_count;
3912
3913 cFYI(1, ("In Query All EAs path %s", searchName));
3914QAllEAsRetry:
3915 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3916 (void **) &pSMBr);
3917 if (rc)
3918 return rc;
3919
3920 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3921 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003922 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003923 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 name_len++; /* trailing null */
3925 name_len *= 2;
3926 } else { /* BB improve the check for buffer overruns BB */
3927 name_len = strnlen(searchName, PATH_MAX);
3928 name_len++; /* trailing null */
3929 strncpy(pSMB->FileName, searchName, name_len);
3930 }
3931
3932 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3933 pSMB->TotalDataCount = 0;
3934 pSMB->MaxParameterCount = cpu_to_le16(2);
3935 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3936 pSMB->MaxSetupCount = 0;
3937 pSMB->Reserved = 0;
3938 pSMB->Flags = 0;
3939 pSMB->Timeout = 0;
3940 pSMB->Reserved2 = 0;
3941 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3942 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3943 pSMB->DataCount = 0;
3944 pSMB->DataOffset = 0;
3945 pSMB->SetupCount = 1;
3946 pSMB->Reserved3 = 0;
3947 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3948 byte_count = params + 1 /* pad */ ;
3949 pSMB->TotalParameterCount = cpu_to_le16(params);
3950 pSMB->ParameterCount = pSMB->TotalParameterCount;
3951 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3952 pSMB->Reserved4 = 0;
3953 pSMB->hdr.smb_buf_length += byte_count;
3954 pSMB->ByteCount = cpu_to_le16(byte_count);
3955
3956 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3957 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3958 if (rc) {
3959 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3960 } else { /* decode response */
3961 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3962
3963 /* BB also check enough total bytes returned */
3964 /* BB we need to improve the validity checking
3965 of these trans2 responses */
3966 if (rc || (pSMBr->ByteCount < 4))
3967 rc = -EIO; /* bad smb */
3968 /* else if (pFindData){
3969 memcpy((char *) pFindData,
3970 (char *) &pSMBr->hdr.Protocol +
3971 data_offset, kl);
3972 }*/ else {
3973 /* check that length of list is not more than bcc */
3974 /* check that each entry does not go beyond length
3975 of list */
3976 /* check that each element of each entry does not
3977 go beyond end of list */
3978 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3979 struct fealist * ea_response_data;
3980 rc = 0;
3981 /* validate_trans2_offsets() */
3982 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
3983 ea_response_data = (struct fealist *)
3984 (((char *) &pSMBr->hdr.Protocol) +
3985 data_offset);
3986 name_len = le32_to_cpu(ea_response_data->list_len);
3987 cFYI(1,("ea length %d", name_len));
3988 if(name_len <= 8) {
3989 /* returned EA size zeroed at top of function */
3990 cFYI(1,("empty EA list returned from server"));
3991 } else {
3992 /* account for ea list len */
3993 name_len -= 4;
3994 temp_fea = ea_response_data->list;
3995 temp_ptr = (char *)temp_fea;
3996 while(name_len > 0) {
3997 __u16 value_len;
3998 name_len -= 4;
3999 temp_ptr += 4;
4000 rc += temp_fea->name_len;
4001 /* account for prefix user. and trailing null */
4002 rc = rc + 5 + 1;
4003 if(rc<(int)buf_size) {
4004 memcpy(EAData,"user.",5);
4005 EAData+=5;
4006 memcpy(EAData,temp_ptr,temp_fea->name_len);
4007 EAData+=temp_fea->name_len;
4008 /* null terminate name */
4009 *EAData = 0;
4010 EAData = EAData + 1;
4011 } else if(buf_size == 0) {
4012 /* skip copy - calc size only */
4013 } else {
4014 /* stop before overrun buffer */
4015 rc = -ERANGE;
4016 break;
4017 }
4018 name_len -= temp_fea->name_len;
4019 temp_ptr += temp_fea->name_len;
4020 /* account for trailing null */
4021 name_len--;
4022 temp_ptr++;
4023 value_len = le16_to_cpu(temp_fea->value_len);
4024 name_len -= value_len;
4025 temp_ptr += value_len;
4026 /* BB check that temp_ptr is still within smb BB*/
4027 /* no trailing null to account for in value len */
4028 /* go on to next EA */
4029 temp_fea = (struct fea *)temp_ptr;
4030 }
4031 }
4032 }
4033 }
4034 if (pSMB)
4035 cifs_buf_release(pSMB);
4036 if (rc == -EAGAIN)
4037 goto QAllEAsRetry;
4038
4039 return (ssize_t)rc;
4040}
4041
4042ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4043 const unsigned char * searchName,const unsigned char * ea_name,
4044 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004045 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046{
4047 TRANSACTION2_QPI_REQ *pSMB = NULL;
4048 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4049 int rc = 0;
4050 int bytes_returned;
4051 int name_len;
4052 struct fea * temp_fea;
4053 char * temp_ptr;
4054 __u16 params, byte_count;
4055
4056 cFYI(1, ("In Query EA path %s", searchName));
4057QEARetry:
4058 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4059 (void **) &pSMBr);
4060 if (rc)
4061 return rc;
4062
4063 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4064 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004065 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004066 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 name_len++; /* trailing null */
4068 name_len *= 2;
4069 } else { /* BB improve the check for buffer overruns BB */
4070 name_len = strnlen(searchName, PATH_MAX);
4071 name_len++; /* trailing null */
4072 strncpy(pSMB->FileName, searchName, name_len);
4073 }
4074
4075 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4076 pSMB->TotalDataCount = 0;
4077 pSMB->MaxParameterCount = cpu_to_le16(2);
4078 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4079 pSMB->MaxSetupCount = 0;
4080 pSMB->Reserved = 0;
4081 pSMB->Flags = 0;
4082 pSMB->Timeout = 0;
4083 pSMB->Reserved2 = 0;
4084 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4085 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4086 pSMB->DataCount = 0;
4087 pSMB->DataOffset = 0;
4088 pSMB->SetupCount = 1;
4089 pSMB->Reserved3 = 0;
4090 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4091 byte_count = params + 1 /* pad */ ;
4092 pSMB->TotalParameterCount = cpu_to_le16(params);
4093 pSMB->ParameterCount = pSMB->TotalParameterCount;
4094 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4095 pSMB->Reserved4 = 0;
4096 pSMB->hdr.smb_buf_length += byte_count;
4097 pSMB->ByteCount = cpu_to_le16(byte_count);
4098
4099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4101 if (rc) {
4102 cFYI(1, ("Send error in Query EA = %d", rc));
4103 } else { /* decode response */
4104 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4105
4106 /* BB also check enough total bytes returned */
4107 /* BB we need to improve the validity checking
4108 of these trans2 responses */
4109 if (rc || (pSMBr->ByteCount < 4))
4110 rc = -EIO; /* bad smb */
4111 /* else if (pFindData){
4112 memcpy((char *) pFindData,
4113 (char *) &pSMBr->hdr.Protocol +
4114 data_offset, kl);
4115 }*/ else {
4116 /* check that length of list is not more than bcc */
4117 /* check that each entry does not go beyond length
4118 of list */
4119 /* check that each element of each entry does not
4120 go beyond end of list */
4121 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4122 struct fealist * ea_response_data;
4123 rc = -ENODATA;
4124 /* validate_trans2_offsets() */
4125 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4126 ea_response_data = (struct fealist *)
4127 (((char *) &pSMBr->hdr.Protocol) +
4128 data_offset);
4129 name_len = le32_to_cpu(ea_response_data->list_len);
4130 cFYI(1,("ea length %d", name_len));
4131 if(name_len <= 8) {
4132 /* returned EA size zeroed at top of function */
4133 cFYI(1,("empty EA list returned from server"));
4134 } else {
4135 /* account for ea list len */
4136 name_len -= 4;
4137 temp_fea = ea_response_data->list;
4138 temp_ptr = (char *)temp_fea;
4139 /* loop through checking if we have a matching
4140 name and then return the associated value */
4141 while(name_len > 0) {
4142 __u16 value_len;
4143 name_len -= 4;
4144 temp_ptr += 4;
4145 value_len = le16_to_cpu(temp_fea->value_len);
4146 /* BB validate that value_len falls within SMB,
4147 even though maximum for name_len is 255 */
4148 if(memcmp(temp_fea->name,ea_name,
4149 temp_fea->name_len) == 0) {
4150 /* found a match */
4151 rc = value_len;
4152 /* account for prefix user. and trailing null */
4153 if(rc<=(int)buf_size) {
4154 memcpy(ea_value,
4155 temp_fea->name+temp_fea->name_len+1,
4156 rc);
4157 /* ea values, unlike ea names,
4158 are not null terminated */
4159 } else if(buf_size == 0) {
4160 /* skip copy - calc size only */
4161 } else {
4162 /* stop before overrun buffer */
4163 rc = -ERANGE;
4164 }
4165 break;
4166 }
4167 name_len -= temp_fea->name_len;
4168 temp_ptr += temp_fea->name_len;
4169 /* account for trailing null */
4170 name_len--;
4171 temp_ptr++;
4172 name_len -= value_len;
4173 temp_ptr += value_len;
4174 /* no trailing null to account for in value len */
4175 /* go on to next EA */
4176 temp_fea = (struct fea *)temp_ptr;
4177 }
4178 }
4179 }
4180 }
4181 if (pSMB)
4182 cifs_buf_release(pSMB);
4183 if (rc == -EAGAIN)
4184 goto QEARetry;
4185
4186 return (ssize_t)rc;
4187}
4188
4189int
4190CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4191 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004192 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4193 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194{
4195 struct smb_com_transaction2_spi_req *pSMB = NULL;
4196 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4197 struct fealist *parm_data;
4198 int name_len;
4199 int rc = 0;
4200 int bytes_returned = 0;
4201 __u16 params, param_offset, byte_count, offset, count;
4202
4203 cFYI(1, ("In SetEA"));
4204SetEARetry:
4205 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4206 (void **) &pSMBr);
4207 if (rc)
4208 return rc;
4209
4210 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4211 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004212 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004213 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 name_len++; /* trailing null */
4215 name_len *= 2;
4216 } else { /* BB improve the check for buffer overruns BB */
4217 name_len = strnlen(fileName, PATH_MAX);
4218 name_len++; /* trailing null */
4219 strncpy(pSMB->FileName, fileName, name_len);
4220 }
4221
4222 params = 6 + name_len;
4223
4224 /* done calculating parms using name_len of file name,
4225 now use name_len to calculate length of ea name
4226 we are going to create in the inode xattrs */
4227 if(ea_name == NULL)
4228 name_len = 0;
4229 else
4230 name_len = strnlen(ea_name,255);
4231
4232 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4233 pSMB->MaxParameterCount = cpu_to_le16(2);
4234 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4235 pSMB->MaxSetupCount = 0;
4236 pSMB->Reserved = 0;
4237 pSMB->Flags = 0;
4238 pSMB->Timeout = 0;
4239 pSMB->Reserved2 = 0;
4240 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4241 InformationLevel) - 4;
4242 offset = param_offset + params;
4243 pSMB->InformationLevel =
4244 cpu_to_le16(SMB_SET_FILE_EA);
4245
4246 parm_data =
4247 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4248 offset);
4249 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4250 pSMB->DataOffset = cpu_to_le16(offset);
4251 pSMB->SetupCount = 1;
4252 pSMB->Reserved3 = 0;
4253 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4254 byte_count = 3 /* pad */ + params + count;
4255 pSMB->DataCount = cpu_to_le16(count);
4256 parm_data->list_len = cpu_to_le32(count);
4257 parm_data->list[0].EA_flags = 0;
4258 /* we checked above that name len is less than 255 */
4259 parm_data->list[0].name_len = (__u8)name_len;;
4260 /* EA names are always ASCII */
4261 if(ea_name)
4262 strncpy(parm_data->list[0].name,ea_name,name_len);
4263 parm_data->list[0].name[name_len] = 0;
4264 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4265 /* caller ensures that ea_value_len is less than 64K but
4266 we need to ensure that it fits within the smb */
4267
4268 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4269 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4270 if(ea_value_len)
4271 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4272
4273 pSMB->TotalDataCount = pSMB->DataCount;
4274 pSMB->ParameterCount = cpu_to_le16(params);
4275 pSMB->TotalParameterCount = pSMB->ParameterCount;
4276 pSMB->Reserved4 = 0;
4277 pSMB->hdr.smb_buf_length += byte_count;
4278 pSMB->ByteCount = cpu_to_le16(byte_count);
4279 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4280 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4281 if (rc) {
4282 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4283 }
4284
4285 cifs_buf_release(pSMB);
4286
4287 if (rc == -EAGAIN)
4288 goto SetEARetry;
4289
4290 return rc;
4291}
4292
4293#endif