blob: b31158a2643dad476fef09a9a5e4d94a693487d2 [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
954int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
955 const int netfid, const unsigned int count,
956 const __u64 offset, unsigned int *nbytes, const char __user *buf,
957 const int long_op)
958{
959 int rc = -EACCES;
960 WRITE_REQ *pSMB = NULL;
961 WRITE_RSP *pSMBr = NULL;
962 /*int bytes_returned;*/
963 unsigned bytes_sent;
964 __u16 byte_count;
965
966 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
967
968 if (rc)
969 return rc;
970
971 pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
972
973 /* tcon and ses pointer are checked in smb_init */
974 if (tcon->ses->server == NULL)
975 return -ECONNABORTED;
976
977 pSMB->AndXCommand = 0xFF; /* none */
978 pSMB->Fid = netfid;
979 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
980 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
981 pSMB->Reserved = 0xFFFFFFFF;
982 pSMB->WriteMode = 0;
983 pSMB->Remaining = 0;
984 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
985 if (bytes_sent > count)
986 bytes_sent = count;
987 pSMB->DataLengthHigh = 0;
988 pSMB->DataOffset =
989 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
990
991 byte_count = bytes_sent + 1 /* pad */ ;
992 pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
993 pSMB->DataLengthHigh = 0;
994 pSMB->hdr.smb_buf_length += byte_count;
995 pSMB->ByteCount = cpu_to_le16(byte_count);
996
997/* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */
999 if (rc) {
1000 cFYI(1, ("Send error in write2 (large write) = %d", rc));
1001 *nbytes = 0;
1002 } else
1003 *nbytes = le16_to_cpu(pSMBr->Count);
1004
1005 cifs_small_buf_release(pSMB);
1006
1007 /* Note: On -EAGAIN error only caller can retry on handle based calls
1008 since file handle passed in no longer valid */
1009
1010 return rc;
1011}
1012#endif /* CIFS_EXPERIMENTAL */
1013
1014int
1015CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1016 const __u16 smb_file_id, const __u64 len,
1017 const __u64 offset, const __u32 numUnlock,
1018 const __u32 numLock, const __u8 lockType, const int waitFlag)
1019{
1020 int rc = 0;
1021 LOCK_REQ *pSMB = NULL;
1022 LOCK_RSP *pSMBr = NULL;
1023 int bytes_returned;
1024 int timeout = 0;
1025 __u16 count;
1026
1027 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001028 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1029
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if (rc)
1031 return rc;
1032
Steve French46810cb2005-04-28 22:41:09 -07001033 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1036 timeout = -1; /* no response expected */
1037 pSMB->Timeout = 0;
1038 } else if (waitFlag == TRUE) {
1039 timeout = 3; /* blocking operation, no timeout */
1040 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1041 } else {
1042 pSMB->Timeout = 0;
1043 }
1044
1045 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1046 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1047 pSMB->LockType = lockType;
1048 pSMB->AndXCommand = 0xFF; /* none */
1049 pSMB->Fid = smb_file_id; /* netfid stays le */
1050
1051 if((numLock != 0) || (numUnlock != 0)) {
1052 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1053 /* BB where to store pid high? */
1054 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1055 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1056 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1057 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1058 count = sizeof(LOCKING_ANDX_RANGE);
1059 } else {
1060 /* oplock break */
1061 count = 0;
1062 }
1063 pSMB->hdr.smb_buf_length += count;
1064 pSMB->ByteCount = cpu_to_le16(count);
1065
1066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1067 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1068
1069 if (rc) {
1070 cFYI(1, ("Send error in Lock = %d", rc));
1071 }
Steve French46810cb2005-04-28 22:41:09 -07001072 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
1074 /* Note: On -EAGAIN error only caller can retry on handle based calls
1075 since file handle passed in no longer valid */
1076 return rc;
1077}
1078
1079int
1080CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1081{
1082 int rc = 0;
1083 CLOSE_REQ *pSMB = NULL;
1084 CLOSE_RSP *pSMBr = NULL;
1085 int bytes_returned;
1086 cFYI(1, ("In CIFSSMBClose"));
1087
1088/* do not retry on dead session on close */
1089 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1090 if(rc == -EAGAIN)
1091 return 0;
1092 if (rc)
1093 return rc;
1094
1095 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1096
1097 pSMB->FileID = (__u16) smb_file_id;
1098 pSMB->LastWriteTime = 0;
1099 pSMB->ByteCount = 0;
1100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1102 if (rc) {
1103 if(rc!=-EINTR) {
1104 /* EINTR is expected when user ctl-c to kill app */
1105 cERROR(1, ("Send error in Close = %d", rc));
1106 }
1107 }
1108
1109 cifs_small_buf_release(pSMB);
1110
1111 /* Since session is dead, file will be closed on server already */
1112 if(rc == -EAGAIN)
1113 rc = 0;
1114
1115 return rc;
1116}
1117
1118int
1119CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1120 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001121 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
1123 int rc = 0;
1124 RENAME_REQ *pSMB = NULL;
1125 RENAME_RSP *pSMBr = NULL;
1126 int bytes_returned;
1127 int name_len, name_len2;
1128 __u16 count;
1129
1130 cFYI(1, ("In CIFSSMBRename"));
1131renameRetry:
1132 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1133 (void **) &pSMBr);
1134 if (rc)
1135 return rc;
1136
1137 pSMB->BufferFormat = 0x04;
1138 pSMB->SearchAttributes =
1139 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1140 ATTR_DIRECTORY);
1141
1142 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1143 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001144 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001145 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 name_len++; /* trailing null */
1147 name_len *= 2;
1148 pSMB->OldFileName[name_len] = 0x04; /* pad */
1149 /* protocol requires ASCII signature byte on Unicode string */
1150 pSMB->OldFileName[name_len + 1] = 0x00;
1151 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001152 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001153 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1155 name_len2 *= 2; /* convert to bytes */
1156 } else { /* BB improve the check for buffer overruns BB */
1157 name_len = strnlen(fromName, PATH_MAX);
1158 name_len++; /* trailing null */
1159 strncpy(pSMB->OldFileName, fromName, name_len);
1160 name_len2 = strnlen(toName, PATH_MAX);
1161 name_len2++; /* trailing null */
1162 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1163 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1164 name_len2++; /* trailing null */
1165 name_len2++; /* signature byte */
1166 }
1167
1168 count = 1 /* 1st signature byte */ + name_len + name_len2;
1169 pSMB->hdr.smb_buf_length += count;
1170 pSMB->ByteCount = cpu_to_le16(count);
1171
1172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1174 if (rc) {
1175 cFYI(1, ("Send error in rename = %d", rc));
1176 }
1177
1178#ifdef CONFIG_CIFS_STATS
1179 else {
1180 atomic_inc(&tcon->num_renames);
1181 }
1182#endif
1183
1184 cifs_buf_release(pSMB);
1185
1186 if (rc == -EAGAIN)
1187 goto renameRetry;
1188
1189 return rc;
1190}
1191
1192int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001193 int netfid, char * target_name,
1194 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
1196 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1197 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1198 struct set_file_rename * rename_info;
1199 char *data_offset;
1200 char dummy_string[30];
1201 int rc = 0;
1202 int bytes_returned = 0;
1203 int len_of_str;
1204 __u16 params, param_offset, offset, count, byte_count;
1205
1206 cFYI(1, ("Rename to File by handle"));
1207 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1208 (void **) &pSMBr);
1209 if (rc)
1210 return rc;
1211
1212 params = 6;
1213 pSMB->MaxSetupCount = 0;
1214 pSMB->Reserved = 0;
1215 pSMB->Flags = 0;
1216 pSMB->Timeout = 0;
1217 pSMB->Reserved2 = 0;
1218 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1219 offset = param_offset + params;
1220
1221 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1222 rename_info = (struct set_file_rename *) data_offset;
1223 pSMB->MaxParameterCount = cpu_to_le16(2);
1224 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1225 pSMB->SetupCount = 1;
1226 pSMB->Reserved3 = 0;
1227 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1228 byte_count = 3 /* pad */ + params;
1229 pSMB->ParameterCount = cpu_to_le16(params);
1230 pSMB->TotalParameterCount = pSMB->ParameterCount;
1231 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1232 pSMB->DataOffset = cpu_to_le16(offset);
1233 /* construct random name ".cifs_tmp<inodenum><mid>" */
1234 rename_info->overwrite = cpu_to_le32(1);
1235 rename_info->root_fid = 0;
1236 /* unicode only call */
1237 if(target_name == NULL) {
1238 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001239 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001240 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001242 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001243 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
1245 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1246 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1247 byte_count += count;
1248 pSMB->DataCount = cpu_to_le16(count);
1249 pSMB->TotalDataCount = pSMB->DataCount;
1250 pSMB->Fid = netfid;
1251 pSMB->InformationLevel =
1252 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1253 pSMB->Reserved4 = 0;
1254 pSMB->hdr.smb_buf_length += byte_count;
1255 pSMB->ByteCount = cpu_to_le16(byte_count);
1256 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1258 if (rc) {
1259 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1260 }
1261#ifdef CONFIG_CIFS_STATS
1262 else {
1263 atomic_inc(&pTcon->num_t2renames);
1264 }
1265#endif
1266 cifs_buf_release(pSMB);
1267
1268 /* Note: On -EAGAIN error only caller can retry on handle based calls
1269 since file handle passed in no longer valid */
1270
1271 return rc;
1272}
1273
1274int
1275CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1276 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001277 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
1279 int rc = 0;
1280 COPY_REQ *pSMB = NULL;
1281 COPY_RSP *pSMBr = NULL;
1282 int bytes_returned;
1283 int name_len, name_len2;
1284 __u16 count;
1285
1286 cFYI(1, ("In CIFSSMBCopy"));
1287copyRetry:
1288 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1289 (void **) &pSMBr);
1290 if (rc)
1291 return rc;
1292
1293 pSMB->BufferFormat = 0x04;
1294 pSMB->Tid2 = target_tid;
1295
1296 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1297
1298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001299 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001300 fromName, PATH_MAX, nls_codepage,
1301 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 name_len++; /* trailing null */
1303 name_len *= 2;
1304 pSMB->OldFileName[name_len] = 0x04; /* pad */
1305 /* protocol requires ASCII signature byte on Unicode string */
1306 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001307 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001308 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1310 name_len2 *= 2; /* convert to bytes */
1311 } else { /* BB improve the check for buffer overruns BB */
1312 name_len = strnlen(fromName, PATH_MAX);
1313 name_len++; /* trailing null */
1314 strncpy(pSMB->OldFileName, fromName, name_len);
1315 name_len2 = strnlen(toName, PATH_MAX);
1316 name_len2++; /* trailing null */
1317 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1318 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1319 name_len2++; /* trailing null */
1320 name_len2++; /* signature byte */
1321 }
1322
1323 count = 1 /* 1st signature byte */ + name_len + name_len2;
1324 pSMB->hdr.smb_buf_length += count;
1325 pSMB->ByteCount = cpu_to_le16(count);
1326
1327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1329 if (rc) {
1330 cFYI(1, ("Send error in copy = %d with %d files copied",
1331 rc, le16_to_cpu(pSMBr->CopyCount)));
1332 }
1333 if (pSMB)
1334 cifs_buf_release(pSMB);
1335
1336 if (rc == -EAGAIN)
1337 goto copyRetry;
1338
1339 return rc;
1340}
1341
1342int
1343CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1344 const char *fromName, const char *toName,
1345 const struct nls_table *nls_codepage)
1346{
1347 TRANSACTION2_SPI_REQ *pSMB = NULL;
1348 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1349 char *data_offset;
1350 int name_len;
1351 int name_len_target;
1352 int rc = 0;
1353 int bytes_returned = 0;
1354 __u16 params, param_offset, offset, byte_count;
1355
1356 cFYI(1, ("In Symlink Unix style"));
1357createSymLinkRetry:
1358 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1359 (void **) &pSMBr);
1360 if (rc)
1361 return rc;
1362
1363 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1364 name_len =
1365 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1366 /* find define for this maxpathcomponent */
1367 , nls_codepage);
1368 name_len++; /* trailing null */
1369 name_len *= 2;
1370
1371 } else { /* BB improve the check for buffer overruns BB */
1372 name_len = strnlen(fromName, PATH_MAX);
1373 name_len++; /* trailing null */
1374 strncpy(pSMB->FileName, fromName, name_len);
1375 }
1376 params = 6 + name_len;
1377 pSMB->MaxSetupCount = 0;
1378 pSMB->Reserved = 0;
1379 pSMB->Flags = 0;
1380 pSMB->Timeout = 0;
1381 pSMB->Reserved2 = 0;
1382 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1383 InformationLevel) - 4;
1384 offset = param_offset + params;
1385
1386 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1387 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1388 name_len_target =
1389 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1390 /* find define for this maxpathcomponent */
1391 , nls_codepage);
1392 name_len_target++; /* trailing null */
1393 name_len_target *= 2;
1394 } else { /* BB improve the check for buffer overruns BB */
1395 name_len_target = strnlen(toName, PATH_MAX);
1396 name_len_target++; /* trailing null */
1397 strncpy(data_offset, toName, name_len_target);
1398 }
1399
1400 pSMB->MaxParameterCount = cpu_to_le16(2);
1401 /* BB find exact max on data count below from sess */
1402 pSMB->MaxDataCount = cpu_to_le16(1000);
1403 pSMB->SetupCount = 1;
1404 pSMB->Reserved3 = 0;
1405 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1406 byte_count = 3 /* pad */ + params + name_len_target;
1407 pSMB->DataCount = cpu_to_le16(name_len_target);
1408 pSMB->ParameterCount = cpu_to_le16(params);
1409 pSMB->TotalDataCount = pSMB->DataCount;
1410 pSMB->TotalParameterCount = pSMB->ParameterCount;
1411 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1412 pSMB->DataOffset = cpu_to_le16(offset);
1413 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1414 pSMB->Reserved4 = 0;
1415 pSMB->hdr.smb_buf_length += byte_count;
1416 pSMB->ByteCount = cpu_to_le16(byte_count);
1417 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1418 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1419 if (rc) {
1420 cFYI(1,
1421 ("Send error in SetPathInfo (create symlink) = %d",
1422 rc));
1423 }
1424
1425 if (pSMB)
1426 cifs_buf_release(pSMB);
1427
1428 if (rc == -EAGAIN)
1429 goto createSymLinkRetry;
1430
1431 return rc;
1432}
1433
1434int
1435CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1436 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001437 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438{
1439 TRANSACTION2_SPI_REQ *pSMB = NULL;
1440 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1441 char *data_offset;
1442 int name_len;
1443 int name_len_target;
1444 int rc = 0;
1445 int bytes_returned = 0;
1446 __u16 params, param_offset, offset, byte_count;
1447
1448 cFYI(1, ("In Create Hard link Unix style"));
1449createHardLinkRetry:
1450 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1451 (void **) &pSMBr);
1452 if (rc)
1453 return rc;
1454
1455 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001456 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001457 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 name_len++; /* trailing null */
1459 name_len *= 2;
1460
1461 } else { /* BB improve the check for buffer overruns BB */
1462 name_len = strnlen(toName, PATH_MAX);
1463 name_len++; /* trailing null */
1464 strncpy(pSMB->FileName, toName, name_len);
1465 }
1466 params = 6 + name_len;
1467 pSMB->MaxSetupCount = 0;
1468 pSMB->Reserved = 0;
1469 pSMB->Flags = 0;
1470 pSMB->Timeout = 0;
1471 pSMB->Reserved2 = 0;
1472 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1473 InformationLevel) - 4;
1474 offset = param_offset + params;
1475
1476 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1477 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1478 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001479 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001480 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 name_len_target++; /* trailing null */
1482 name_len_target *= 2;
1483 } else { /* BB improve the check for buffer overruns BB */
1484 name_len_target = strnlen(fromName, PATH_MAX);
1485 name_len_target++; /* trailing null */
1486 strncpy(data_offset, fromName, name_len_target);
1487 }
1488
1489 pSMB->MaxParameterCount = cpu_to_le16(2);
1490 /* BB find exact max on data count below from sess*/
1491 pSMB->MaxDataCount = cpu_to_le16(1000);
1492 pSMB->SetupCount = 1;
1493 pSMB->Reserved3 = 0;
1494 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1495 byte_count = 3 /* pad */ + params + name_len_target;
1496 pSMB->ParameterCount = cpu_to_le16(params);
1497 pSMB->TotalParameterCount = pSMB->ParameterCount;
1498 pSMB->DataCount = cpu_to_le16(name_len_target);
1499 pSMB->TotalDataCount = pSMB->DataCount;
1500 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1501 pSMB->DataOffset = cpu_to_le16(offset);
1502 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1503 pSMB->Reserved4 = 0;
1504 pSMB->hdr.smb_buf_length += byte_count;
1505 pSMB->ByteCount = cpu_to_le16(byte_count);
1506 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1507 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1508 if (rc) {
1509 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1510 }
1511
1512 cifs_buf_release(pSMB);
1513 if (rc == -EAGAIN)
1514 goto createHardLinkRetry;
1515
1516 return rc;
1517}
1518
1519int
1520CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1521 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001522 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523{
1524 int rc = 0;
1525 NT_RENAME_REQ *pSMB = NULL;
1526 RENAME_RSP *pSMBr = NULL;
1527 int bytes_returned;
1528 int name_len, name_len2;
1529 __u16 count;
1530
1531 cFYI(1, ("In CIFSCreateHardLink"));
1532winCreateHardLinkRetry:
1533
1534 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1535 (void **) &pSMBr);
1536 if (rc)
1537 return rc;
1538
1539 pSMB->SearchAttributes =
1540 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1541 ATTR_DIRECTORY);
1542 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1543 pSMB->ClusterCount = 0;
1544
1545 pSMB->BufferFormat = 0x04;
1546
1547 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1548 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001549 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001550 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 name_len++; /* trailing null */
1552 name_len *= 2;
1553 pSMB->OldFileName[name_len] = 0; /* pad */
1554 pSMB->OldFileName[name_len + 1] = 0x04;
1555 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001556 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001557 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1559 name_len2 *= 2; /* convert to bytes */
1560 } else { /* BB improve the check for buffer overruns BB */
1561 name_len = strnlen(fromName, PATH_MAX);
1562 name_len++; /* trailing null */
1563 strncpy(pSMB->OldFileName, fromName, name_len);
1564 name_len2 = strnlen(toName, PATH_MAX);
1565 name_len2++; /* trailing null */
1566 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1567 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1568 name_len2++; /* trailing null */
1569 name_len2++; /* signature byte */
1570 }
1571
1572 count = 1 /* string type byte */ + name_len + name_len2;
1573 pSMB->hdr.smb_buf_length += count;
1574 pSMB->ByteCount = cpu_to_le16(count);
1575
1576 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1577 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1578 if (rc) {
1579 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1580 }
1581 cifs_buf_release(pSMB);
1582 if (rc == -EAGAIN)
1583 goto winCreateHardLinkRetry;
1584
1585 return rc;
1586}
1587
1588int
1589CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1590 const unsigned char *searchName,
1591 char *symlinkinfo, const int buflen,
1592 const struct nls_table *nls_codepage)
1593{
1594/* SMB_QUERY_FILE_UNIX_LINK */
1595 TRANSACTION2_QPI_REQ *pSMB = NULL;
1596 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1597 int rc = 0;
1598 int bytes_returned;
1599 int name_len;
1600 __u16 params, byte_count;
1601
1602 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1603
1604querySymLinkRetry:
1605 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1606 (void **) &pSMBr);
1607 if (rc)
1608 return rc;
1609
1610 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1611 name_len =
1612 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1613 /* find define for this maxpathcomponent */
1614 , nls_codepage);
1615 name_len++; /* trailing null */
1616 name_len *= 2;
1617 } else { /* BB improve the check for buffer overruns BB */
1618 name_len = strnlen(searchName, PATH_MAX);
1619 name_len++; /* trailing null */
1620 strncpy(pSMB->FileName, searchName, name_len);
1621 }
1622
1623 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1624 pSMB->TotalDataCount = 0;
1625 pSMB->MaxParameterCount = cpu_to_le16(2);
1626 /* BB find exact max data count below from sess structure BB */
1627 pSMB->MaxDataCount = cpu_to_le16(4000);
1628 pSMB->MaxSetupCount = 0;
1629 pSMB->Reserved = 0;
1630 pSMB->Flags = 0;
1631 pSMB->Timeout = 0;
1632 pSMB->Reserved2 = 0;
1633 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1634 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1635 pSMB->DataCount = 0;
1636 pSMB->DataOffset = 0;
1637 pSMB->SetupCount = 1;
1638 pSMB->Reserved3 = 0;
1639 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1640 byte_count = params + 1 /* pad */ ;
1641 pSMB->TotalParameterCount = cpu_to_le16(params);
1642 pSMB->ParameterCount = pSMB->TotalParameterCount;
1643 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1644 pSMB->Reserved4 = 0;
1645 pSMB->hdr.smb_buf_length += byte_count;
1646 pSMB->ByteCount = cpu_to_le16(byte_count);
1647
1648 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1649 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1650 if (rc) {
1651 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1652 } else {
1653 /* decode response */
1654
1655 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1656 if (rc || (pSMBr->ByteCount < 2))
1657 /* BB also check enough total bytes returned */
1658 rc = -EIO; /* bad smb */
1659 else {
1660 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1661 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1662
1663 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1664 name_len = UniStrnlen((wchar_t *) ((char *)
1665 &pSMBr->hdr.Protocol +data_offset),
1666 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001667 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 cifs_strfromUCS_le(symlinkinfo,
1669 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1670 data_offset),
1671 name_len, nls_codepage);
1672 } else {
1673 strncpy(symlinkinfo,
1674 (char *) &pSMBr->hdr.Protocol +
1675 data_offset,
1676 min_t(const int, buflen, count));
1677 }
1678 symlinkinfo[buflen] = 0;
1679 /* just in case so calling code does not go off the end of buffer */
1680 }
1681 }
1682 cifs_buf_release(pSMB);
1683 if (rc == -EAGAIN)
1684 goto querySymLinkRetry;
1685 return rc;
1686}
1687
1688int
1689CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1690 const unsigned char *searchName,
1691 char *symlinkinfo, const int buflen,__u16 fid,
1692 const struct nls_table *nls_codepage)
1693{
1694 int rc = 0;
1695 int bytes_returned;
1696 int name_len;
1697 struct smb_com_transaction_ioctl_req * pSMB;
1698 struct smb_com_transaction_ioctl_rsp * pSMBr;
1699
1700 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1701 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1702 (void **) &pSMBr);
1703 if (rc)
1704 return rc;
1705
1706 pSMB->TotalParameterCount = 0 ;
1707 pSMB->TotalDataCount = 0;
1708 pSMB->MaxParameterCount = cpu_to_le32(2);
1709 /* BB find exact data count max from sess structure BB */
1710 pSMB->MaxDataCount = cpu_to_le32(4000);
1711 pSMB->MaxSetupCount = 4;
1712 pSMB->Reserved = 0;
1713 pSMB->ParameterOffset = 0;
1714 pSMB->DataCount = 0;
1715 pSMB->DataOffset = 0;
1716 pSMB->SetupCount = 4;
1717 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1718 pSMB->ParameterCount = pSMB->TotalParameterCount;
1719 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1720 pSMB->IsFsctl = 1; /* FSCTL */
1721 pSMB->IsRootFlag = 0;
1722 pSMB->Fid = fid; /* file handle always le */
1723 pSMB->ByteCount = 0;
1724
1725 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1726 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1727 if (rc) {
1728 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1729 } else { /* decode response */
1730 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1731 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1732 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1733 /* BB also check enough total bytes returned */
1734 rc = -EIO; /* bad smb */
1735 else {
1736 if(data_count && (data_count < 2048)) {
1737 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1738
1739 struct reparse_data * reparse_buf = (struct reparse_data *)
1740 ((char *)&pSMBr->hdr.Protocol + data_offset);
1741 if((char*)reparse_buf >= end_of_smb) {
1742 rc = -EIO;
1743 goto qreparse_out;
1744 }
1745 if((reparse_buf->LinkNamesBuf +
1746 reparse_buf->TargetNameOffset +
1747 reparse_buf->TargetNameLen) >
1748 end_of_smb) {
1749 cFYI(1,("reparse buf extended beyond SMB"));
1750 rc = -EIO;
1751 goto qreparse_out;
1752 }
1753
1754 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1755 name_len = UniStrnlen((wchar_t *)
1756 (reparse_buf->LinkNamesBuf +
1757 reparse_buf->TargetNameOffset),
1758 min(buflen/2, reparse_buf->TargetNameLen / 2));
1759 cifs_strfromUCS_le(symlinkinfo,
1760 (wchar_t *) (reparse_buf->LinkNamesBuf +
1761 reparse_buf->TargetNameOffset),
1762 name_len, nls_codepage);
1763 } else { /* ASCII names */
1764 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1765 reparse_buf->TargetNameOffset,
1766 min_t(const int, buflen, reparse_buf->TargetNameLen));
1767 }
1768 } else {
1769 rc = -EIO;
1770 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1771 }
1772 symlinkinfo[buflen] = 0; /* just in case so the caller
1773 does not go off the end of the buffer */
1774 cFYI(1,("readlink result - %s ",symlinkinfo));
1775 }
1776 }
1777qreparse_out:
1778 if (pSMB)
1779 cifs_buf_release(pSMB);
1780
1781 /* Note: On -EAGAIN error only caller can retry on handle based calls
1782 since file handle passed in no longer valid */
1783
1784 return rc;
1785}
1786
1787#ifdef CONFIG_CIFS_POSIX
1788
1789/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1790static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1791{
1792 /* u8 cifs fields do not need le conversion */
1793 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1794 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1795 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1796 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1797
1798 return;
1799}
1800
1801/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07001802static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1803 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804{
1805 int size = 0;
1806 int i;
1807 __u16 count;
1808 struct cifs_posix_ace * pACE;
1809 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1810 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1811
1812 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1813 return -EOPNOTSUPP;
1814
1815 if(acl_type & ACL_TYPE_ACCESS) {
1816 count = le16_to_cpu(cifs_acl->access_entry_count);
1817 pACE = &cifs_acl->ace_array[0];
1818 size = sizeof(struct cifs_posix_acl);
1819 size += sizeof(struct cifs_posix_ace) * count;
1820 /* check if we would go beyond end of SMB */
1821 if(size_of_data_area < size) {
1822 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1823 return -EINVAL;
1824 }
1825 } else if(acl_type & ACL_TYPE_DEFAULT) {
1826 count = le16_to_cpu(cifs_acl->access_entry_count);
1827 size = sizeof(struct cifs_posix_acl);
1828 size += sizeof(struct cifs_posix_ace) * count;
1829/* skip past access ACEs to get to default ACEs */
1830 pACE = &cifs_acl->ace_array[count];
1831 count = le16_to_cpu(cifs_acl->default_entry_count);
1832 size += sizeof(struct cifs_posix_ace) * count;
1833 /* check if we would go beyond end of SMB */
1834 if(size_of_data_area < size)
1835 return -EINVAL;
1836 } else {
1837 /* illegal type */
1838 return -EINVAL;
1839 }
1840
1841 size = posix_acl_xattr_size(count);
1842 if((buflen == 0) || (local_acl == NULL)) {
1843 /* used to query ACL EA size */
1844 } else if(size > buflen) {
1845 return -ERANGE;
1846 } else /* buffer big enough */ {
1847 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1848 for(i = 0;i < count ;i++) {
1849 cifs_convert_ace(&local_acl->a_entries[i],pACE);
1850 pACE ++;
1851 }
1852 }
1853 return size;
1854}
1855
1856static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1857 const posix_acl_xattr_entry * local_ace)
1858{
1859 __u16 rc = 0; /* 0 = ACL converted ok */
1860
1861 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1862 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
1863 /* BB is there a better way to handle the large uid? */
1864 if(local_ace->e_id == -1) {
1865 /* Probably no need to le convert -1 on any arch but can not hurt */
1866 cifs_ace->cifs_uid = cpu_to_le64(-1);
1867 } else
1868 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1869 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1870 return rc;
1871}
1872
1873/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1874static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1875 const int acl_type)
1876{
1877 __u16 rc = 0;
1878 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1879 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1880 int count;
1881 int i;
1882
1883 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1884 return 0;
1885
1886 count = posix_acl_xattr_count((size_t)buflen);
1887 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1888 count,buflen,local_acl->a_version));
1889 if(local_acl->a_version != 2) {
1890 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1891 return 0;
1892 }
1893 cifs_acl->version = cpu_to_le16(1);
1894 if(acl_type == ACL_TYPE_ACCESS)
1895 cifs_acl->access_entry_count = count;
1896 else if(acl_type == ACL_TYPE_DEFAULT)
1897 cifs_acl->default_entry_count = count;
1898 else {
1899 cFYI(1,("unknown ACL type %d",acl_type));
1900 return 0;
1901 }
1902 for(i=0;i<count;i++) {
1903 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1904 &local_acl->a_entries[i]);
1905 if(rc != 0) {
1906 /* ACE not converted */
1907 break;
1908 }
1909 }
1910 if(rc == 0) {
1911 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1912 rc += sizeof(struct cifs_posix_acl);
1913 /* BB add check to make sure ACL does not overflow SMB */
1914 }
1915 return rc;
1916}
1917
1918int
1919CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1920 const unsigned char *searchName,
1921 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07001922 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923{
1924/* SMB_QUERY_POSIX_ACL */
1925 TRANSACTION2_QPI_REQ *pSMB = NULL;
1926 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1927 int rc = 0;
1928 int bytes_returned;
1929 int name_len;
1930 __u16 params, byte_count;
1931
1932 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1933
1934queryAclRetry:
1935 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1936 (void **) &pSMBr);
1937 if (rc)
1938 return rc;
1939
1940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1941 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001942 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07001943 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 name_len++; /* trailing null */
1945 name_len *= 2;
1946 pSMB->FileName[name_len] = 0;
1947 pSMB->FileName[name_len+1] = 0;
1948 } else { /* BB improve the check for buffer overruns BB */
1949 name_len = strnlen(searchName, PATH_MAX);
1950 name_len++; /* trailing null */
1951 strncpy(pSMB->FileName, searchName, name_len);
1952 }
1953
1954 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1955 pSMB->TotalDataCount = 0;
1956 pSMB->MaxParameterCount = cpu_to_le16(2);
1957 /* BB find exact max data count below from sess structure BB */
1958 pSMB->MaxDataCount = cpu_to_le16(4000);
1959 pSMB->MaxSetupCount = 0;
1960 pSMB->Reserved = 0;
1961 pSMB->Flags = 0;
1962 pSMB->Timeout = 0;
1963 pSMB->Reserved2 = 0;
1964 pSMB->ParameterOffset = cpu_to_le16(
1965 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1966 pSMB->DataCount = 0;
1967 pSMB->DataOffset = 0;
1968 pSMB->SetupCount = 1;
1969 pSMB->Reserved3 = 0;
1970 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1971 byte_count = params + 1 /* pad */ ;
1972 pSMB->TotalParameterCount = cpu_to_le16(params);
1973 pSMB->ParameterCount = pSMB->TotalParameterCount;
1974 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1975 pSMB->Reserved4 = 0;
1976 pSMB->hdr.smb_buf_length += byte_count;
1977 pSMB->ByteCount = cpu_to_le16(byte_count);
1978
1979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1981 if (rc) {
1982 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
1983 } else {
1984 /* decode response */
1985
1986 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1987 if (rc || (pSMBr->ByteCount < 2))
1988 /* BB also check enough total bytes returned */
1989 rc = -EIO; /* bad smb */
1990 else {
1991 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1992 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1993 rc = cifs_copy_posix_acl(acl_inf,
1994 (char *)&pSMBr->hdr.Protocol+data_offset,
1995 buflen,acl_type,count);
1996 }
1997 }
1998 cifs_buf_release(pSMB);
1999 if (rc == -EAGAIN)
2000 goto queryAclRetry;
2001 return rc;
2002}
2003
2004int
2005CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2006 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002007 const char *local_acl, const int buflen,
2008 const int acl_type,
2009 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010{
2011 struct smb_com_transaction2_spi_req *pSMB = NULL;
2012 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2013 char *parm_data;
2014 int name_len;
2015 int rc = 0;
2016 int bytes_returned = 0;
2017 __u16 params, byte_count, data_count, param_offset, offset;
2018
2019 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2020setAclRetry:
2021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2022 (void **) &pSMBr);
2023 if (rc)
2024 return rc;
2025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2026 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002027 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002028 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 name_len++; /* trailing null */
2030 name_len *= 2;
2031 } else { /* BB improve the check for buffer overruns BB */
2032 name_len = strnlen(fileName, PATH_MAX);
2033 name_len++; /* trailing null */
2034 strncpy(pSMB->FileName, fileName, name_len);
2035 }
2036 params = 6 + name_len;
2037 pSMB->MaxParameterCount = cpu_to_le16(2);
2038 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2039 pSMB->MaxSetupCount = 0;
2040 pSMB->Reserved = 0;
2041 pSMB->Flags = 0;
2042 pSMB->Timeout = 0;
2043 pSMB->Reserved2 = 0;
2044 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2045 InformationLevel) - 4;
2046 offset = param_offset + params;
2047 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2048 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2049
2050 /* convert to on the wire format for POSIX ACL */
2051 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2052
2053 if(data_count == 0) {
2054 rc = -EOPNOTSUPP;
2055 goto setACLerrorExit;
2056 }
2057 pSMB->DataOffset = cpu_to_le16(offset);
2058 pSMB->SetupCount = 1;
2059 pSMB->Reserved3 = 0;
2060 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2061 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2062 byte_count = 3 /* pad */ + params + data_count;
2063 pSMB->DataCount = cpu_to_le16(data_count);
2064 pSMB->TotalDataCount = pSMB->DataCount;
2065 pSMB->ParameterCount = cpu_to_le16(params);
2066 pSMB->TotalParameterCount = pSMB->ParameterCount;
2067 pSMB->Reserved4 = 0;
2068 pSMB->hdr.smb_buf_length += byte_count;
2069 pSMB->ByteCount = cpu_to_le16(byte_count);
2070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2072 if (rc) {
2073 cFYI(1, ("Set POSIX ACL returned %d", rc));
2074 }
2075
2076setACLerrorExit:
2077 cifs_buf_release(pSMB);
2078 if (rc == -EAGAIN)
2079 goto setAclRetry;
2080 return rc;
2081}
2082
Steve Frenchf654bac2005-04-28 22:41:04 -07002083/* BB fix tabs in this function FIXME BB */
2084int
2085CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2086 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2087{
2088 int rc = 0;
2089 struct smb_t2_qfi_req *pSMB = NULL;
2090 struct smb_t2_qfi_rsp *pSMBr = NULL;
2091 int bytes_returned;
2092 __u16 params, byte_count;
2093
2094 cFYI(1,("In GetExtAttr"));
2095 if(tcon == NULL)
2096 return -ENODEV;
2097
2098GetExtAttrRetry:
2099 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2100 (void **) &pSMBr);
2101 if (rc)
2102 return rc;
2103
Steve Frenchc67593a2005-04-28 22:41:04 -07002104 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002105 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002106 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002107 /* BB find exact max data count below from sess structure BB */
2108 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2109 pSMB->t2.MaxSetupCount = 0;
2110 pSMB->t2.Reserved = 0;
2111 pSMB->t2.Flags = 0;
2112 pSMB->t2.Timeout = 0;
2113 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002114 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2115 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002116 pSMB->t2.DataCount = 0;
2117 pSMB->t2.DataOffset = 0;
2118 pSMB->t2.SetupCount = 1;
2119 pSMB->t2.Reserved3 = 0;
2120 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002121 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002122 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2123 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2124 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002125 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002126 pSMB->Fid = netfid;
2127 pSMB->hdr.smb_buf_length += byte_count;
2128 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2129
2130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2131 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2132 if (rc) {
2133 cFYI(1, ("error %d in GetExtAttr", rc));
2134 } else {
2135 /* decode response */
2136 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2137 if (rc || (pSMBr->ByteCount < 2))
2138 /* BB also check enough total bytes returned */
2139 /* If rc should we check for EOPNOSUPP and
2140 disable the srvino flag? or in caller? */
2141 rc = -EIO; /* bad smb */
2142 else {
2143 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2144 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2145 struct file_chattr_info * pfinfo;
2146 /* BB Do we need a cast or hash here ? */
2147 if(count != 16) {
2148 cFYI(1, ("Illegal size ret in GetExtAttr"));
2149 rc = -EIO;
2150 goto GetExtAttrOut;
2151 }
2152 pfinfo = (struct file_chattr_info *)
2153 (data_offset + (char *) &pSMBr->hdr.Protocol);
2154 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2155 *pMask = le64_to_cpu(pfinfo->mask);
2156 }
2157 }
2158GetExtAttrOut:
2159 cifs_buf_release(pSMB);
2160 if (rc == -EAGAIN)
2161 goto GetExtAttrRetry;
2162 return rc;
2163}
2164
2165
2166#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
2168int
2169CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2170 const unsigned char *searchName,
2171 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002172 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173{
2174/* level 263 SMB_QUERY_FILE_ALL_INFO */
2175 TRANSACTION2_QPI_REQ *pSMB = NULL;
2176 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2177 int rc = 0;
2178 int bytes_returned;
2179 int name_len;
2180 __u16 params, byte_count;
2181
2182/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2183QPathInfoRetry:
2184 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2185 (void **) &pSMBr);
2186 if (rc)
2187 return rc;
2188
2189 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2190 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002191 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002192 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 name_len++; /* trailing null */
2194 name_len *= 2;
2195 } else { /* BB improve the check for buffer overruns BB */
2196 name_len = strnlen(searchName, PATH_MAX);
2197 name_len++; /* trailing null */
2198 strncpy(pSMB->FileName, searchName, name_len);
2199 }
2200
2201 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2202 pSMB->TotalDataCount = 0;
2203 pSMB->MaxParameterCount = cpu_to_le16(2);
2204 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2205 pSMB->MaxSetupCount = 0;
2206 pSMB->Reserved = 0;
2207 pSMB->Flags = 0;
2208 pSMB->Timeout = 0;
2209 pSMB->Reserved2 = 0;
2210 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2211 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2212 pSMB->DataCount = 0;
2213 pSMB->DataOffset = 0;
2214 pSMB->SetupCount = 1;
2215 pSMB->Reserved3 = 0;
2216 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2217 byte_count = params + 1 /* pad */ ;
2218 pSMB->TotalParameterCount = cpu_to_le16(params);
2219 pSMB->ParameterCount = pSMB->TotalParameterCount;
2220 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2221 pSMB->Reserved4 = 0;
2222 pSMB->hdr.smb_buf_length += byte_count;
2223 pSMB->ByteCount = cpu_to_le16(byte_count);
2224
2225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2227 if (rc) {
2228 cFYI(1, ("Send error in QPathInfo = %d", rc));
2229 } else { /* decode response */
2230 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2231
2232 if (rc || (pSMBr->ByteCount < 40))
2233 rc = -EIO; /* bad smb */
2234 else if (pFindData){
2235 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2236 memcpy((char *) pFindData,
2237 (char *) &pSMBr->hdr.Protocol +
2238 data_offset, sizeof (FILE_ALL_INFO));
2239 } else
2240 rc = -ENOMEM;
2241 }
2242 cifs_buf_release(pSMB);
2243 if (rc == -EAGAIN)
2244 goto QPathInfoRetry;
2245
2246 return rc;
2247}
2248
2249int
2250CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2251 const unsigned char *searchName,
2252 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002253 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254{
2255/* SMB_QUERY_FILE_UNIX_BASIC */
2256 TRANSACTION2_QPI_REQ *pSMB = NULL;
2257 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2258 int rc = 0;
2259 int bytes_returned = 0;
2260 int name_len;
2261 __u16 params, byte_count;
2262
2263 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2264UnixQPathInfoRetry:
2265 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2266 (void **) &pSMBr);
2267 if (rc)
2268 return rc;
2269
2270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002272 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002273 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 name_len++; /* trailing null */
2275 name_len *= 2;
2276 } else { /* BB improve the check for buffer overruns BB */
2277 name_len = strnlen(searchName, PATH_MAX);
2278 name_len++; /* trailing null */
2279 strncpy(pSMB->FileName, searchName, name_len);
2280 }
2281
2282 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2283 pSMB->TotalDataCount = 0;
2284 pSMB->MaxParameterCount = cpu_to_le16(2);
2285 /* BB find exact max SMB PDU from sess structure BB */
2286 pSMB->MaxDataCount = cpu_to_le16(4000);
2287 pSMB->MaxSetupCount = 0;
2288 pSMB->Reserved = 0;
2289 pSMB->Flags = 0;
2290 pSMB->Timeout = 0;
2291 pSMB->Reserved2 = 0;
2292 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2293 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2294 pSMB->DataCount = 0;
2295 pSMB->DataOffset = 0;
2296 pSMB->SetupCount = 1;
2297 pSMB->Reserved3 = 0;
2298 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2299 byte_count = params + 1 /* pad */ ;
2300 pSMB->TotalParameterCount = cpu_to_le16(params);
2301 pSMB->ParameterCount = pSMB->TotalParameterCount;
2302 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2303 pSMB->Reserved4 = 0;
2304 pSMB->hdr.smb_buf_length += byte_count;
2305 pSMB->ByteCount = cpu_to_le16(byte_count);
2306
2307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2309 if (rc) {
2310 cFYI(1, ("Send error in QPathInfo = %d", rc));
2311 } else { /* decode response */
2312 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2313
2314 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2315 rc = -EIO; /* bad smb */
2316 } else {
2317 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2318 memcpy((char *) pFindData,
2319 (char *) &pSMBr->hdr.Protocol +
2320 data_offset,
2321 sizeof (FILE_UNIX_BASIC_INFO));
2322 }
2323 }
2324 cifs_buf_release(pSMB);
2325 if (rc == -EAGAIN)
2326 goto UnixQPathInfoRetry;
2327
2328 return rc;
2329}
2330
2331#if 0 /* function unused at present */
2332int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2333 const char *searchName, FILE_ALL_INFO * findData,
2334 const struct nls_table *nls_codepage)
2335{
2336/* level 257 SMB_ */
2337 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2338 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2339 int rc = 0;
2340 int bytes_returned;
2341 int name_len;
2342 __u16 params, byte_count;
2343
2344 cFYI(1, ("In FindUnique"));
2345findUniqueRetry:
2346 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2347 (void **) &pSMBr);
2348 if (rc)
2349 return rc;
2350
2351 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2352 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002353 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 /* find define for this maxpathcomponent */
2355 , nls_codepage);
2356 name_len++; /* trailing null */
2357 name_len *= 2;
2358 } else { /* BB improve the check for buffer overruns BB */
2359 name_len = strnlen(searchName, PATH_MAX);
2360 name_len++; /* trailing null */
2361 strncpy(pSMB->FileName, searchName, name_len);
2362 }
2363
2364 params = 12 + name_len /* includes null */ ;
2365 pSMB->TotalDataCount = 0; /* no EAs */
2366 pSMB->MaxParameterCount = cpu_to_le16(2);
2367 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2368 pSMB->MaxSetupCount = 0;
2369 pSMB->Reserved = 0;
2370 pSMB->Flags = 0;
2371 pSMB->Timeout = 0;
2372 pSMB->Reserved2 = 0;
2373 pSMB->ParameterOffset = cpu_to_le16(
2374 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2375 pSMB->DataCount = 0;
2376 pSMB->DataOffset = 0;
2377 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2378 pSMB->Reserved3 = 0;
2379 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2380 byte_count = params + 1 /* pad */ ;
2381 pSMB->TotalParameterCount = cpu_to_le16(params);
2382 pSMB->ParameterCount = pSMB->TotalParameterCount;
2383 pSMB->SearchAttributes =
2384 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2385 ATTR_DIRECTORY);
2386 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2387 pSMB->SearchFlags = cpu_to_le16(1);
2388 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2389 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2390 pSMB->hdr.smb_buf_length += byte_count;
2391 pSMB->ByteCount = cpu_to_le16(byte_count);
2392
2393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2395
2396 if (rc) {
2397 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2398 } else { /* decode response */
Steve Frenchdfb75332005-06-22 17:13:47 -07002399#ifdef CONFIG_CIFS_STATS
2400 atomic_inc(&tcon->num_ffirst);
2401#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 /* BB fill in */
2403 }
2404
2405 cifs_buf_release(pSMB);
2406 if (rc == -EAGAIN)
2407 goto findUniqueRetry;
2408
2409 return rc;
2410}
2411#endif /* end unused (temporarily) function */
2412
2413/* xid, tcon, searchName and codepage are input parms, rest are returned */
2414int
2415CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2416 const char *searchName,
2417 const struct nls_table *nls_codepage,
2418 __u16 * pnetfid,
Steve French737b7582005-04-28 22:41:06 -07002419 struct cifs_search_info * psrch_inf, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420{
2421/* level 257 SMB_ */
2422 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2423 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2424 T2_FFIRST_RSP_PARMS * parms;
2425 int rc = 0;
2426 int bytes_returned = 0;
2427 int name_len;
2428 __u16 params, byte_count;
2429
Steve French737b7582005-04-28 22:41:06 -07002430 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
2432findFirstRetry:
2433 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2434 (void **) &pSMBr);
2435 if (rc)
2436 return rc;
2437
2438 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2439 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002440 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002441 PATH_MAX, nls_codepage, remap);
2442 /* We can not add the asterik earlier in case
2443 it got remapped to 0xF03A as if it were part of the
2444 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 name_len *= 2;
Steve French737b7582005-04-28 22:41:06 -07002446 pSMB->FileName[name_len] = '\\';
2447 pSMB->FileName[name_len+1] = 0;
2448 pSMB->FileName[name_len+2] = '*';
2449 pSMB->FileName[name_len+3] = 0;
2450 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2452 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002453 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 } else { /* BB add check for overrun of SMB buf BB */
2455 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456/* BB fix here and in unicode clause above ie
2457 if(name_len > buffersize-header)
2458 free buffer exit; BB */
2459 strncpy(pSMB->FileName, searchName, name_len);
Steve French68575472005-04-30 11:10:57 -07002460 pSMB->FileName[name_len] = '\\';
2461 pSMB->FileName[name_len+1] = '*';
2462 pSMB->FileName[name_len+2] = 0;
2463 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 }
2465
2466 params = 12 + name_len /* includes null */ ;
2467 pSMB->TotalDataCount = 0; /* no EAs */
2468 pSMB->MaxParameterCount = cpu_to_le16(10);
2469 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2470 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2471 pSMB->MaxSetupCount = 0;
2472 pSMB->Reserved = 0;
2473 pSMB->Flags = 0;
2474 pSMB->Timeout = 0;
2475 pSMB->Reserved2 = 0;
2476 byte_count = params + 1 /* pad */ ;
2477 pSMB->TotalParameterCount = cpu_to_le16(params);
2478 pSMB->ParameterCount = pSMB->TotalParameterCount;
2479 pSMB->ParameterOffset = cpu_to_le16(
2480 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2481 pSMB->DataCount = 0;
2482 pSMB->DataOffset = 0;
2483 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2484 pSMB->Reserved3 = 0;
2485 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2486 pSMB->SearchAttributes =
2487 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2488 ATTR_DIRECTORY);
2489 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2490 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2491 CIFS_SEARCH_RETURN_RESUME);
2492 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2493
2494 /* BB what should we set StorageType to? Does it matter? BB */
2495 pSMB->SearchStorageType = 0;
2496 pSMB->hdr.smb_buf_length += byte_count;
2497 pSMB->ByteCount = cpu_to_le16(byte_count);
2498
2499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2501
2502 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2503 /* BB Add code to handle unsupported level rc */
2504 cFYI(1, ("Error in FindFirst = %d", rc));
2505
2506 if (pSMB)
2507 cifs_buf_release(pSMB);
2508
2509 /* BB eventually could optimize out free and realloc of buf */
2510 /* for this case */
2511 if (rc == -EAGAIN)
2512 goto findFirstRetry;
2513 } else { /* decode response */
Steve Frenchdfb75332005-06-22 17:13:47 -07002514#ifdef CONFIG_CIFS_STATS
2515 atomic_inc(&tcon->num_ffirst);
2516#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 /* BB remember to free buffer if error BB */
2518 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2519 if(rc == 0) {
2520 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2521 psrch_inf->unicode = TRUE;
2522 else
2523 psrch_inf->unicode = FALSE;
2524
2525 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2526 psrch_inf->srch_entries_start =
2527 (char *) &pSMBr->hdr.Protocol +
2528 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2530 le16_to_cpu(pSMBr->t2.ParameterOffset));
2531
2532 if(parms->EndofSearch)
2533 psrch_inf->endOfSearch = TRUE;
2534 else
2535 psrch_inf->endOfSearch = FALSE;
2536
2537 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2538 psrch_inf->index_of_last_entry =
2539 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 *pnetfid = parms->SearchHandle;
2541 } else {
2542 cifs_buf_release(pSMB);
2543 }
2544 }
2545
2546 return rc;
2547}
2548
2549int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2550 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2551{
2552 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2553 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2554 T2_FNEXT_RSP_PARMS * parms;
2555 char *response_data;
2556 int rc = 0;
2557 int bytes_returned, name_len;
2558 __u16 params, byte_count;
2559
2560 cFYI(1, ("In FindNext"));
2561
2562 if(psrch_inf->endOfSearch == TRUE)
2563 return -ENOENT;
2564
2565 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2566 (void **) &pSMBr);
2567 if (rc)
2568 return rc;
2569
2570 params = 14; /* includes 2 bytes of null string, converted to LE below */
2571 byte_count = 0;
2572 pSMB->TotalDataCount = 0; /* no EAs */
2573 pSMB->MaxParameterCount = cpu_to_le16(8);
2574 pSMB->MaxDataCount =
2575 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2576 pSMB->MaxSetupCount = 0;
2577 pSMB->Reserved = 0;
2578 pSMB->Flags = 0;
2579 pSMB->Timeout = 0;
2580 pSMB->Reserved2 = 0;
2581 pSMB->ParameterOffset = cpu_to_le16(
2582 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2583 pSMB->DataCount = 0;
2584 pSMB->DataOffset = 0;
2585 pSMB->SetupCount = 1;
2586 pSMB->Reserved3 = 0;
2587 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2588 pSMB->SearchHandle = searchHandle; /* always kept as le */
2589 pSMB->SearchCount =
2590 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2591 /* test for Unix extensions */
2592/* if (tcon->ses->capabilities & CAP_UNIX) {
2593 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2594 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2595 } else {
2596 pSMB->InformationLevel =
2597 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2598 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2599 } */
2600 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2601 pSMB->ResumeKey = psrch_inf->resume_key;
2602 pSMB->SearchFlags =
2603 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2604
2605 name_len = psrch_inf->resume_name_len;
2606 params += name_len;
2607 if(name_len < PATH_MAX) {
2608 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2609 byte_count += name_len;
2610 } else {
2611 rc = -EINVAL;
2612 goto FNext2_err_exit;
2613 }
2614 byte_count = params + 1 /* pad */ ;
2615 pSMB->TotalParameterCount = cpu_to_le16(params);
2616 pSMB->ParameterCount = pSMB->TotalParameterCount;
2617 pSMB->hdr.smb_buf_length += byte_count;
2618 pSMB->ByteCount = cpu_to_le16(byte_count);
2619
2620 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2621 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2622
2623 if (rc) {
2624 if (rc == -EBADF) {
2625 psrch_inf->endOfSearch = TRUE;
2626 rc = 0; /* search probably was closed at end of search above */
2627 } else
2628 cFYI(1, ("FindNext returned = %d", rc));
2629 } else { /* decode response */
Steve Frenchdfb75332005-06-22 17:13:47 -07002630#ifdef CONFIG_CIFS_STATS
2631 atomic_inc(&tcon->num_fnext);
2632#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2634
2635 if(rc == 0) {
2636 /* BB fixme add lock for file (srch_info) struct here */
2637 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2638 psrch_inf->unicode = TRUE;
2639 else
2640 psrch_inf->unicode = FALSE;
2641 response_data = (char *) &pSMBr->hdr.Protocol +
2642 le16_to_cpu(pSMBr->t2.ParameterOffset);
2643 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2644 response_data = (char *)&pSMBr->hdr.Protocol +
2645 le16_to_cpu(pSMBr->t2.DataOffset);
2646 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2647 psrch_inf->srch_entries_start = response_data;
2648 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2649 if(parms->EndofSearch)
2650 psrch_inf->endOfSearch = TRUE;
2651 else
2652 psrch_inf->endOfSearch = FALSE;
2653
2654 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2655 psrch_inf->index_of_last_entry +=
2656 psrch_inf->entries_in_buffer;
2657/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2658
2659 /* BB fixme add unlock here */
2660 }
2661
2662 }
2663
2664 /* BB On error, should we leave previous search buf (and count and
2665 last entry fields) intact or free the previous one? */
2666
2667 /* Note: On -EAGAIN error only caller can retry on handle based calls
2668 since file handle passed in no longer valid */
2669FNext2_err_exit:
2670 if (rc != 0)
2671 cifs_buf_release(pSMB);
2672
2673 return rc;
2674}
2675
2676int
2677CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2678{
2679 int rc = 0;
2680 FINDCLOSE_REQ *pSMB = NULL;
2681 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2682 int bytes_returned;
2683
2684 cFYI(1, ("In CIFSSMBFindClose"));
2685 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2686
2687 /* no sense returning error if session restarted
2688 as file handle has been closed */
2689 if(rc == -EAGAIN)
2690 return 0;
2691 if (rc)
2692 return rc;
2693
2694 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2695 pSMB->FileID = searchHandle;
2696 pSMB->ByteCount = 0;
2697 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2698 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2699 if (rc) {
2700 cERROR(1, ("Send error in FindClose = %d", rc));
2701 }
Steve Frenchdfb75332005-06-22 17:13:47 -07002702#ifdef CONFIG_CIFS_STATS
2703 atomic_inc(&tcon->num_fclose);
2704#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 cifs_small_buf_release(pSMB);
2706
2707 /* Since session is dead, search handle closed on server already */
2708 if (rc == -EAGAIN)
2709 rc = 0;
2710
2711 return rc;
2712}
2713
2714#ifdef CONFIG_CIFS_EXPERIMENTAL
2715int
2716CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2717 const unsigned char *searchName,
2718 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002719 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720{
2721 int rc = 0;
2722 TRANSACTION2_QPI_REQ *pSMB = NULL;
2723 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2724 int name_len, bytes_returned;
2725 __u16 params, byte_count;
2726
2727 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2728 if(tcon == NULL)
2729 return -ENODEV;
2730
2731GetInodeNumberRetry:
2732 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2733 (void **) &pSMBr);
2734 if (rc)
2735 return rc;
2736
2737
2738 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2739 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002740 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002741 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 name_len++; /* trailing null */
2743 name_len *= 2;
2744 } else { /* BB improve the check for buffer overruns BB */
2745 name_len = strnlen(searchName, PATH_MAX);
2746 name_len++; /* trailing null */
2747 strncpy(pSMB->FileName, searchName, name_len);
2748 }
2749
2750 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2751 pSMB->TotalDataCount = 0;
2752 pSMB->MaxParameterCount = cpu_to_le16(2);
2753 /* BB find exact max data count below from sess structure BB */
2754 pSMB->MaxDataCount = cpu_to_le16(4000);
2755 pSMB->MaxSetupCount = 0;
2756 pSMB->Reserved = 0;
2757 pSMB->Flags = 0;
2758 pSMB->Timeout = 0;
2759 pSMB->Reserved2 = 0;
2760 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2761 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2762 pSMB->DataCount = 0;
2763 pSMB->DataOffset = 0;
2764 pSMB->SetupCount = 1;
2765 pSMB->Reserved3 = 0;
2766 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2767 byte_count = params + 1 /* pad */ ;
2768 pSMB->TotalParameterCount = cpu_to_le16(params);
2769 pSMB->ParameterCount = pSMB->TotalParameterCount;
2770 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2771 pSMB->Reserved4 = 0;
2772 pSMB->hdr.smb_buf_length += byte_count;
2773 pSMB->ByteCount = cpu_to_le16(byte_count);
2774
2775 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2776 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2777 if (rc) {
2778 cFYI(1, ("error %d in QueryInternalInfo", rc));
2779 } else {
2780 /* decode response */
2781 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2782 if (rc || (pSMBr->ByteCount < 2))
2783 /* BB also check enough total bytes returned */
2784 /* If rc should we check for EOPNOSUPP and
2785 disable the srvino flag? or in caller? */
2786 rc = -EIO; /* bad smb */
2787 else {
2788 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2789 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2790 struct file_internal_info * pfinfo;
2791 /* BB Do we need a cast or hash here ? */
2792 if(count < 8) {
2793 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2794 rc = -EIO;
2795 goto GetInodeNumOut;
2796 }
2797 pfinfo = (struct file_internal_info *)
2798 (data_offset + (char *) &pSMBr->hdr.Protocol);
2799 *inode_number = pfinfo->UniqueId;
2800 }
2801 }
2802GetInodeNumOut:
2803 cifs_buf_release(pSMB);
2804 if (rc == -EAGAIN)
2805 goto GetInodeNumberRetry;
2806 return rc;
2807}
2808#endif /* CIFS_EXPERIMENTAL */
2809
2810int
2811CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2812 const unsigned char *searchName,
2813 unsigned char **targetUNCs,
2814 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07002815 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816{
2817/* TRANS2_GET_DFS_REFERRAL */
2818 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2819 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2820 struct dfs_referral_level_3 * referrals = NULL;
2821 int rc = 0;
2822 int bytes_returned;
2823 int name_len;
2824 unsigned int i;
2825 char * temp;
2826 __u16 params, byte_count;
2827 *number_of_UNC_in_array = 0;
2828 *targetUNCs = NULL;
2829
2830 cFYI(1, ("In GetDFSRefer the path %s", searchName));
2831 if (ses == NULL)
2832 return -ENODEV;
2833getDFSRetry:
2834 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2835 (void **) &pSMBr);
2836 if (rc)
2837 return rc;
2838
2839 pSMB->hdr.Tid = ses->ipc_tid;
2840 pSMB->hdr.Uid = ses->Suid;
2841 if (ses->capabilities & CAP_STATUS32) {
2842 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2843 }
2844 if (ses->capabilities & CAP_DFS) {
2845 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2846 }
2847
2848 if (ses->capabilities & CAP_UNICODE) {
2849 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2850 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002851 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07002852 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 name_len++; /* trailing null */
2854 name_len *= 2;
2855 } else { /* BB improve the check for buffer overruns BB */
2856 name_len = strnlen(searchName, PATH_MAX);
2857 name_len++; /* trailing null */
2858 strncpy(pSMB->RequestFileName, searchName, name_len);
2859 }
2860
2861 params = 2 /* level */ + name_len /*includes null */ ;
2862 pSMB->TotalDataCount = 0;
2863 pSMB->DataCount = 0;
2864 pSMB->DataOffset = 0;
2865 pSMB->MaxParameterCount = 0;
2866 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2867 pSMB->MaxSetupCount = 0;
2868 pSMB->Reserved = 0;
2869 pSMB->Flags = 0;
2870 pSMB->Timeout = 0;
2871 pSMB->Reserved2 = 0;
2872 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2873 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2874 pSMB->SetupCount = 1;
2875 pSMB->Reserved3 = 0;
2876 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2877 byte_count = params + 3 /* pad */ ;
2878 pSMB->ParameterCount = cpu_to_le16(params);
2879 pSMB->TotalParameterCount = pSMB->ParameterCount;
2880 pSMB->MaxReferralLevel = cpu_to_le16(3);
2881 pSMB->hdr.smb_buf_length += byte_count;
2882 pSMB->ByteCount = cpu_to_le16(byte_count);
2883
2884 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2886 if (rc) {
2887 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2888 } else { /* decode response */
2889/* BB Add logic to parse referrals here */
2890 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2891
2892 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
2893 rc = -EIO; /* bad smb */
2894 else {
2895 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2896 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2897
2898 cFYI(1,
2899 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
2900 pSMBr->ByteCount, data_offset));
2901 referrals =
2902 (struct dfs_referral_level_3 *)
2903 (8 /* sizeof start of data block */ +
2904 data_offset +
2905 (char *) &pSMBr->hdr.Protocol);
2906 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",
2907 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)));
2908 /* BB This field is actually two bytes in from start of
2909 data block so we could do safety check that DataBlock
2910 begins at address of pSMBr->NumberOfReferrals */
2911 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2912
2913 /* BB Fix below so can return more than one referral */
2914 if(*number_of_UNC_in_array > 1)
2915 *number_of_UNC_in_array = 1;
2916
2917 /* get the length of the strings describing refs */
2918 name_len = 0;
2919 for(i=0;i<*number_of_UNC_in_array;i++) {
2920 /* make sure that DfsPathOffset not past end */
2921 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2922 if (offset > data_count) {
2923 /* if invalid referral, stop here and do
2924 not try to copy any more */
2925 *number_of_UNC_in_array = i;
2926 break;
2927 }
2928 temp = ((char *)referrals) + offset;
2929
2930 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2931 name_len += UniStrnlen((wchar_t *)temp,data_count);
2932 } else {
2933 name_len += strnlen(temp,data_count);
2934 }
2935 referrals++;
2936 /* BB add check that referral pointer does not fall off end PDU */
2937
2938 }
2939 /* BB add check for name_len bigger than bcc */
2940 *targetUNCs =
2941 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2942 if(*targetUNCs == NULL) {
2943 rc = -ENOMEM;
2944 goto GetDFSRefExit;
2945 }
2946 /* copy the ref strings */
2947 referrals =
2948 (struct dfs_referral_level_3 *)
2949 (8 /* sizeof data hdr */ +
2950 data_offset +
2951 (char *) &pSMBr->hdr.Protocol);
2952
2953 for(i=0;i<*number_of_UNC_in_array;i++) {
2954 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2955 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2956 cifs_strfromUCS_le(*targetUNCs,
2957 (wchar_t *) temp, name_len, nls_codepage);
2958 } else {
2959 strncpy(*targetUNCs,temp,name_len);
2960 }
2961 /* BB update target_uncs pointers */
2962 referrals++;
2963 }
2964 temp = *targetUNCs;
2965 temp[name_len] = 0;
2966 }
2967
2968 }
2969GetDFSRefExit:
2970 if (pSMB)
2971 cifs_buf_release(pSMB);
2972
2973 if (rc == -EAGAIN)
2974 goto getDFSRetry;
2975
2976 return rc;
2977}
2978
2979int
Steve French737b7582005-04-28 22:41:06 -07002980CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981{
2982/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
2983 TRANSACTION2_QFSI_REQ *pSMB = NULL;
2984 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2985 FILE_SYSTEM_INFO *response_data;
2986 int rc = 0;
2987 int bytes_returned = 0;
2988 __u16 params, byte_count;
2989
2990 cFYI(1, ("In QFSInfo"));
2991QFSInfoRetry:
2992 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2993 (void **) &pSMBr);
2994 if (rc)
2995 return rc;
2996
2997 params = 2; /* level */
2998 pSMB->TotalDataCount = 0;
2999 pSMB->MaxParameterCount = cpu_to_le16(2);
3000 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3001 pSMB->MaxSetupCount = 0;
3002 pSMB->Reserved = 0;
3003 pSMB->Flags = 0;
3004 pSMB->Timeout = 0;
3005 pSMB->Reserved2 = 0;
3006 byte_count = params + 1 /* pad */ ;
3007 pSMB->TotalParameterCount = cpu_to_le16(params);
3008 pSMB->ParameterCount = pSMB->TotalParameterCount;
3009 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3010 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3011 pSMB->DataCount = 0;
3012 pSMB->DataOffset = 0;
3013 pSMB->SetupCount = 1;
3014 pSMB->Reserved3 = 0;
3015 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3016 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3017 pSMB->hdr.smb_buf_length += byte_count;
3018 pSMB->ByteCount = cpu_to_le16(byte_count);
3019
3020 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3021 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3022 if (rc) {
3023 cERROR(1, ("Send error in QFSInfo = %d", rc));
3024 } else { /* decode response */
3025 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3026
3027 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3028 rc = -EIO; /* bad smb */
3029 else {
3030 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3031 cFYI(1,
3032 ("Decoding qfsinfo response. BCC: %d Offset %d",
3033 pSMBr->ByteCount, data_offset));
3034
3035 response_data =
3036 (FILE_SYSTEM_INFO
3037 *) (((char *) &pSMBr->hdr.Protocol) +
3038 data_offset);
3039 FSData->f_bsize =
3040 le32_to_cpu(response_data->BytesPerSector) *
3041 le32_to_cpu(response_data->
3042 SectorsPerAllocationUnit);
3043 FSData->f_blocks =
3044 le64_to_cpu(response_data->TotalAllocationUnits);
3045 FSData->f_bfree = FSData->f_bavail =
3046 le64_to_cpu(response_data->FreeAllocationUnits);
3047 cFYI(1,
3048 ("Blocks: %lld Free: %lld Block size %ld",
3049 (unsigned long long)FSData->f_blocks,
3050 (unsigned long long)FSData->f_bfree,
3051 FSData->f_bsize));
3052 }
3053 }
3054 cifs_buf_release(pSMB);
3055
3056 if (rc == -EAGAIN)
3057 goto QFSInfoRetry;
3058
3059 return rc;
3060}
3061
3062int
Steve French737b7582005-04-28 22:41:06 -07003063CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064{
3065/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3066 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3067 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3068 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3069 int rc = 0;
3070 int bytes_returned = 0;
3071 __u16 params, byte_count;
3072
3073 cFYI(1, ("In QFSAttributeInfo"));
3074QFSAttributeRetry:
3075 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3076 (void **) &pSMBr);
3077 if (rc)
3078 return rc;
3079
3080 params = 2; /* level */
3081 pSMB->TotalDataCount = 0;
3082 pSMB->MaxParameterCount = cpu_to_le16(2);
3083 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3084 pSMB->MaxSetupCount = 0;
3085 pSMB->Reserved = 0;
3086 pSMB->Flags = 0;
3087 pSMB->Timeout = 0;
3088 pSMB->Reserved2 = 0;
3089 byte_count = params + 1 /* pad */ ;
3090 pSMB->TotalParameterCount = cpu_to_le16(params);
3091 pSMB->ParameterCount = pSMB->TotalParameterCount;
3092 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3093 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3094 pSMB->DataCount = 0;
3095 pSMB->DataOffset = 0;
3096 pSMB->SetupCount = 1;
3097 pSMB->Reserved3 = 0;
3098 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3099 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3100 pSMB->hdr.smb_buf_length += byte_count;
3101 pSMB->ByteCount = cpu_to_le16(byte_count);
3102
3103 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3104 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3105 if (rc) {
3106 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3107 } else { /* decode response */
3108 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3109
3110 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3111 rc = -EIO; /* bad smb */
3112 } else {
3113 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3114 response_data =
3115 (FILE_SYSTEM_ATTRIBUTE_INFO
3116 *) (((char *) &pSMBr->hdr.Protocol) +
3117 data_offset);
3118 memcpy(&tcon->fsAttrInfo, response_data,
3119 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3120 }
3121 }
3122 cifs_buf_release(pSMB);
3123
3124 if (rc == -EAGAIN)
3125 goto QFSAttributeRetry;
3126
3127 return rc;
3128}
3129
3130int
Steve French737b7582005-04-28 22:41:06 -07003131CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132{
3133/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3134 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3135 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3136 FILE_SYSTEM_DEVICE_INFO *response_data;
3137 int rc = 0;
3138 int bytes_returned = 0;
3139 __u16 params, byte_count;
3140
3141 cFYI(1, ("In QFSDeviceInfo"));
3142QFSDeviceRetry:
3143 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3144 (void **) &pSMBr);
3145 if (rc)
3146 return rc;
3147
3148 params = 2; /* level */
3149 pSMB->TotalDataCount = 0;
3150 pSMB->MaxParameterCount = cpu_to_le16(2);
3151 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3152 pSMB->MaxSetupCount = 0;
3153 pSMB->Reserved = 0;
3154 pSMB->Flags = 0;
3155 pSMB->Timeout = 0;
3156 pSMB->Reserved2 = 0;
3157 byte_count = params + 1 /* pad */ ;
3158 pSMB->TotalParameterCount = cpu_to_le16(params);
3159 pSMB->ParameterCount = pSMB->TotalParameterCount;
3160 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3161 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3162
3163 pSMB->DataCount = 0;
3164 pSMB->DataOffset = 0;
3165 pSMB->SetupCount = 1;
3166 pSMB->Reserved3 = 0;
3167 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3168 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3169 pSMB->hdr.smb_buf_length += byte_count;
3170 pSMB->ByteCount = cpu_to_le16(byte_count);
3171
3172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3174 if (rc) {
3175 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3176 } else { /* decode response */
3177 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3178
3179 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3180 rc = -EIO; /* bad smb */
3181 else {
3182 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3183 response_data =
Steve French737b7582005-04-28 22:41:06 -07003184 (FILE_SYSTEM_DEVICE_INFO *)
3185 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 data_offset);
3187 memcpy(&tcon->fsDevInfo, response_data,
3188 sizeof (FILE_SYSTEM_DEVICE_INFO));
3189 }
3190 }
3191 cifs_buf_release(pSMB);
3192
3193 if (rc == -EAGAIN)
3194 goto QFSDeviceRetry;
3195
3196 return rc;
3197}
3198
3199int
Steve French737b7582005-04-28 22:41:06 -07003200CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201{
3202/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3203 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3204 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3205 FILE_SYSTEM_UNIX_INFO *response_data;
3206 int rc = 0;
3207 int bytes_returned = 0;
3208 __u16 params, byte_count;
3209
3210 cFYI(1, ("In QFSUnixInfo"));
3211QFSUnixRetry:
3212 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3213 (void **) &pSMBr);
3214 if (rc)
3215 return rc;
3216
3217 params = 2; /* level */
3218 pSMB->TotalDataCount = 0;
3219 pSMB->DataCount = 0;
3220 pSMB->DataOffset = 0;
3221 pSMB->MaxParameterCount = cpu_to_le16(2);
3222 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3223 pSMB->MaxSetupCount = 0;
3224 pSMB->Reserved = 0;
3225 pSMB->Flags = 0;
3226 pSMB->Timeout = 0;
3227 pSMB->Reserved2 = 0;
3228 byte_count = params + 1 /* pad */ ;
3229 pSMB->ParameterCount = cpu_to_le16(params);
3230 pSMB->TotalParameterCount = pSMB->ParameterCount;
3231 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3232 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3233 pSMB->SetupCount = 1;
3234 pSMB->Reserved3 = 0;
3235 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3236 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3237 pSMB->hdr.smb_buf_length += byte_count;
3238 pSMB->ByteCount = cpu_to_le16(byte_count);
3239
3240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3241 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3242 if (rc) {
3243 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3244 } else { /* decode response */
3245 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3246
3247 if (rc || (pSMBr->ByteCount < 13)) {
3248 rc = -EIO; /* bad smb */
3249 } else {
3250 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3251 response_data =
3252 (FILE_SYSTEM_UNIX_INFO
3253 *) (((char *) &pSMBr->hdr.Protocol) +
3254 data_offset);
3255 memcpy(&tcon->fsUnixInfo, response_data,
3256 sizeof (FILE_SYSTEM_UNIX_INFO));
3257 }
3258 }
3259 cifs_buf_release(pSMB);
3260
3261 if (rc == -EAGAIN)
3262 goto QFSUnixRetry;
3263
3264
3265 return rc;
3266}
3267
3268
3269int
3270CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003271 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272{
3273/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3274 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3275 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3276 FILE_SYSTEM_POSIX_INFO *response_data;
3277 int rc = 0;
3278 int bytes_returned = 0;
3279 __u16 params, byte_count;
3280
3281 cFYI(1, ("In QFSPosixInfo"));
3282QFSPosixRetry:
3283 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3284 (void **) &pSMBr);
3285 if (rc)
3286 return rc;
3287
3288 params = 2; /* level */
3289 pSMB->TotalDataCount = 0;
3290 pSMB->DataCount = 0;
3291 pSMB->DataOffset = 0;
3292 pSMB->MaxParameterCount = cpu_to_le16(2);
3293 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3294 pSMB->MaxSetupCount = 0;
3295 pSMB->Reserved = 0;
3296 pSMB->Flags = 0;
3297 pSMB->Timeout = 0;
3298 pSMB->Reserved2 = 0;
3299 byte_count = params + 1 /* pad */ ;
3300 pSMB->ParameterCount = cpu_to_le16(params);
3301 pSMB->TotalParameterCount = pSMB->ParameterCount;
3302 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3303 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3304 pSMB->SetupCount = 1;
3305 pSMB->Reserved3 = 0;
3306 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3307 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3308 pSMB->hdr.smb_buf_length += byte_count;
3309 pSMB->ByteCount = cpu_to_le16(byte_count);
3310
3311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3312 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3313 if (rc) {
3314 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3315 } else { /* decode response */
3316 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3317
3318 if (rc || (pSMBr->ByteCount < 13)) {
3319 rc = -EIO; /* bad smb */
3320 } else {
3321 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3322 response_data =
3323 (FILE_SYSTEM_POSIX_INFO
3324 *) (((char *) &pSMBr->hdr.Protocol) +
3325 data_offset);
3326 FSData->f_bsize =
3327 le32_to_cpu(response_data->BlockSize);
3328 FSData->f_blocks =
3329 le64_to_cpu(response_data->TotalBlocks);
3330 FSData->f_bfree =
3331 le64_to_cpu(response_data->BlocksAvail);
3332 if(response_data->UserBlocksAvail == -1) {
3333 FSData->f_bavail = FSData->f_bfree;
3334 } else {
3335 FSData->f_bavail =
3336 le64_to_cpu(response_data->UserBlocksAvail);
3337 }
3338 if(response_data->TotalFileNodes != -1)
3339 FSData->f_files =
3340 le64_to_cpu(response_data->TotalFileNodes);
3341 if(response_data->FreeFileNodes != -1)
3342 FSData->f_ffree =
3343 le64_to_cpu(response_data->FreeFileNodes);
3344 }
3345 }
3346 cifs_buf_release(pSMB);
3347
3348 if (rc == -EAGAIN)
3349 goto QFSPosixRetry;
3350
3351 return rc;
3352}
3353
3354
3355/* We can not use write of zero bytes trick to
3356 set file size due to need for large file support. Also note that
3357 this SetPathInfo is preferred to SetFileInfo based method in next
3358 routine which is only needed to work around a sharing violation bug
3359 in Samba which this routine can run into */
3360
3361int
3362CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003363 __u64 size, int SetAllocation,
3364 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365{
3366 struct smb_com_transaction2_spi_req *pSMB = NULL;
3367 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3368 struct file_end_of_file_info *parm_data;
3369 int name_len;
3370 int rc = 0;
3371 int bytes_returned = 0;
3372 __u16 params, byte_count, data_count, param_offset, offset;
3373
3374 cFYI(1, ("In SetEOF"));
3375SetEOFRetry:
3376 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3377 (void **) &pSMBr);
3378 if (rc)
3379 return rc;
3380
3381 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3382 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003383 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003384 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 name_len++; /* trailing null */
3386 name_len *= 2;
3387 } else { /* BB improve the check for buffer overruns BB */
3388 name_len = strnlen(fileName, PATH_MAX);
3389 name_len++; /* trailing null */
3390 strncpy(pSMB->FileName, fileName, name_len);
3391 }
3392 params = 6 + name_len;
3393 data_count = sizeof (struct file_end_of_file_info);
3394 pSMB->MaxParameterCount = cpu_to_le16(2);
3395 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3396 pSMB->MaxSetupCount = 0;
3397 pSMB->Reserved = 0;
3398 pSMB->Flags = 0;
3399 pSMB->Timeout = 0;
3400 pSMB->Reserved2 = 0;
3401 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3402 InformationLevel) - 4;
3403 offset = param_offset + params;
3404 if(SetAllocation) {
3405 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3406 pSMB->InformationLevel =
3407 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3408 else
3409 pSMB->InformationLevel =
3410 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3411 } else /* Set File Size */ {
3412 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3413 pSMB->InformationLevel =
3414 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3415 else
3416 pSMB->InformationLevel =
3417 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3418 }
3419
3420 parm_data =
3421 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3422 offset);
3423 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3424 pSMB->DataOffset = cpu_to_le16(offset);
3425 pSMB->SetupCount = 1;
3426 pSMB->Reserved3 = 0;
3427 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3428 byte_count = 3 /* pad */ + params + data_count;
3429 pSMB->DataCount = cpu_to_le16(data_count);
3430 pSMB->TotalDataCount = pSMB->DataCount;
3431 pSMB->ParameterCount = cpu_to_le16(params);
3432 pSMB->TotalParameterCount = pSMB->ParameterCount;
3433 pSMB->Reserved4 = 0;
3434 pSMB->hdr.smb_buf_length += byte_count;
3435 parm_data->FileSize = cpu_to_le64(size);
3436 pSMB->ByteCount = cpu_to_le16(byte_count);
3437 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3439 if (rc) {
3440 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3441 }
3442
3443 cifs_buf_release(pSMB);
3444
3445 if (rc == -EAGAIN)
3446 goto SetEOFRetry;
3447
3448 return rc;
3449}
3450
3451int
3452CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3453 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3454{
3455 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3456 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3457 char *data_offset;
3458 struct file_end_of_file_info *parm_data;
3459 int rc = 0;
3460 int bytes_returned = 0;
3461 __u16 params, param_offset, offset, byte_count, count;
3462
3463 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3464 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003465 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3466
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 if (rc)
3468 return rc;
3469
Steve Frenchcd634992005-04-28 22:41:10 -07003470 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3471
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3473 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3474
3475 params = 6;
3476 pSMB->MaxSetupCount = 0;
3477 pSMB->Reserved = 0;
3478 pSMB->Flags = 0;
3479 pSMB->Timeout = 0;
3480 pSMB->Reserved2 = 0;
3481 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3482 offset = param_offset + params;
3483
3484 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3485
3486 count = sizeof(struct file_end_of_file_info);
3487 pSMB->MaxParameterCount = cpu_to_le16(2);
3488 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3489 pSMB->SetupCount = 1;
3490 pSMB->Reserved3 = 0;
3491 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3492 byte_count = 3 /* pad */ + params + count;
3493 pSMB->DataCount = cpu_to_le16(count);
3494 pSMB->ParameterCount = cpu_to_le16(params);
3495 pSMB->TotalDataCount = pSMB->DataCount;
3496 pSMB->TotalParameterCount = pSMB->ParameterCount;
3497 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3498 parm_data =
3499 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3500 offset);
3501 pSMB->DataOffset = cpu_to_le16(offset);
3502 parm_data->FileSize = cpu_to_le64(size);
3503 pSMB->Fid = fid;
3504 if(SetAllocation) {
3505 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3506 pSMB->InformationLevel =
3507 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3508 else
3509 pSMB->InformationLevel =
3510 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3511 } else /* Set File Size */ {
3512 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3513 pSMB->InformationLevel =
3514 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3515 else
3516 pSMB->InformationLevel =
3517 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3518 }
3519 pSMB->Reserved4 = 0;
3520 pSMB->hdr.smb_buf_length += byte_count;
3521 pSMB->ByteCount = cpu_to_le16(byte_count);
3522 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3523 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3524 if (rc) {
3525 cFYI(1,
3526 ("Send error in SetFileInfo (SetFileSize) = %d",
3527 rc));
3528 }
3529
3530 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003531 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
3533 /* Note: On -EAGAIN error only caller can retry on handle based calls
3534 since file handle passed in no longer valid */
3535
3536 return rc;
3537}
3538
3539/* Some legacy servers such as NT4 require that the file times be set on
3540 an open handle, rather than by pathname - this is awkward due to
3541 potential access conflicts on the open, but it is unavoidable for these
3542 old servers since the only other choice is to go from 100 nanosecond DCE
3543 time and resort to the original setpathinfo level which takes the ancient
3544 DOS time format with 2 second granularity */
3545int
3546CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3547 __u16 fid)
3548{
3549 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3550 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3551 char *data_offset;
3552 int rc = 0;
3553 int bytes_returned = 0;
3554 __u16 params, param_offset, offset, byte_count, count;
3555
3556 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003557 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3558
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 if (rc)
3560 return rc;
3561
Steve Frenchcd634992005-04-28 22:41:10 -07003562 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3563
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 /* At this point there is no need to override the current pid
3565 with the pid of the opener, but that could change if we someday
3566 use an existing handle (rather than opening one on the fly) */
3567 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3568 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3569
3570 params = 6;
3571 pSMB->MaxSetupCount = 0;
3572 pSMB->Reserved = 0;
3573 pSMB->Flags = 0;
3574 pSMB->Timeout = 0;
3575 pSMB->Reserved2 = 0;
3576 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3577 offset = param_offset + params;
3578
3579 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3580
3581 count = sizeof (FILE_BASIC_INFO);
3582 pSMB->MaxParameterCount = cpu_to_le16(2);
3583 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3584 pSMB->SetupCount = 1;
3585 pSMB->Reserved3 = 0;
3586 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3587 byte_count = 3 /* pad */ + params + count;
3588 pSMB->DataCount = cpu_to_le16(count);
3589 pSMB->ParameterCount = cpu_to_le16(params);
3590 pSMB->TotalDataCount = pSMB->DataCount;
3591 pSMB->TotalParameterCount = pSMB->ParameterCount;
3592 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3593 pSMB->DataOffset = cpu_to_le16(offset);
3594 pSMB->Fid = fid;
3595 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3596 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3597 else
3598 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3599 pSMB->Reserved4 = 0;
3600 pSMB->hdr.smb_buf_length += byte_count;
3601 pSMB->ByteCount = cpu_to_le16(byte_count);
3602 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3605 if (rc) {
3606 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3607 }
3608
Steve Frenchcd634992005-04-28 22:41:10 -07003609 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610
3611 /* Note: On -EAGAIN error only caller can retry on handle based calls
3612 since file handle passed in no longer valid */
3613
3614 return rc;
3615}
3616
3617
3618int
3619CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3620 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07003621 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622{
3623 TRANSACTION2_SPI_REQ *pSMB = NULL;
3624 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3625 int name_len;
3626 int rc = 0;
3627 int bytes_returned = 0;
3628 char *data_offset;
3629 __u16 params, param_offset, offset, byte_count, count;
3630
3631 cFYI(1, ("In SetTimes"));
3632
3633SetTimesRetry:
3634 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3635 (void **) &pSMBr);
3636 if (rc)
3637 return rc;
3638
3639 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3640 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003641 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003642 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 name_len++; /* trailing null */
3644 name_len *= 2;
3645 } else { /* BB improve the check for buffer overruns BB */
3646 name_len = strnlen(fileName, PATH_MAX);
3647 name_len++; /* trailing null */
3648 strncpy(pSMB->FileName, fileName, name_len);
3649 }
3650
3651 params = 6 + name_len;
3652 count = sizeof (FILE_BASIC_INFO);
3653 pSMB->MaxParameterCount = cpu_to_le16(2);
3654 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3655 pSMB->MaxSetupCount = 0;
3656 pSMB->Reserved = 0;
3657 pSMB->Flags = 0;
3658 pSMB->Timeout = 0;
3659 pSMB->Reserved2 = 0;
3660 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3661 InformationLevel) - 4;
3662 offset = param_offset + params;
3663 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3664 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3665 pSMB->DataOffset = cpu_to_le16(offset);
3666 pSMB->SetupCount = 1;
3667 pSMB->Reserved3 = 0;
3668 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3669 byte_count = 3 /* pad */ + params + count;
3670
3671 pSMB->DataCount = cpu_to_le16(count);
3672 pSMB->ParameterCount = cpu_to_le16(params);
3673 pSMB->TotalDataCount = pSMB->DataCount;
3674 pSMB->TotalParameterCount = pSMB->ParameterCount;
3675 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3676 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3677 else
3678 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3679 pSMB->Reserved4 = 0;
3680 pSMB->hdr.smb_buf_length += byte_count;
3681 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3682 pSMB->ByteCount = cpu_to_le16(byte_count);
3683 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3684 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3685 if (rc) {
3686 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3687 }
3688
3689 cifs_buf_release(pSMB);
3690
3691 if (rc == -EAGAIN)
3692 goto SetTimesRetry;
3693
3694 return rc;
3695}
3696
3697/* Can not be used to set time stamps yet (due to old DOS time format) */
3698/* Can be used to set attributes */
3699#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
3700 handling it anyway and NT4 was what we thought it would be needed for
3701 Do not delete it until we prove whether needed for Win9x though */
3702int
3703CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3704 __u16 dos_attrs, const struct nls_table *nls_codepage)
3705{
3706 SETATTR_REQ *pSMB = NULL;
3707 SETATTR_RSP *pSMBr = NULL;
3708 int rc = 0;
3709 int bytes_returned;
3710 int name_len;
3711
3712 cFYI(1, ("In SetAttrLegacy"));
3713
3714SetAttrLgcyRetry:
3715 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3716 (void **) &pSMBr);
3717 if (rc)
3718 return rc;
3719
3720 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3721 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003722 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 PATH_MAX, nls_codepage);
3724 name_len++; /* trailing null */
3725 name_len *= 2;
3726 } else { /* BB improve the check for buffer overruns BB */
3727 name_len = strnlen(fileName, PATH_MAX);
3728 name_len++; /* trailing null */
3729 strncpy(pSMB->fileName, fileName, name_len);
3730 }
3731 pSMB->attr = cpu_to_le16(dos_attrs);
3732 pSMB->BufferFormat = 0x04;
3733 pSMB->hdr.smb_buf_length += name_len + 1;
3734 pSMB->ByteCount = cpu_to_le16(name_len + 1);
3735 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3736 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3737 if (rc) {
3738 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3739 }
3740
3741 cifs_buf_release(pSMB);
3742
3743 if (rc == -EAGAIN)
3744 goto SetAttrLgcyRetry;
3745
3746 return rc;
3747}
3748#endif /* temporarily unneeded SetAttr legacy function */
3749
3750int
3751CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003752 char *fileName, __u64 mode, __u64 uid, __u64 gid,
3753 dev_t device, const struct nls_table *nls_codepage,
3754 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755{
3756 TRANSACTION2_SPI_REQ *pSMB = NULL;
3757 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3758 int name_len;
3759 int rc = 0;
3760 int bytes_returned = 0;
3761 FILE_UNIX_BASIC_INFO *data_offset;
3762 __u16 params, param_offset, offset, count, byte_count;
3763
3764 cFYI(1, ("In SetUID/GID/Mode"));
3765setPermsRetry:
3766 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3767 (void **) &pSMBr);
3768 if (rc)
3769 return rc;
3770
3771 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3772 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003773 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003774 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 name_len++; /* trailing null */
3776 name_len *= 2;
3777 } else { /* BB improve the check for buffer overruns BB */
3778 name_len = strnlen(fileName, PATH_MAX);
3779 name_len++; /* trailing null */
3780 strncpy(pSMB->FileName, fileName, name_len);
3781 }
3782
3783 params = 6 + name_len;
3784 count = sizeof (FILE_UNIX_BASIC_INFO);
3785 pSMB->MaxParameterCount = cpu_to_le16(2);
3786 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3787 pSMB->MaxSetupCount = 0;
3788 pSMB->Reserved = 0;
3789 pSMB->Flags = 0;
3790 pSMB->Timeout = 0;
3791 pSMB->Reserved2 = 0;
3792 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3793 InformationLevel) - 4;
3794 offset = param_offset + params;
3795 data_offset =
3796 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3797 offset);
3798 memset(data_offset, 0, count);
3799 pSMB->DataOffset = cpu_to_le16(offset);
3800 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3801 pSMB->SetupCount = 1;
3802 pSMB->Reserved3 = 0;
3803 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3804 byte_count = 3 /* pad */ + params + count;
3805 pSMB->ParameterCount = cpu_to_le16(params);
3806 pSMB->DataCount = cpu_to_le16(count);
3807 pSMB->TotalParameterCount = pSMB->ParameterCount;
3808 pSMB->TotalDataCount = pSMB->DataCount;
3809 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3810 pSMB->Reserved4 = 0;
3811 pSMB->hdr.smb_buf_length += byte_count;
3812 data_offset->Uid = cpu_to_le64(uid);
3813 data_offset->Gid = cpu_to_le64(gid);
3814 /* better to leave device as zero when it is */
3815 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3816 data_offset->DevMinor = cpu_to_le64(MINOR(device));
3817 data_offset->Permissions = cpu_to_le64(mode);
3818
3819 if(S_ISREG(mode))
3820 data_offset->Type = cpu_to_le32(UNIX_FILE);
3821 else if(S_ISDIR(mode))
3822 data_offset->Type = cpu_to_le32(UNIX_DIR);
3823 else if(S_ISLNK(mode))
3824 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3825 else if(S_ISCHR(mode))
3826 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3827 else if(S_ISBLK(mode))
3828 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3829 else if(S_ISFIFO(mode))
3830 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3831 else if(S_ISSOCK(mode))
3832 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3833
3834
3835 pSMB->ByteCount = cpu_to_le16(byte_count);
3836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3837 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3838 if (rc) {
3839 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3840 }
3841
3842 if (pSMB)
3843 cifs_buf_release(pSMB);
3844 if (rc == -EAGAIN)
3845 goto setPermsRetry;
3846 return rc;
3847}
3848
3849int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
3850 const int notify_subdirs, const __u16 netfid,
3851 __u32 filter, const struct nls_table *nls_codepage)
3852{
3853 int rc = 0;
3854 struct smb_com_transaction_change_notify_req * pSMB = NULL;
3855 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3856 int bytes_returned;
3857
3858 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3859 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3860 (void **) &pSMBr);
3861 if (rc)
3862 return rc;
3863
3864 pSMB->TotalParameterCount = 0 ;
3865 pSMB->TotalDataCount = 0;
3866 pSMB->MaxParameterCount = cpu_to_le32(2);
3867 /* BB find exact data count max from sess structure BB */
3868 pSMB->MaxDataCount = 0; /* same in little endian or be */
3869 pSMB->MaxSetupCount = 4;
3870 pSMB->Reserved = 0;
3871 pSMB->ParameterOffset = 0;
3872 pSMB->DataCount = 0;
3873 pSMB->DataOffset = 0;
3874 pSMB->SetupCount = 4; /* single byte does not need le conversion */
3875 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3876 pSMB->ParameterCount = pSMB->TotalParameterCount;
3877 if(notify_subdirs)
3878 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3879 pSMB->Reserved2 = 0;
3880 pSMB->CompletionFilter = cpu_to_le32(filter);
3881 pSMB->Fid = netfid; /* file handle always le */
3882 pSMB->ByteCount = 0;
3883
3884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3885 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3886 if (rc) {
3887 cFYI(1, ("Error in Notify = %d", rc));
3888 }
3889 cifs_buf_release(pSMB);
3890 return rc;
3891}
3892#ifdef CONFIG_CIFS_XATTR
3893ssize_t
3894CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3895 const unsigned char *searchName,
3896 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07003897 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898{
3899 /* BB assumes one setup word */
3900 TRANSACTION2_QPI_REQ *pSMB = NULL;
3901 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3902 int rc = 0;
3903 int bytes_returned;
3904 int name_len;
3905 struct fea * temp_fea;
3906 char * temp_ptr;
3907 __u16 params, byte_count;
3908
3909 cFYI(1, ("In Query All EAs path %s", searchName));
3910QAllEAsRetry:
3911 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3912 (void **) &pSMBr);
3913 if (rc)
3914 return rc;
3915
3916 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3917 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003918 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003919 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 name_len++; /* trailing null */
3921 name_len *= 2;
3922 } else { /* BB improve the check for buffer overruns BB */
3923 name_len = strnlen(searchName, PATH_MAX);
3924 name_len++; /* trailing null */
3925 strncpy(pSMB->FileName, searchName, name_len);
3926 }
3927
3928 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3929 pSMB->TotalDataCount = 0;
3930 pSMB->MaxParameterCount = cpu_to_le16(2);
3931 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3932 pSMB->MaxSetupCount = 0;
3933 pSMB->Reserved = 0;
3934 pSMB->Flags = 0;
3935 pSMB->Timeout = 0;
3936 pSMB->Reserved2 = 0;
3937 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3938 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3939 pSMB->DataCount = 0;
3940 pSMB->DataOffset = 0;
3941 pSMB->SetupCount = 1;
3942 pSMB->Reserved3 = 0;
3943 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3944 byte_count = params + 1 /* pad */ ;
3945 pSMB->TotalParameterCount = cpu_to_le16(params);
3946 pSMB->ParameterCount = pSMB->TotalParameterCount;
3947 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3948 pSMB->Reserved4 = 0;
3949 pSMB->hdr.smb_buf_length += byte_count;
3950 pSMB->ByteCount = cpu_to_le16(byte_count);
3951
3952 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3953 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3954 if (rc) {
3955 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3956 } else { /* decode response */
3957 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3958
3959 /* BB also check enough total bytes returned */
3960 /* BB we need to improve the validity checking
3961 of these trans2 responses */
3962 if (rc || (pSMBr->ByteCount < 4))
3963 rc = -EIO; /* bad smb */
3964 /* else if (pFindData){
3965 memcpy((char *) pFindData,
3966 (char *) &pSMBr->hdr.Protocol +
3967 data_offset, kl);
3968 }*/ else {
3969 /* check that length of list is not more than bcc */
3970 /* check that each entry does not go beyond length
3971 of list */
3972 /* check that each element of each entry does not
3973 go beyond end of list */
3974 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3975 struct fealist * ea_response_data;
3976 rc = 0;
3977 /* validate_trans2_offsets() */
3978 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
3979 ea_response_data = (struct fealist *)
3980 (((char *) &pSMBr->hdr.Protocol) +
3981 data_offset);
3982 name_len = le32_to_cpu(ea_response_data->list_len);
3983 cFYI(1,("ea length %d", name_len));
3984 if(name_len <= 8) {
3985 /* returned EA size zeroed at top of function */
3986 cFYI(1,("empty EA list returned from server"));
3987 } else {
3988 /* account for ea list len */
3989 name_len -= 4;
3990 temp_fea = ea_response_data->list;
3991 temp_ptr = (char *)temp_fea;
3992 while(name_len > 0) {
3993 __u16 value_len;
3994 name_len -= 4;
3995 temp_ptr += 4;
3996 rc += temp_fea->name_len;
3997 /* account for prefix user. and trailing null */
3998 rc = rc + 5 + 1;
3999 if(rc<(int)buf_size) {
4000 memcpy(EAData,"user.",5);
4001 EAData+=5;
4002 memcpy(EAData,temp_ptr,temp_fea->name_len);
4003 EAData+=temp_fea->name_len;
4004 /* null terminate name */
4005 *EAData = 0;
4006 EAData = EAData + 1;
4007 } else if(buf_size == 0) {
4008 /* skip copy - calc size only */
4009 } else {
4010 /* stop before overrun buffer */
4011 rc = -ERANGE;
4012 break;
4013 }
4014 name_len -= temp_fea->name_len;
4015 temp_ptr += temp_fea->name_len;
4016 /* account for trailing null */
4017 name_len--;
4018 temp_ptr++;
4019 value_len = le16_to_cpu(temp_fea->value_len);
4020 name_len -= value_len;
4021 temp_ptr += value_len;
4022 /* BB check that temp_ptr is still within smb BB*/
4023 /* no trailing null to account for in value len */
4024 /* go on to next EA */
4025 temp_fea = (struct fea *)temp_ptr;
4026 }
4027 }
4028 }
4029 }
4030 if (pSMB)
4031 cifs_buf_release(pSMB);
4032 if (rc == -EAGAIN)
4033 goto QAllEAsRetry;
4034
4035 return (ssize_t)rc;
4036}
4037
4038ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4039 const unsigned char * searchName,const unsigned char * ea_name,
4040 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004041 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042{
4043 TRANSACTION2_QPI_REQ *pSMB = NULL;
4044 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4045 int rc = 0;
4046 int bytes_returned;
4047 int name_len;
4048 struct fea * temp_fea;
4049 char * temp_ptr;
4050 __u16 params, byte_count;
4051
4052 cFYI(1, ("In Query EA path %s", searchName));
4053QEARetry:
4054 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4055 (void **) &pSMBr);
4056 if (rc)
4057 return rc;
4058
4059 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4060 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004061 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004062 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 name_len++; /* trailing null */
4064 name_len *= 2;
4065 } else { /* BB improve the check for buffer overruns BB */
4066 name_len = strnlen(searchName, PATH_MAX);
4067 name_len++; /* trailing null */
4068 strncpy(pSMB->FileName, searchName, name_len);
4069 }
4070
4071 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4072 pSMB->TotalDataCount = 0;
4073 pSMB->MaxParameterCount = cpu_to_le16(2);
4074 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4075 pSMB->MaxSetupCount = 0;
4076 pSMB->Reserved = 0;
4077 pSMB->Flags = 0;
4078 pSMB->Timeout = 0;
4079 pSMB->Reserved2 = 0;
4080 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4081 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4082 pSMB->DataCount = 0;
4083 pSMB->DataOffset = 0;
4084 pSMB->SetupCount = 1;
4085 pSMB->Reserved3 = 0;
4086 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4087 byte_count = params + 1 /* pad */ ;
4088 pSMB->TotalParameterCount = cpu_to_le16(params);
4089 pSMB->ParameterCount = pSMB->TotalParameterCount;
4090 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4091 pSMB->Reserved4 = 0;
4092 pSMB->hdr.smb_buf_length += byte_count;
4093 pSMB->ByteCount = cpu_to_le16(byte_count);
4094
4095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4097 if (rc) {
4098 cFYI(1, ("Send error in Query EA = %d", rc));
4099 } else { /* decode response */
4100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4101
4102 /* BB also check enough total bytes returned */
4103 /* BB we need to improve the validity checking
4104 of these trans2 responses */
4105 if (rc || (pSMBr->ByteCount < 4))
4106 rc = -EIO; /* bad smb */
4107 /* else if (pFindData){
4108 memcpy((char *) pFindData,
4109 (char *) &pSMBr->hdr.Protocol +
4110 data_offset, kl);
4111 }*/ else {
4112 /* check that length of list is not more than bcc */
4113 /* check that each entry does not go beyond length
4114 of list */
4115 /* check that each element of each entry does not
4116 go beyond end of list */
4117 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4118 struct fealist * ea_response_data;
4119 rc = -ENODATA;
4120 /* validate_trans2_offsets() */
4121 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4122 ea_response_data = (struct fealist *)
4123 (((char *) &pSMBr->hdr.Protocol) +
4124 data_offset);
4125 name_len = le32_to_cpu(ea_response_data->list_len);
4126 cFYI(1,("ea length %d", name_len));
4127 if(name_len <= 8) {
4128 /* returned EA size zeroed at top of function */
4129 cFYI(1,("empty EA list returned from server"));
4130 } else {
4131 /* account for ea list len */
4132 name_len -= 4;
4133 temp_fea = ea_response_data->list;
4134 temp_ptr = (char *)temp_fea;
4135 /* loop through checking if we have a matching
4136 name and then return the associated value */
4137 while(name_len > 0) {
4138 __u16 value_len;
4139 name_len -= 4;
4140 temp_ptr += 4;
4141 value_len = le16_to_cpu(temp_fea->value_len);
4142 /* BB validate that value_len falls within SMB,
4143 even though maximum for name_len is 255 */
4144 if(memcmp(temp_fea->name,ea_name,
4145 temp_fea->name_len) == 0) {
4146 /* found a match */
4147 rc = value_len;
4148 /* account for prefix user. and trailing null */
4149 if(rc<=(int)buf_size) {
4150 memcpy(ea_value,
4151 temp_fea->name+temp_fea->name_len+1,
4152 rc);
4153 /* ea values, unlike ea names,
4154 are not null terminated */
4155 } else if(buf_size == 0) {
4156 /* skip copy - calc size only */
4157 } else {
4158 /* stop before overrun buffer */
4159 rc = -ERANGE;
4160 }
4161 break;
4162 }
4163 name_len -= temp_fea->name_len;
4164 temp_ptr += temp_fea->name_len;
4165 /* account for trailing null */
4166 name_len--;
4167 temp_ptr++;
4168 name_len -= value_len;
4169 temp_ptr += value_len;
4170 /* no trailing null to account for in value len */
4171 /* go on to next EA */
4172 temp_fea = (struct fea *)temp_ptr;
4173 }
4174 }
4175 }
4176 }
4177 if (pSMB)
4178 cifs_buf_release(pSMB);
4179 if (rc == -EAGAIN)
4180 goto QEARetry;
4181
4182 return (ssize_t)rc;
4183}
4184
4185int
4186CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4187 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004188 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4189 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190{
4191 struct smb_com_transaction2_spi_req *pSMB = NULL;
4192 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4193 struct fealist *parm_data;
4194 int name_len;
4195 int rc = 0;
4196 int bytes_returned = 0;
4197 __u16 params, param_offset, byte_count, offset, count;
4198
4199 cFYI(1, ("In SetEA"));
4200SetEARetry:
4201 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4202 (void **) &pSMBr);
4203 if (rc)
4204 return rc;
4205
4206 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4207 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004208 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004209 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 name_len++; /* trailing null */
4211 name_len *= 2;
4212 } else { /* BB improve the check for buffer overruns BB */
4213 name_len = strnlen(fileName, PATH_MAX);
4214 name_len++; /* trailing null */
4215 strncpy(pSMB->FileName, fileName, name_len);
4216 }
4217
4218 params = 6 + name_len;
4219
4220 /* done calculating parms using name_len of file name,
4221 now use name_len to calculate length of ea name
4222 we are going to create in the inode xattrs */
4223 if(ea_name == NULL)
4224 name_len = 0;
4225 else
4226 name_len = strnlen(ea_name,255);
4227
4228 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4229 pSMB->MaxParameterCount = cpu_to_le16(2);
4230 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4231 pSMB->MaxSetupCount = 0;
4232 pSMB->Reserved = 0;
4233 pSMB->Flags = 0;
4234 pSMB->Timeout = 0;
4235 pSMB->Reserved2 = 0;
4236 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4237 InformationLevel) - 4;
4238 offset = param_offset + params;
4239 pSMB->InformationLevel =
4240 cpu_to_le16(SMB_SET_FILE_EA);
4241
4242 parm_data =
4243 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4244 offset);
4245 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4246 pSMB->DataOffset = cpu_to_le16(offset);
4247 pSMB->SetupCount = 1;
4248 pSMB->Reserved3 = 0;
4249 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4250 byte_count = 3 /* pad */ + params + count;
4251 pSMB->DataCount = cpu_to_le16(count);
4252 parm_data->list_len = cpu_to_le32(count);
4253 parm_data->list[0].EA_flags = 0;
4254 /* we checked above that name len is less than 255 */
4255 parm_data->list[0].name_len = (__u8)name_len;;
4256 /* EA names are always ASCII */
4257 if(ea_name)
4258 strncpy(parm_data->list[0].name,ea_name,name_len);
4259 parm_data->list[0].name[name_len] = 0;
4260 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4261 /* caller ensures that ea_value_len is less than 64K but
4262 we need to ensure that it fits within the smb */
4263
4264 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4265 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4266 if(ea_value_len)
4267 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4268
4269 pSMB->TotalDataCount = pSMB->DataCount;
4270 pSMB->ParameterCount = cpu_to_le16(params);
4271 pSMB->TotalParameterCount = pSMB->ParameterCount;
4272 pSMB->Reserved4 = 0;
4273 pSMB->hdr.smb_buf_length += byte_count;
4274 pSMB->ByteCount = cpu_to_le16(byte_count);
4275 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4276 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4277 if (rc) {
4278 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4279 }
4280
4281 cifs_buf_release(pSMB);
4282
4283 if (rc == -EAGAIN)
4284 goto SetEARetry;
4285
4286 return rc;
4287}
4288
4289#endif