blob: 459320222cf7d5d3ff77a183d0bf1a8303f42dee [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"));
Steve French4a6d87f2005-08-13 08:15:54 -0700418 server->secMode &= ~(SECMODE_SIGN_ENABLED |
419 SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 } else if(sign_CIFS_PDUs == 1) {
421 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French4a6d87f2005-08-13 08:15:54 -0700422 server->secMode &= ~(SECMODE_SIGN_ENABLED |
423 SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 }
425
426 }
Steve French4a6d87f2005-08-13 08:15:54 -0700427 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 return rc;
429}
430
431int
432CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
433{
434 struct smb_hdr *smb_buffer;
435 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
436 int rc = 0;
437 int length;
438
439 cFYI(1, ("In tree disconnect"));
440 /*
441 * If last user of the connection and
442 * connection alive - disconnect it
443 * If this is the last connection on the server session disconnect it
444 * (and inside session disconnect we should check if tcp socket needs
445 * to be freed and kernel thread woken up).
446 */
447 if (tcon)
448 down(&tcon->tconSem);
449 else
450 return -EIO;
451
452 atomic_dec(&tcon->useCount);
453 if (atomic_read(&tcon->useCount) > 0) {
454 up(&tcon->tconSem);
455 return -EBUSY;
456 }
457
458 /* No need to return error on this operation if tid invalidated and
459 closed on server already e.g. due to tcp session crashing */
460 if(tcon->tidStatus == CifsNeedReconnect) {
461 up(&tcon->tconSem);
462 return 0;
463 }
464
465 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
466 up(&tcon->tconSem);
467 return -EIO;
468 }
Steve French09d1db52005-04-28 22:41:08 -0700469 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
470 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if (rc) {
472 up(&tcon->tconSem);
473 return rc;
474 } else {
475 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
478 &length, 0);
479 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700480 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482 if (smb_buffer)
483 cifs_small_buf_release(smb_buffer);
484 up(&tcon->tconSem);
485
486 /* No need to return error on this operation if tid invalidated and
487 closed on server already e.g. due to tcp session crashing */
488 if (rc == -EAGAIN)
489 rc = 0;
490
491 return rc;
492}
493
494int
495CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
496{
497 struct smb_hdr *smb_buffer_response;
498 LOGOFF_ANDX_REQ *pSMB;
499 int rc = 0;
500 int length;
501
502 cFYI(1, ("In SMBLogoff for session disconnect"));
503 if (ses)
504 down(&ses->sesSem);
505 else
506 return -EIO;
507
508 atomic_dec(&ses->inUse);
509 if (atomic_read(&ses->inUse) > 0) {
510 up(&ses->sesSem);
511 return -EBUSY;
512 }
513 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
514 if (rc) {
515 up(&ses->sesSem);
516 return rc;
517 }
518
519 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
520
521 if(ses->server) {
522 if(ses->server->secMode &
523 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
524 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
525 }
526
527 pSMB->hdr.Uid = ses->Suid;
528
529 pSMB->AndXCommand = 0xFF;
530 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
531 smb_buffer_response, &length, 0);
532 if (ses->server) {
533 atomic_dec(&ses->server->socketUseCount);
534 if (atomic_read(&ses->server->socketUseCount) == 0) {
535 spin_lock(&GlobalMid_Lock);
536 ses->server->tcpStatus = CifsExiting;
537 spin_unlock(&GlobalMid_Lock);
538 rc = -ESHUTDOWN;
539 }
540 }
Steve French4a6d87f2005-08-13 08:15:54 -0700541 up(&ses->sesSem)
542 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
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;
Steve Frencheda3c022005-07-21 15:20:28 -0700741 /* set file as system file if special file such
742 as fifo and server expecting SFU style and
743 no Unix extensions */
744 if(create_options & CREATE_OPTION_SPECIAL)
745 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
746 else
747 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 /* XP does not handle ATTR_POSIX_SEMANTICS */
749 /* but it helps speed up case sensitive checks for other
750 servers such as Samba */
751 if (tcon->ses->capabilities & CAP_UNIX)
752 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
753
754 /* if ((omode & S_IWUGO) == 0)
755 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
756 /* Above line causes problems due to vfs splitting create into two
757 pieces - need to set mode after file created not while it is
758 being created */
759 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
760 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -0700761 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700762 /* BB Expirement with various impersonation levels and verify */
763 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 pSMB->SecurityFlags =
765 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
766
767 count += name_len;
768 pSMB->hdr.smb_buf_length += count;
769
770 pSMB->ByteCount = cpu_to_le16(count);
771 /* long_op set to 1 to allow for oplock break timeouts */
772 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
773 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
774 if (rc) {
775 cFYI(1, ("Error in Open = %d", rc));
776 } else {
Steve French09d1db52005-04-28 22:41:08 -0700777 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 *netfid = pSMBr->Fid; /* cifs fid stays in le */
779 /* Let caller know file was created so we can set the mode. */
780 /* Do we care about the CreateAction in any other cases? */
781 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
782 *pOplock |= CIFS_CREATE_ACTION;
783 if(pfile_info) {
784 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
785 36 /* CreationTime to Attributes */);
786 /* the file_info buf is endian converted by caller */
787 pfile_info->AllocationSize = pSMBr->AllocationSize;
788 pfile_info->EndOfFile = pSMBr->EndOfFile;
789 pfile_info->NumberOfLinks = cpu_to_le32(1);
790 }
791
792#ifdef CONFIG_CIFS_STATS
793 atomic_inc(&tcon->num_opens);
794#endif
795 }
796 cifs_buf_release(pSMB);
797 if (rc == -EAGAIN)
798 goto openRetry;
799 return rc;
800}
801
802/* If no buffer passed in, then caller wants to do the copy
803 as in the case of readpages so the SMB buffer must be
804 freed by the caller */
805
806int
807CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
808 const int netfid, const unsigned int count,
809 const __u64 lseek, unsigned int *nbytes, char **buf)
810{
811 int rc = -EACCES;
812 READ_REQ *pSMB = NULL;
813 READ_RSP *pSMBr = NULL;
814 char *pReadData = NULL;
815 int bytes_returned;
816
817 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
818
819 *nbytes = 0;
820 rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
821 (void **) &pSMBr);
822 if (rc)
823 return rc;
824
825 /* tcon and ses pointer are checked in smb_init */
826 if (tcon->ses->server == NULL)
827 return -ECONNABORTED;
828
829 pSMB->AndXCommand = 0xFF; /* none */
830 pSMB->Fid = netfid;
831 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
832 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
833 pSMB->Remaining = 0;
834 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
835 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
836 pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
837
838 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
839 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
840 if (rc) {
841 cERROR(1, ("Send error in read = %d", rc));
842 } else {
843 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
844 data_length = data_length << 16;
845 data_length += le16_to_cpu(pSMBr->DataLength);
846 *nbytes = data_length;
847
848 /*check that DataLength would not go beyond end of SMB */
849 if ((data_length > CIFSMaxBufSize)
850 || (data_length > count)) {
851 cFYI(1,("bad length %d for count %d",data_length,count));
852 rc = -EIO;
853 *nbytes = 0;
854 } else {
855 pReadData =
856 (char *) (&pSMBr->hdr.Protocol) +
857 le16_to_cpu(pSMBr->DataOffset);
858/* if(rc = copy_to_user(buf, pReadData, data_length)) {
859 cERROR(1,("Faulting on read rc = %d",rc));
860 rc = -EFAULT;
861 }*/ /* can not use copy_to_user when using page cache*/
862 if(*buf)
863 memcpy(*buf,pReadData,data_length);
864 }
865 }
866 if(*buf)
867 cifs_buf_release(pSMB);
868 else
869 *buf = (char *)pSMB;
870
871 /* Note: On -EAGAIN error only caller can retry on handle based calls
872 since file handle passed in no longer valid */
873 return rc;
874}
875
876int
877CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
878 const int netfid, const unsigned int count,
879 const __u64 offset, unsigned int *nbytes, const char *buf,
880 const char __user * ubuf, const int long_op)
881{
882 int rc = -EACCES;
883 WRITE_REQ *pSMB = NULL;
884 WRITE_RSP *pSMBr = NULL;
885 int bytes_returned;
886 __u32 bytes_sent;
887 __u16 byte_count;
888
889 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
890 rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
891 (void **) &pSMBr);
892 if (rc)
893 return rc;
894 /* tcon and ses pointer are checked in smb_init */
895 if (tcon->ses->server == NULL)
896 return -ECONNABORTED;
897
898 pSMB->AndXCommand = 0xFF; /* none */
899 pSMB->Fid = netfid;
900 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
901 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
902 pSMB->Reserved = 0xFFFFFFFF;
903 pSMB->WriteMode = 0;
904 pSMB->Remaining = 0;
905
906 /* Can increase buffer size if buffer is big enough in some cases - ie we
907 can send more if LARGE_WRITE_X capability returned by the server and if
908 our buffer is big enough or if we convert to iovecs on socket writes
909 and eliminate the copy to the CIFS buffer */
910 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
911 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
912 } else {
913 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
914 & ~0xFF;
915 }
916
917 if (bytes_sent > count)
918 bytes_sent = count;
919 pSMB->DataOffset =
920 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
921 if(buf)
922 memcpy(pSMB->Data,buf,bytes_sent);
923 else if(ubuf) {
924 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
925 cifs_buf_release(pSMB);
926 return -EFAULT;
927 }
928 } else {
929 /* No buffer */
930 cifs_buf_release(pSMB);
931 return -EINVAL;
932 }
933
934 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
935 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
936 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
937 pSMB->hdr.smb_buf_length += bytes_sent+1;
938 pSMB->ByteCount = cpu_to_le16(byte_count);
939
940 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
941 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
942 if (rc) {
943 cFYI(1, ("Send error in write = %d", rc));
944 *nbytes = 0;
945 } else {
946 *nbytes = le16_to_cpu(pSMBr->CountHigh);
947 *nbytes = (*nbytes) << 16;
948 *nbytes += le16_to_cpu(pSMBr->Count);
949 }
950
951 cifs_buf_release(pSMB);
952
953 /* Note: On -EAGAIN error only caller can retry on handle based calls
954 since file handle passed in no longer valid */
955
956 return rc;
957}
958
959#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500960int
961CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 const int netfid, const unsigned int count,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500963 const __u64 offset, unsigned int *nbytes, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 const int long_op)
965{
966 int rc = -EACCES;
967 WRITE_REQ *pSMB = NULL;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500968 int bytes_returned;
969 int smb_hdr_len;
970 __u32 bytes_sent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 __u16 byte_count;
972
Steve French0c0ff092005-06-23 19:31:17 -0500973 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (rc)
976 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 /* tcon and ses pointer are checked in smb_init */
978 if (tcon->ses->server == NULL)
979 return -ECONNABORTED;
980
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500981 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 pSMB->Fid = netfid;
983 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
984 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
985 pSMB->Reserved = 0xFFFFFFFF;
986 pSMB->WriteMode = 0;
987 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500988
989 /* Can increase buffer size if buffer is big enough in some cases - ie
990 can send more if LARGE_WRITE_X capability returned by the server and if
991 our buffer is big enough or if we convert to iovecs on socket writes
992 and eliminate the copy to the CIFS buffer */
993 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
994 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
995 } else {
996 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
997 & ~0xFF;
998 }
999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (bytes_sent > count)
1001 bytes_sent = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 pSMB->DataOffset =
1003 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1004
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001005 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1006 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1007 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1008 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1009 pSMB->hdr.smb_buf_length += bytes_sent+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 pSMB->ByteCount = cpu_to_le16(byte_count);
1011
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001012 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1013 buf, bytes_sent, &bytes_returned, long_op);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 if (rc) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001015 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001017 } else {
1018 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1019 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1020 *nbytes = (*nbytes) << 16;
1021 *nbytes += le16_to_cpu(pSMBr->Count);
1022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 cifs_small_buf_release(pSMB);
1025
1026 /* Note: On -EAGAIN error only caller can retry on handle based calls
1027 since file handle passed in no longer valid */
1028
1029 return rc;
1030}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001031
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033#endif /* CIFS_EXPERIMENTAL */
1034
1035int
1036CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1037 const __u16 smb_file_id, const __u64 len,
1038 const __u64 offset, const __u32 numUnlock,
1039 const __u32 numLock, const __u8 lockType, const int waitFlag)
1040{
1041 int rc = 0;
1042 LOCK_REQ *pSMB = NULL;
1043 LOCK_RSP *pSMBr = NULL;
1044 int bytes_returned;
1045 int timeout = 0;
1046 __u16 count;
1047
1048 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001049 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 if (rc)
1052 return rc;
1053
Steve French46810cb2005-04-28 22:41:09 -07001054 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1057 timeout = -1; /* no response expected */
1058 pSMB->Timeout = 0;
1059 } else if (waitFlag == TRUE) {
1060 timeout = 3; /* blocking operation, no timeout */
1061 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1062 } else {
1063 pSMB->Timeout = 0;
1064 }
1065
1066 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1067 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1068 pSMB->LockType = lockType;
1069 pSMB->AndXCommand = 0xFF; /* none */
1070 pSMB->Fid = smb_file_id; /* netfid stays le */
1071
1072 if((numLock != 0) || (numUnlock != 0)) {
1073 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1074 /* BB where to store pid high? */
1075 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1076 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1077 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1078 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1079 count = sizeof(LOCKING_ANDX_RANGE);
1080 } else {
1081 /* oplock break */
1082 count = 0;
1083 }
1084 pSMB->hdr.smb_buf_length += count;
1085 pSMB->ByteCount = cpu_to_le16(count);
1086
1087 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1088 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1089
1090 if (rc) {
1091 cFYI(1, ("Send error in Lock = %d", rc));
1092 }
Steve French46810cb2005-04-28 22:41:09 -07001093 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095 /* Note: On -EAGAIN error only caller can retry on handle based calls
1096 since file handle passed in no longer valid */
1097 return rc;
1098}
1099
1100int
1101CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1102{
1103 int rc = 0;
1104 CLOSE_REQ *pSMB = NULL;
1105 CLOSE_RSP *pSMBr = NULL;
1106 int bytes_returned;
1107 cFYI(1, ("In CIFSSMBClose"));
1108
1109/* do not retry on dead session on close */
1110 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1111 if(rc == -EAGAIN)
1112 return 0;
1113 if (rc)
1114 return rc;
1115
1116 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1117
1118 pSMB->FileID = (__u16) smb_file_id;
1119 pSMB->LastWriteTime = 0;
1120 pSMB->ByteCount = 0;
1121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1123 if (rc) {
1124 if(rc!=-EINTR) {
1125 /* EINTR is expected when user ctl-c to kill app */
1126 cERROR(1, ("Send error in Close = %d", rc));
1127 }
1128 }
1129
1130 cifs_small_buf_release(pSMB);
1131
1132 /* Since session is dead, file will be closed on server already */
1133 if(rc == -EAGAIN)
1134 rc = 0;
1135
1136 return rc;
1137}
1138
1139int
1140CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1141 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001142 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 int rc = 0;
1145 RENAME_REQ *pSMB = NULL;
1146 RENAME_RSP *pSMBr = NULL;
1147 int bytes_returned;
1148 int name_len, name_len2;
1149 __u16 count;
1150
1151 cFYI(1, ("In CIFSSMBRename"));
1152renameRetry:
1153 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1154 (void **) &pSMBr);
1155 if (rc)
1156 return rc;
1157
1158 pSMB->BufferFormat = 0x04;
1159 pSMB->SearchAttributes =
1160 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1161 ATTR_DIRECTORY);
1162
1163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1164 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001165 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001166 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 name_len++; /* trailing null */
1168 name_len *= 2;
1169 pSMB->OldFileName[name_len] = 0x04; /* pad */
1170 /* protocol requires ASCII signature byte on Unicode string */
1171 pSMB->OldFileName[name_len + 1] = 0x00;
1172 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001173 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001174 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1176 name_len2 *= 2; /* convert to bytes */
1177 } else { /* BB improve the check for buffer overruns BB */
1178 name_len = strnlen(fromName, PATH_MAX);
1179 name_len++; /* trailing null */
1180 strncpy(pSMB->OldFileName, fromName, name_len);
1181 name_len2 = strnlen(toName, PATH_MAX);
1182 name_len2++; /* trailing null */
1183 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1184 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1185 name_len2++; /* trailing null */
1186 name_len2++; /* signature byte */
1187 }
1188
1189 count = 1 /* 1st signature byte */ + name_len + name_len2;
1190 pSMB->hdr.smb_buf_length += count;
1191 pSMB->ByteCount = cpu_to_le16(count);
1192
1193 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1194 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1195 if (rc) {
1196 cFYI(1, ("Send error in rename = %d", rc));
1197 }
1198
1199#ifdef CONFIG_CIFS_STATS
1200 else {
1201 atomic_inc(&tcon->num_renames);
1202 }
1203#endif
1204
1205 cifs_buf_release(pSMB);
1206
1207 if (rc == -EAGAIN)
1208 goto renameRetry;
1209
1210 return rc;
1211}
1212
1213int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001214 int netfid, char * target_name,
1215 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216{
1217 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1218 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1219 struct set_file_rename * rename_info;
1220 char *data_offset;
1221 char dummy_string[30];
1222 int rc = 0;
1223 int bytes_returned = 0;
1224 int len_of_str;
1225 __u16 params, param_offset, offset, count, byte_count;
1226
1227 cFYI(1, ("Rename to File by handle"));
1228 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1229 (void **) &pSMBr);
1230 if (rc)
1231 return rc;
1232
1233 params = 6;
1234 pSMB->MaxSetupCount = 0;
1235 pSMB->Reserved = 0;
1236 pSMB->Flags = 0;
1237 pSMB->Timeout = 0;
1238 pSMB->Reserved2 = 0;
1239 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1240 offset = param_offset + params;
1241
1242 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1243 rename_info = (struct set_file_rename *) data_offset;
1244 pSMB->MaxParameterCount = cpu_to_le16(2);
1245 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1246 pSMB->SetupCount = 1;
1247 pSMB->Reserved3 = 0;
1248 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1249 byte_count = 3 /* pad */ + params;
1250 pSMB->ParameterCount = cpu_to_le16(params);
1251 pSMB->TotalParameterCount = pSMB->ParameterCount;
1252 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1253 pSMB->DataOffset = cpu_to_le16(offset);
1254 /* construct random name ".cifs_tmp<inodenum><mid>" */
1255 rename_info->overwrite = cpu_to_le32(1);
1256 rename_info->root_fid = 0;
1257 /* unicode only call */
1258 if(target_name == NULL) {
1259 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001260 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001261 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001263 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001264 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 }
1266 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1267 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1268 byte_count += count;
1269 pSMB->DataCount = cpu_to_le16(count);
1270 pSMB->TotalDataCount = pSMB->DataCount;
1271 pSMB->Fid = netfid;
1272 pSMB->InformationLevel =
1273 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1274 pSMB->Reserved4 = 0;
1275 pSMB->hdr.smb_buf_length += byte_count;
1276 pSMB->ByteCount = cpu_to_le16(byte_count);
1277 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1278 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1279 if (rc) {
1280 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1281 }
1282#ifdef CONFIG_CIFS_STATS
1283 else {
1284 atomic_inc(&pTcon->num_t2renames);
1285 }
1286#endif
1287 cifs_buf_release(pSMB);
1288
1289 /* Note: On -EAGAIN error only caller can retry on handle based calls
1290 since file handle passed in no longer valid */
1291
1292 return rc;
1293}
1294
1295int
1296CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1297 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001298 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299{
1300 int rc = 0;
1301 COPY_REQ *pSMB = NULL;
1302 COPY_RSP *pSMBr = NULL;
1303 int bytes_returned;
1304 int name_len, name_len2;
1305 __u16 count;
1306
1307 cFYI(1, ("In CIFSSMBCopy"));
1308copyRetry:
1309 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1310 (void **) &pSMBr);
1311 if (rc)
1312 return rc;
1313
1314 pSMB->BufferFormat = 0x04;
1315 pSMB->Tid2 = target_tid;
1316
1317 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1318
1319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001320 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001321 fromName, PATH_MAX, nls_codepage,
1322 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 name_len++; /* trailing null */
1324 name_len *= 2;
1325 pSMB->OldFileName[name_len] = 0x04; /* pad */
1326 /* protocol requires ASCII signature byte on Unicode string */
1327 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001328 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001329 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1331 name_len2 *= 2; /* convert to bytes */
1332 } else { /* BB improve the check for buffer overruns BB */
1333 name_len = strnlen(fromName, PATH_MAX);
1334 name_len++; /* trailing null */
1335 strncpy(pSMB->OldFileName, fromName, name_len);
1336 name_len2 = strnlen(toName, PATH_MAX);
1337 name_len2++; /* trailing null */
1338 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1339 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1340 name_len2++; /* trailing null */
1341 name_len2++; /* signature byte */
1342 }
1343
1344 count = 1 /* 1st signature byte */ + name_len + name_len2;
1345 pSMB->hdr.smb_buf_length += count;
1346 pSMB->ByteCount = cpu_to_le16(count);
1347
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1350 if (rc) {
1351 cFYI(1, ("Send error in copy = %d with %d files copied",
1352 rc, le16_to_cpu(pSMBr->CopyCount)));
1353 }
1354 if (pSMB)
1355 cifs_buf_release(pSMB);
1356
1357 if (rc == -EAGAIN)
1358 goto copyRetry;
1359
1360 return rc;
1361}
1362
1363int
1364CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1365 const char *fromName, const char *toName,
1366 const struct nls_table *nls_codepage)
1367{
1368 TRANSACTION2_SPI_REQ *pSMB = NULL;
1369 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1370 char *data_offset;
1371 int name_len;
1372 int name_len_target;
1373 int rc = 0;
1374 int bytes_returned = 0;
1375 __u16 params, param_offset, offset, byte_count;
1376
1377 cFYI(1, ("In Symlink Unix style"));
1378createSymLinkRetry:
1379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1380 (void **) &pSMBr);
1381 if (rc)
1382 return rc;
1383
1384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1385 name_len =
1386 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1387 /* find define for this maxpathcomponent */
1388 , nls_codepage);
1389 name_len++; /* trailing null */
1390 name_len *= 2;
1391
1392 } else { /* BB improve the check for buffer overruns BB */
1393 name_len = strnlen(fromName, PATH_MAX);
1394 name_len++; /* trailing null */
1395 strncpy(pSMB->FileName, fromName, name_len);
1396 }
1397 params = 6 + name_len;
1398 pSMB->MaxSetupCount = 0;
1399 pSMB->Reserved = 0;
1400 pSMB->Flags = 0;
1401 pSMB->Timeout = 0;
1402 pSMB->Reserved2 = 0;
1403 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1404 InformationLevel) - 4;
1405 offset = param_offset + params;
1406
1407 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1408 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1409 name_len_target =
1410 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1411 /* find define for this maxpathcomponent */
1412 , nls_codepage);
1413 name_len_target++; /* trailing null */
1414 name_len_target *= 2;
1415 } else { /* BB improve the check for buffer overruns BB */
1416 name_len_target = strnlen(toName, PATH_MAX);
1417 name_len_target++; /* trailing null */
1418 strncpy(data_offset, toName, name_len_target);
1419 }
1420
1421 pSMB->MaxParameterCount = cpu_to_le16(2);
1422 /* BB find exact max on data count below from sess */
1423 pSMB->MaxDataCount = cpu_to_le16(1000);
1424 pSMB->SetupCount = 1;
1425 pSMB->Reserved3 = 0;
1426 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1427 byte_count = 3 /* pad */ + params + name_len_target;
1428 pSMB->DataCount = cpu_to_le16(name_len_target);
1429 pSMB->ParameterCount = cpu_to_le16(params);
1430 pSMB->TotalDataCount = pSMB->DataCount;
1431 pSMB->TotalParameterCount = pSMB->ParameterCount;
1432 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1433 pSMB->DataOffset = cpu_to_le16(offset);
1434 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1435 pSMB->Reserved4 = 0;
1436 pSMB->hdr.smb_buf_length += byte_count;
1437 pSMB->ByteCount = cpu_to_le16(byte_count);
1438 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1439 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1440 if (rc) {
1441 cFYI(1,
1442 ("Send error in SetPathInfo (create symlink) = %d",
1443 rc));
1444 }
1445
1446 if (pSMB)
1447 cifs_buf_release(pSMB);
1448
1449 if (rc == -EAGAIN)
1450 goto createSymLinkRetry;
1451
1452 return rc;
1453}
1454
1455int
1456CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1457 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001458 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459{
1460 TRANSACTION2_SPI_REQ *pSMB = NULL;
1461 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1462 char *data_offset;
1463 int name_len;
1464 int name_len_target;
1465 int rc = 0;
1466 int bytes_returned = 0;
1467 __u16 params, param_offset, offset, byte_count;
1468
1469 cFYI(1, ("In Create Hard link Unix style"));
1470createHardLinkRetry:
1471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1472 (void **) &pSMBr);
1473 if (rc)
1474 return rc;
1475
1476 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001477 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001478 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 name_len++; /* trailing null */
1480 name_len *= 2;
1481
1482 } else { /* BB improve the check for buffer overruns BB */
1483 name_len = strnlen(toName, PATH_MAX);
1484 name_len++; /* trailing null */
1485 strncpy(pSMB->FileName, toName, name_len);
1486 }
1487 params = 6 + name_len;
1488 pSMB->MaxSetupCount = 0;
1489 pSMB->Reserved = 0;
1490 pSMB->Flags = 0;
1491 pSMB->Timeout = 0;
1492 pSMB->Reserved2 = 0;
1493 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1494 InformationLevel) - 4;
1495 offset = param_offset + params;
1496
1497 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1498 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1499 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001500 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001501 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 name_len_target++; /* trailing null */
1503 name_len_target *= 2;
1504 } else { /* BB improve the check for buffer overruns BB */
1505 name_len_target = strnlen(fromName, PATH_MAX);
1506 name_len_target++; /* trailing null */
1507 strncpy(data_offset, fromName, name_len_target);
1508 }
1509
1510 pSMB->MaxParameterCount = cpu_to_le16(2);
1511 /* BB find exact max on data count below from sess*/
1512 pSMB->MaxDataCount = cpu_to_le16(1000);
1513 pSMB->SetupCount = 1;
1514 pSMB->Reserved3 = 0;
1515 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1516 byte_count = 3 /* pad */ + params + name_len_target;
1517 pSMB->ParameterCount = cpu_to_le16(params);
1518 pSMB->TotalParameterCount = pSMB->ParameterCount;
1519 pSMB->DataCount = cpu_to_le16(name_len_target);
1520 pSMB->TotalDataCount = pSMB->DataCount;
1521 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1522 pSMB->DataOffset = cpu_to_le16(offset);
1523 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1524 pSMB->Reserved4 = 0;
1525 pSMB->hdr.smb_buf_length += byte_count;
1526 pSMB->ByteCount = cpu_to_le16(byte_count);
1527 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1528 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1529 if (rc) {
1530 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1531 }
1532
1533 cifs_buf_release(pSMB);
1534 if (rc == -EAGAIN)
1535 goto createHardLinkRetry;
1536
1537 return rc;
1538}
1539
1540int
1541CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1542 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001543 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544{
1545 int rc = 0;
1546 NT_RENAME_REQ *pSMB = NULL;
1547 RENAME_RSP *pSMBr = NULL;
1548 int bytes_returned;
1549 int name_len, name_len2;
1550 __u16 count;
1551
1552 cFYI(1, ("In CIFSCreateHardLink"));
1553winCreateHardLinkRetry:
1554
1555 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1556 (void **) &pSMBr);
1557 if (rc)
1558 return rc;
1559
1560 pSMB->SearchAttributes =
1561 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1562 ATTR_DIRECTORY);
1563 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1564 pSMB->ClusterCount = 0;
1565
1566 pSMB->BufferFormat = 0x04;
1567
1568 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1569 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001570 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001571 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 name_len++; /* trailing null */
1573 name_len *= 2;
1574 pSMB->OldFileName[name_len] = 0; /* pad */
1575 pSMB->OldFileName[name_len + 1] = 0x04;
1576 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001577 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001578 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1580 name_len2 *= 2; /* convert to bytes */
1581 } else { /* BB improve the check for buffer overruns BB */
1582 name_len = strnlen(fromName, PATH_MAX);
1583 name_len++; /* trailing null */
1584 strncpy(pSMB->OldFileName, fromName, name_len);
1585 name_len2 = strnlen(toName, PATH_MAX);
1586 name_len2++; /* trailing null */
1587 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1588 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1589 name_len2++; /* trailing null */
1590 name_len2++; /* signature byte */
1591 }
1592
1593 count = 1 /* string type byte */ + name_len + name_len2;
1594 pSMB->hdr.smb_buf_length += count;
1595 pSMB->ByteCount = cpu_to_le16(count);
1596
1597 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1598 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1599 if (rc) {
1600 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1601 }
1602 cifs_buf_release(pSMB);
1603 if (rc == -EAGAIN)
1604 goto winCreateHardLinkRetry;
1605
1606 return rc;
1607}
1608
1609int
1610CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1611 const unsigned char *searchName,
1612 char *symlinkinfo, const int buflen,
1613 const struct nls_table *nls_codepage)
1614{
1615/* SMB_QUERY_FILE_UNIX_LINK */
1616 TRANSACTION2_QPI_REQ *pSMB = NULL;
1617 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1618 int rc = 0;
1619 int bytes_returned;
1620 int name_len;
1621 __u16 params, byte_count;
1622
1623 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1624
1625querySymLinkRetry:
1626 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1627 (void **) &pSMBr);
1628 if (rc)
1629 return rc;
1630
1631 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1632 name_len =
1633 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1634 /* find define for this maxpathcomponent */
1635 , nls_codepage);
1636 name_len++; /* trailing null */
1637 name_len *= 2;
1638 } else { /* BB improve the check for buffer overruns BB */
1639 name_len = strnlen(searchName, PATH_MAX);
1640 name_len++; /* trailing null */
1641 strncpy(pSMB->FileName, searchName, name_len);
1642 }
1643
1644 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1645 pSMB->TotalDataCount = 0;
1646 pSMB->MaxParameterCount = cpu_to_le16(2);
1647 /* BB find exact max data count below from sess structure BB */
1648 pSMB->MaxDataCount = cpu_to_le16(4000);
1649 pSMB->MaxSetupCount = 0;
1650 pSMB->Reserved = 0;
1651 pSMB->Flags = 0;
1652 pSMB->Timeout = 0;
1653 pSMB->Reserved2 = 0;
1654 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1655 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1656 pSMB->DataCount = 0;
1657 pSMB->DataOffset = 0;
1658 pSMB->SetupCount = 1;
1659 pSMB->Reserved3 = 0;
1660 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1661 byte_count = params + 1 /* pad */ ;
1662 pSMB->TotalParameterCount = cpu_to_le16(params);
1663 pSMB->ParameterCount = pSMB->TotalParameterCount;
1664 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1665 pSMB->Reserved4 = 0;
1666 pSMB->hdr.smb_buf_length += byte_count;
1667 pSMB->ByteCount = cpu_to_le16(byte_count);
1668
1669 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1670 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1671 if (rc) {
1672 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1673 } else {
1674 /* decode response */
1675
1676 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1677 if (rc || (pSMBr->ByteCount < 2))
1678 /* BB also check enough total bytes returned */
1679 rc = -EIO; /* bad smb */
1680 else {
1681 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1682 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1683
1684 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1685 name_len = UniStrnlen((wchar_t *) ((char *)
1686 &pSMBr->hdr.Protocol +data_offset),
1687 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001688 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 cifs_strfromUCS_le(symlinkinfo,
1690 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1691 data_offset),
1692 name_len, nls_codepage);
1693 } else {
1694 strncpy(symlinkinfo,
1695 (char *) &pSMBr->hdr.Protocol +
1696 data_offset,
1697 min_t(const int, buflen, count));
1698 }
1699 symlinkinfo[buflen] = 0;
1700 /* just in case so calling code does not go off the end of buffer */
1701 }
1702 }
1703 cifs_buf_release(pSMB);
1704 if (rc == -EAGAIN)
1705 goto querySymLinkRetry;
1706 return rc;
1707}
1708
1709int
1710CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1711 const unsigned char *searchName,
1712 char *symlinkinfo, const int buflen,__u16 fid,
1713 const struct nls_table *nls_codepage)
1714{
1715 int rc = 0;
1716 int bytes_returned;
1717 int name_len;
1718 struct smb_com_transaction_ioctl_req * pSMB;
1719 struct smb_com_transaction_ioctl_rsp * pSMBr;
1720
1721 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1722 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1723 (void **) &pSMBr);
1724 if (rc)
1725 return rc;
1726
1727 pSMB->TotalParameterCount = 0 ;
1728 pSMB->TotalDataCount = 0;
1729 pSMB->MaxParameterCount = cpu_to_le32(2);
1730 /* BB find exact data count max from sess structure BB */
1731 pSMB->MaxDataCount = cpu_to_le32(4000);
1732 pSMB->MaxSetupCount = 4;
1733 pSMB->Reserved = 0;
1734 pSMB->ParameterOffset = 0;
1735 pSMB->DataCount = 0;
1736 pSMB->DataOffset = 0;
1737 pSMB->SetupCount = 4;
1738 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1739 pSMB->ParameterCount = pSMB->TotalParameterCount;
1740 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1741 pSMB->IsFsctl = 1; /* FSCTL */
1742 pSMB->IsRootFlag = 0;
1743 pSMB->Fid = fid; /* file handle always le */
1744 pSMB->ByteCount = 0;
1745
1746 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1747 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1748 if (rc) {
1749 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1750 } else { /* decode response */
1751 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1752 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1753 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1754 /* BB also check enough total bytes returned */
1755 rc = -EIO; /* bad smb */
1756 else {
1757 if(data_count && (data_count < 2048)) {
1758 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1759
1760 struct reparse_data * reparse_buf = (struct reparse_data *)
1761 ((char *)&pSMBr->hdr.Protocol + data_offset);
1762 if((char*)reparse_buf >= end_of_smb) {
1763 rc = -EIO;
1764 goto qreparse_out;
1765 }
1766 if((reparse_buf->LinkNamesBuf +
1767 reparse_buf->TargetNameOffset +
1768 reparse_buf->TargetNameLen) >
1769 end_of_smb) {
1770 cFYI(1,("reparse buf extended beyond SMB"));
1771 rc = -EIO;
1772 goto qreparse_out;
1773 }
1774
1775 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1776 name_len = UniStrnlen((wchar_t *)
1777 (reparse_buf->LinkNamesBuf +
1778 reparse_buf->TargetNameOffset),
1779 min(buflen/2, reparse_buf->TargetNameLen / 2));
1780 cifs_strfromUCS_le(symlinkinfo,
1781 (wchar_t *) (reparse_buf->LinkNamesBuf +
1782 reparse_buf->TargetNameOffset),
1783 name_len, nls_codepage);
1784 } else { /* ASCII names */
1785 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1786 reparse_buf->TargetNameOffset,
1787 min_t(const int, buflen, reparse_buf->TargetNameLen));
1788 }
1789 } else {
1790 rc = -EIO;
1791 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1792 }
1793 symlinkinfo[buflen] = 0; /* just in case so the caller
1794 does not go off the end of the buffer */
1795 cFYI(1,("readlink result - %s ",symlinkinfo));
1796 }
1797 }
1798qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001799 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
1801 /* Note: On -EAGAIN error only caller can retry on handle based calls
1802 since file handle passed in no longer valid */
1803
1804 return rc;
1805}
1806
1807#ifdef CONFIG_CIFS_POSIX
1808
1809/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1810static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1811{
1812 /* u8 cifs fields do not need le conversion */
1813 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1814 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1815 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1816 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1817
1818 return;
1819}
1820
1821/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07001822static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1823 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824{
1825 int size = 0;
1826 int i;
1827 __u16 count;
1828 struct cifs_posix_ace * pACE;
1829 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1830 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1831
1832 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1833 return -EOPNOTSUPP;
1834
1835 if(acl_type & ACL_TYPE_ACCESS) {
1836 count = le16_to_cpu(cifs_acl->access_entry_count);
1837 pACE = &cifs_acl->ace_array[0];
1838 size = sizeof(struct cifs_posix_acl);
1839 size += sizeof(struct cifs_posix_ace) * count;
1840 /* check if we would go beyond end of SMB */
1841 if(size_of_data_area < size) {
1842 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1843 return -EINVAL;
1844 }
1845 } else if(acl_type & ACL_TYPE_DEFAULT) {
1846 count = le16_to_cpu(cifs_acl->access_entry_count);
1847 size = sizeof(struct cifs_posix_acl);
1848 size += sizeof(struct cifs_posix_ace) * count;
1849/* skip past access ACEs to get to default ACEs */
1850 pACE = &cifs_acl->ace_array[count];
1851 count = le16_to_cpu(cifs_acl->default_entry_count);
1852 size += sizeof(struct cifs_posix_ace) * count;
1853 /* check if we would go beyond end of SMB */
1854 if(size_of_data_area < size)
1855 return -EINVAL;
1856 } else {
1857 /* illegal type */
1858 return -EINVAL;
1859 }
1860
1861 size = posix_acl_xattr_size(count);
1862 if((buflen == 0) || (local_acl == NULL)) {
1863 /* used to query ACL EA size */
1864 } else if(size > buflen) {
1865 return -ERANGE;
1866 } else /* buffer big enough */ {
1867 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1868 for(i = 0;i < count ;i++) {
1869 cifs_convert_ace(&local_acl->a_entries[i],pACE);
1870 pACE ++;
1871 }
1872 }
1873 return size;
1874}
1875
1876static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1877 const posix_acl_xattr_entry * local_ace)
1878{
1879 __u16 rc = 0; /* 0 = ACL converted ok */
1880
1881 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1882 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
1883 /* BB is there a better way to handle the large uid? */
1884 if(local_ace->e_id == -1) {
1885 /* Probably no need to le convert -1 on any arch but can not hurt */
1886 cifs_ace->cifs_uid = cpu_to_le64(-1);
1887 } else
1888 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1889 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1890 return rc;
1891}
1892
1893/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1894static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1895 const int acl_type)
1896{
1897 __u16 rc = 0;
1898 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1899 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1900 int count;
1901 int i;
1902
1903 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1904 return 0;
1905
1906 count = posix_acl_xattr_count((size_t)buflen);
1907 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1908 count,buflen,local_acl->a_version));
1909 if(local_acl->a_version != 2) {
1910 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1911 return 0;
1912 }
1913 cifs_acl->version = cpu_to_le16(1);
1914 if(acl_type == ACL_TYPE_ACCESS)
1915 cifs_acl->access_entry_count = count;
1916 else if(acl_type == ACL_TYPE_DEFAULT)
1917 cifs_acl->default_entry_count = count;
1918 else {
1919 cFYI(1,("unknown ACL type %d",acl_type));
1920 return 0;
1921 }
1922 for(i=0;i<count;i++) {
1923 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1924 &local_acl->a_entries[i]);
1925 if(rc != 0) {
1926 /* ACE not converted */
1927 break;
1928 }
1929 }
1930 if(rc == 0) {
1931 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1932 rc += sizeof(struct cifs_posix_acl);
1933 /* BB add check to make sure ACL does not overflow SMB */
1934 }
1935 return rc;
1936}
1937
1938int
1939CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1940 const unsigned char *searchName,
1941 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07001942 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
1944/* SMB_QUERY_POSIX_ACL */
1945 TRANSACTION2_QPI_REQ *pSMB = NULL;
1946 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1947 int rc = 0;
1948 int bytes_returned;
1949 int name_len;
1950 __u16 params, byte_count;
1951
1952 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1953
1954queryAclRetry:
1955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1956 (void **) &pSMBr);
1957 if (rc)
1958 return rc;
1959
1960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1961 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001962 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07001963 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 name_len++; /* trailing null */
1965 name_len *= 2;
1966 pSMB->FileName[name_len] = 0;
1967 pSMB->FileName[name_len+1] = 0;
1968 } else { /* BB improve the check for buffer overruns BB */
1969 name_len = strnlen(searchName, PATH_MAX);
1970 name_len++; /* trailing null */
1971 strncpy(pSMB->FileName, searchName, name_len);
1972 }
1973
1974 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1975 pSMB->TotalDataCount = 0;
1976 pSMB->MaxParameterCount = cpu_to_le16(2);
1977 /* BB find exact max data count below from sess structure BB */
1978 pSMB->MaxDataCount = cpu_to_le16(4000);
1979 pSMB->MaxSetupCount = 0;
1980 pSMB->Reserved = 0;
1981 pSMB->Flags = 0;
1982 pSMB->Timeout = 0;
1983 pSMB->Reserved2 = 0;
1984 pSMB->ParameterOffset = cpu_to_le16(
1985 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1986 pSMB->DataCount = 0;
1987 pSMB->DataOffset = 0;
1988 pSMB->SetupCount = 1;
1989 pSMB->Reserved3 = 0;
1990 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1991 byte_count = params + 1 /* pad */ ;
1992 pSMB->TotalParameterCount = cpu_to_le16(params);
1993 pSMB->ParameterCount = pSMB->TotalParameterCount;
1994 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1995 pSMB->Reserved4 = 0;
1996 pSMB->hdr.smb_buf_length += byte_count;
1997 pSMB->ByteCount = cpu_to_le16(byte_count);
1998
1999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2001 if (rc) {
2002 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2003 } else {
2004 /* decode response */
2005
2006 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2007 if (rc || (pSMBr->ByteCount < 2))
2008 /* BB also check enough total bytes returned */
2009 rc = -EIO; /* bad smb */
2010 else {
2011 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2012 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2013 rc = cifs_copy_posix_acl(acl_inf,
2014 (char *)&pSMBr->hdr.Protocol+data_offset,
2015 buflen,acl_type,count);
2016 }
2017 }
2018 cifs_buf_release(pSMB);
2019 if (rc == -EAGAIN)
2020 goto queryAclRetry;
2021 return rc;
2022}
2023
2024int
2025CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2026 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002027 const char *local_acl, const int buflen,
2028 const int acl_type,
2029 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030{
2031 struct smb_com_transaction2_spi_req *pSMB = NULL;
2032 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2033 char *parm_data;
2034 int name_len;
2035 int rc = 0;
2036 int bytes_returned = 0;
2037 __u16 params, byte_count, data_count, param_offset, offset;
2038
2039 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2040setAclRetry:
2041 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2042 (void **) &pSMBr);
2043 if (rc)
2044 return rc;
2045 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2046 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002047 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002048 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 name_len++; /* trailing null */
2050 name_len *= 2;
2051 } else { /* BB improve the check for buffer overruns BB */
2052 name_len = strnlen(fileName, PATH_MAX);
2053 name_len++; /* trailing null */
2054 strncpy(pSMB->FileName, fileName, name_len);
2055 }
2056 params = 6 + name_len;
2057 pSMB->MaxParameterCount = cpu_to_le16(2);
2058 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2059 pSMB->MaxSetupCount = 0;
2060 pSMB->Reserved = 0;
2061 pSMB->Flags = 0;
2062 pSMB->Timeout = 0;
2063 pSMB->Reserved2 = 0;
2064 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2065 InformationLevel) - 4;
2066 offset = param_offset + params;
2067 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2068 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2069
2070 /* convert to on the wire format for POSIX ACL */
2071 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2072
2073 if(data_count == 0) {
2074 rc = -EOPNOTSUPP;
2075 goto setACLerrorExit;
2076 }
2077 pSMB->DataOffset = cpu_to_le16(offset);
2078 pSMB->SetupCount = 1;
2079 pSMB->Reserved3 = 0;
2080 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2081 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2082 byte_count = 3 /* pad */ + params + data_count;
2083 pSMB->DataCount = cpu_to_le16(data_count);
2084 pSMB->TotalDataCount = pSMB->DataCount;
2085 pSMB->ParameterCount = cpu_to_le16(params);
2086 pSMB->TotalParameterCount = pSMB->ParameterCount;
2087 pSMB->Reserved4 = 0;
2088 pSMB->hdr.smb_buf_length += byte_count;
2089 pSMB->ByteCount = cpu_to_le16(byte_count);
2090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2092 if (rc) {
2093 cFYI(1, ("Set POSIX ACL returned %d", rc));
2094 }
2095
2096setACLerrorExit:
2097 cifs_buf_release(pSMB);
2098 if (rc == -EAGAIN)
2099 goto setAclRetry;
2100 return rc;
2101}
2102
Steve Frenchf654bac2005-04-28 22:41:04 -07002103/* BB fix tabs in this function FIXME BB */
2104int
2105CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2106 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2107{
2108 int rc = 0;
2109 struct smb_t2_qfi_req *pSMB = NULL;
2110 struct smb_t2_qfi_rsp *pSMBr = NULL;
2111 int bytes_returned;
2112 __u16 params, byte_count;
2113
2114 cFYI(1,("In GetExtAttr"));
2115 if(tcon == NULL)
2116 return -ENODEV;
2117
2118GetExtAttrRetry:
2119 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2120 (void **) &pSMBr);
2121 if (rc)
2122 return rc;
2123
Steve Frenchc67593a2005-04-28 22:41:04 -07002124 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002125 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002126 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002127 /* BB find exact max data count below from sess structure BB */
2128 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2129 pSMB->t2.MaxSetupCount = 0;
2130 pSMB->t2.Reserved = 0;
2131 pSMB->t2.Flags = 0;
2132 pSMB->t2.Timeout = 0;
2133 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002134 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2135 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002136 pSMB->t2.DataCount = 0;
2137 pSMB->t2.DataOffset = 0;
2138 pSMB->t2.SetupCount = 1;
2139 pSMB->t2.Reserved3 = 0;
2140 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002141 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002142 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2143 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2144 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002145 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002146 pSMB->Fid = netfid;
2147 pSMB->hdr.smb_buf_length += byte_count;
2148 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2149
2150 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2151 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2152 if (rc) {
2153 cFYI(1, ("error %d in GetExtAttr", rc));
2154 } else {
2155 /* decode response */
2156 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2157 if (rc || (pSMBr->ByteCount < 2))
2158 /* BB also check enough total bytes returned */
2159 /* If rc should we check for EOPNOSUPP and
2160 disable the srvino flag? or in caller? */
2161 rc = -EIO; /* bad smb */
2162 else {
2163 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2164 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2165 struct file_chattr_info * pfinfo;
2166 /* BB Do we need a cast or hash here ? */
2167 if(count != 16) {
2168 cFYI(1, ("Illegal size ret in GetExtAttr"));
2169 rc = -EIO;
2170 goto GetExtAttrOut;
2171 }
2172 pfinfo = (struct file_chattr_info *)
2173 (data_offset + (char *) &pSMBr->hdr.Protocol);
2174 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2175 *pMask = le64_to_cpu(pfinfo->mask);
2176 }
2177 }
2178GetExtAttrOut:
2179 cifs_buf_release(pSMB);
2180 if (rc == -EAGAIN)
2181 goto GetExtAttrRetry;
2182 return rc;
2183}
2184
2185
2186#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
2188int
2189CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2190 const unsigned char *searchName,
2191 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002192 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193{
2194/* level 263 SMB_QUERY_FILE_ALL_INFO */
2195 TRANSACTION2_QPI_REQ *pSMB = NULL;
2196 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2197 int rc = 0;
2198 int bytes_returned;
2199 int name_len;
2200 __u16 params, byte_count;
2201
2202/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2203QPathInfoRetry:
2204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2205 (void **) &pSMBr);
2206 if (rc)
2207 return rc;
2208
2209 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2210 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002211 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002212 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 name_len++; /* trailing null */
2214 name_len *= 2;
2215 } else { /* BB improve the check for buffer overruns BB */
2216 name_len = strnlen(searchName, PATH_MAX);
2217 name_len++; /* trailing null */
2218 strncpy(pSMB->FileName, searchName, name_len);
2219 }
2220
2221 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2222 pSMB->TotalDataCount = 0;
2223 pSMB->MaxParameterCount = cpu_to_le16(2);
2224 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2225 pSMB->MaxSetupCount = 0;
2226 pSMB->Reserved = 0;
2227 pSMB->Flags = 0;
2228 pSMB->Timeout = 0;
2229 pSMB->Reserved2 = 0;
2230 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2231 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2232 pSMB->DataCount = 0;
2233 pSMB->DataOffset = 0;
2234 pSMB->SetupCount = 1;
2235 pSMB->Reserved3 = 0;
2236 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2237 byte_count = params + 1 /* pad */ ;
2238 pSMB->TotalParameterCount = cpu_to_le16(params);
2239 pSMB->ParameterCount = pSMB->TotalParameterCount;
2240 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2241 pSMB->Reserved4 = 0;
2242 pSMB->hdr.smb_buf_length += byte_count;
2243 pSMB->ByteCount = cpu_to_le16(byte_count);
2244
2245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2246 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2247 if (rc) {
2248 cFYI(1, ("Send error in QPathInfo = %d", rc));
2249 } else { /* decode response */
2250 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2251
2252 if (rc || (pSMBr->ByteCount < 40))
2253 rc = -EIO; /* bad smb */
2254 else if (pFindData){
2255 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2256 memcpy((char *) pFindData,
2257 (char *) &pSMBr->hdr.Protocol +
2258 data_offset, sizeof (FILE_ALL_INFO));
2259 } else
2260 rc = -ENOMEM;
2261 }
2262 cifs_buf_release(pSMB);
2263 if (rc == -EAGAIN)
2264 goto QPathInfoRetry;
2265
2266 return rc;
2267}
2268
2269int
2270CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2271 const unsigned char *searchName,
2272 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002273 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274{
2275/* SMB_QUERY_FILE_UNIX_BASIC */
2276 TRANSACTION2_QPI_REQ *pSMB = NULL;
2277 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2278 int rc = 0;
2279 int bytes_returned = 0;
2280 int name_len;
2281 __u16 params, byte_count;
2282
2283 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2284UnixQPathInfoRetry:
2285 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2286 (void **) &pSMBr);
2287 if (rc)
2288 return rc;
2289
2290 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2291 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002292 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002293 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 name_len++; /* trailing null */
2295 name_len *= 2;
2296 } else { /* BB improve the check for buffer overruns BB */
2297 name_len = strnlen(searchName, PATH_MAX);
2298 name_len++; /* trailing null */
2299 strncpy(pSMB->FileName, searchName, name_len);
2300 }
2301
2302 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2303 pSMB->TotalDataCount = 0;
2304 pSMB->MaxParameterCount = cpu_to_le16(2);
2305 /* BB find exact max SMB PDU from sess structure BB */
2306 pSMB->MaxDataCount = cpu_to_le16(4000);
2307 pSMB->MaxSetupCount = 0;
2308 pSMB->Reserved = 0;
2309 pSMB->Flags = 0;
2310 pSMB->Timeout = 0;
2311 pSMB->Reserved2 = 0;
2312 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2313 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2314 pSMB->DataCount = 0;
2315 pSMB->DataOffset = 0;
2316 pSMB->SetupCount = 1;
2317 pSMB->Reserved3 = 0;
2318 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2319 byte_count = params + 1 /* pad */ ;
2320 pSMB->TotalParameterCount = cpu_to_le16(params);
2321 pSMB->ParameterCount = pSMB->TotalParameterCount;
2322 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2323 pSMB->Reserved4 = 0;
2324 pSMB->hdr.smb_buf_length += byte_count;
2325 pSMB->ByteCount = cpu_to_le16(byte_count);
2326
2327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2329 if (rc) {
2330 cFYI(1, ("Send error in QPathInfo = %d", rc));
2331 } else { /* decode response */
2332 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2333
2334 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2335 rc = -EIO; /* bad smb */
2336 } else {
2337 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2338 memcpy((char *) pFindData,
2339 (char *) &pSMBr->hdr.Protocol +
2340 data_offset,
2341 sizeof (FILE_UNIX_BASIC_INFO));
2342 }
2343 }
2344 cifs_buf_release(pSMB);
2345 if (rc == -EAGAIN)
2346 goto UnixQPathInfoRetry;
2347
2348 return rc;
2349}
2350
2351#if 0 /* function unused at present */
2352int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2353 const char *searchName, FILE_ALL_INFO * findData,
2354 const struct nls_table *nls_codepage)
2355{
2356/* level 257 SMB_ */
2357 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2358 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2359 int rc = 0;
2360 int bytes_returned;
2361 int name_len;
2362 __u16 params, byte_count;
2363
2364 cFYI(1, ("In FindUnique"));
2365findUniqueRetry:
2366 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2367 (void **) &pSMBr);
2368 if (rc)
2369 return rc;
2370
2371 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2372 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002373 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 /* find define for this maxpathcomponent */
2375 , nls_codepage);
2376 name_len++; /* trailing null */
2377 name_len *= 2;
2378 } else { /* BB improve the check for buffer overruns BB */
2379 name_len = strnlen(searchName, PATH_MAX);
2380 name_len++; /* trailing null */
2381 strncpy(pSMB->FileName, searchName, name_len);
2382 }
2383
2384 params = 12 + name_len /* includes null */ ;
2385 pSMB->TotalDataCount = 0; /* no EAs */
2386 pSMB->MaxParameterCount = cpu_to_le16(2);
2387 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2388 pSMB->MaxSetupCount = 0;
2389 pSMB->Reserved = 0;
2390 pSMB->Flags = 0;
2391 pSMB->Timeout = 0;
2392 pSMB->Reserved2 = 0;
2393 pSMB->ParameterOffset = cpu_to_le16(
2394 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2395 pSMB->DataCount = 0;
2396 pSMB->DataOffset = 0;
2397 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2398 pSMB->Reserved3 = 0;
2399 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2400 byte_count = params + 1 /* pad */ ;
2401 pSMB->TotalParameterCount = cpu_to_le16(params);
2402 pSMB->ParameterCount = pSMB->TotalParameterCount;
2403 pSMB->SearchAttributes =
2404 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2405 ATTR_DIRECTORY);
2406 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2407 pSMB->SearchFlags = cpu_to_le16(1);
2408 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2409 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2410 pSMB->hdr.smb_buf_length += byte_count;
2411 pSMB->ByteCount = cpu_to_le16(byte_count);
2412
2413 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2414 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2415
2416 if (rc) {
2417 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2418 } else { /* decode response */
Steve Frenchdfb75332005-06-22 17:13:47 -07002419#ifdef CONFIG_CIFS_STATS
2420 atomic_inc(&tcon->num_ffirst);
2421#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 /* BB fill in */
2423 }
2424
2425 cifs_buf_release(pSMB);
2426 if (rc == -EAGAIN)
2427 goto findUniqueRetry;
2428
2429 return rc;
2430}
2431#endif /* end unused (temporarily) function */
2432
2433/* xid, tcon, searchName and codepage are input parms, rest are returned */
2434int
2435CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2436 const char *searchName,
2437 const struct nls_table *nls_codepage,
2438 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002439 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440{
2441/* level 257 SMB_ */
2442 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2443 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2444 T2_FFIRST_RSP_PARMS * parms;
2445 int rc = 0;
2446 int bytes_returned = 0;
2447 int name_len;
2448 __u16 params, byte_count;
2449
Steve French737b7582005-04-28 22:41:06 -07002450 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
2452findFirstRetry:
2453 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2454 (void **) &pSMBr);
2455 if (rc)
2456 return rc;
2457
2458 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2459 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002460 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002461 PATH_MAX, nls_codepage, remap);
2462 /* We can not add the asterik earlier in case
2463 it got remapped to 0xF03A as if it were part of the
2464 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002466 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002467 pSMB->FileName[name_len+1] = 0;
2468 pSMB->FileName[name_len+2] = '*';
2469 pSMB->FileName[name_len+3] = 0;
2470 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2472 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002473 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 } else { /* BB add check for overrun of SMB buf BB */
2475 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476/* BB fix here and in unicode clause above ie
2477 if(name_len > buffersize-header)
2478 free buffer exit; BB */
2479 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002480 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002481 pSMB->FileName[name_len+1] = '*';
2482 pSMB->FileName[name_len+2] = 0;
2483 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485
2486 params = 12 + name_len /* includes null */ ;
2487 pSMB->TotalDataCount = 0; /* no EAs */
2488 pSMB->MaxParameterCount = cpu_to_le16(10);
2489 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2490 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2491 pSMB->MaxSetupCount = 0;
2492 pSMB->Reserved = 0;
2493 pSMB->Flags = 0;
2494 pSMB->Timeout = 0;
2495 pSMB->Reserved2 = 0;
2496 byte_count = params + 1 /* pad */ ;
2497 pSMB->TotalParameterCount = cpu_to_le16(params);
2498 pSMB->ParameterCount = pSMB->TotalParameterCount;
2499 pSMB->ParameterOffset = cpu_to_le16(
2500 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2501 pSMB->DataCount = 0;
2502 pSMB->DataOffset = 0;
2503 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2504 pSMB->Reserved3 = 0;
2505 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2506 pSMB->SearchAttributes =
2507 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2508 ATTR_DIRECTORY);
2509 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2510 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2511 CIFS_SEARCH_RETURN_RESUME);
2512 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2513
2514 /* BB what should we set StorageType to? Does it matter? BB */
2515 pSMB->SearchStorageType = 0;
2516 pSMB->hdr.smb_buf_length += byte_count;
2517 pSMB->ByteCount = cpu_to_le16(byte_count);
2518
2519 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2520 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2521
Steve French4a6d87f2005-08-13 08:15:54 -07002522 if (rc) {/* BB add logic to retry regular search if Unix search
2523 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 /* BB Add code to handle unsupported level rc */
2525 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French4a6d87f2005-08-13 08:15:54 -07002526 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
2528 /* BB eventually could optimize out free and realloc of buf */
2529 /* for this case */
2530 if (rc == -EAGAIN)
2531 goto findFirstRetry;
2532 } else { /* decode response */
Steve Frenchdfb75332005-06-22 17:13:47 -07002533#ifdef CONFIG_CIFS_STATS
2534 atomic_inc(&tcon->num_ffirst);
2535#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 /* BB remember to free buffer if error BB */
2537 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2538 if(rc == 0) {
2539 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2540 psrch_inf->unicode = TRUE;
2541 else
2542 psrch_inf->unicode = FALSE;
2543
2544 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2545 psrch_inf->srch_entries_start =
2546 (char *) &pSMBr->hdr.Protocol +
2547 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2549 le16_to_cpu(pSMBr->t2.ParameterOffset));
2550
2551 if(parms->EndofSearch)
2552 psrch_inf->endOfSearch = TRUE;
2553 else
2554 psrch_inf->endOfSearch = FALSE;
2555
2556 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2557 psrch_inf->index_of_last_entry =
2558 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 *pnetfid = parms->SearchHandle;
2560 } else {
2561 cifs_buf_release(pSMB);
2562 }
2563 }
2564
2565 return rc;
2566}
2567
2568int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2569 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2570{
2571 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2572 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2573 T2_FNEXT_RSP_PARMS * parms;
2574 char *response_data;
2575 int rc = 0;
2576 int bytes_returned, name_len;
2577 __u16 params, byte_count;
2578
2579 cFYI(1, ("In FindNext"));
2580
2581 if(psrch_inf->endOfSearch == TRUE)
2582 return -ENOENT;
2583
2584 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2585 (void **) &pSMBr);
2586 if (rc)
2587 return rc;
2588
2589 params = 14; /* includes 2 bytes of null string, converted to LE below */
2590 byte_count = 0;
2591 pSMB->TotalDataCount = 0; /* no EAs */
2592 pSMB->MaxParameterCount = cpu_to_le16(8);
2593 pSMB->MaxDataCount =
2594 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2595 pSMB->MaxSetupCount = 0;
2596 pSMB->Reserved = 0;
2597 pSMB->Flags = 0;
2598 pSMB->Timeout = 0;
2599 pSMB->Reserved2 = 0;
2600 pSMB->ParameterOffset = cpu_to_le16(
2601 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2602 pSMB->DataCount = 0;
2603 pSMB->DataOffset = 0;
2604 pSMB->SetupCount = 1;
2605 pSMB->Reserved3 = 0;
2606 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2607 pSMB->SearchHandle = searchHandle; /* always kept as le */
2608 pSMB->SearchCount =
2609 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2610 /* test for Unix extensions */
2611/* if (tcon->ses->capabilities & CAP_UNIX) {
2612 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2613 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2614 } else {
2615 pSMB->InformationLevel =
2616 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2617 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2618 } */
2619 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2620 pSMB->ResumeKey = psrch_inf->resume_key;
2621 pSMB->SearchFlags =
2622 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2623
2624 name_len = psrch_inf->resume_name_len;
2625 params += name_len;
2626 if(name_len < PATH_MAX) {
2627 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2628 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002629 /* 14 byte parm len above enough for 2 byte null terminator */
2630 pSMB->ResumeFileName[name_len] = 0;
2631 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 } else {
2633 rc = -EINVAL;
2634 goto FNext2_err_exit;
2635 }
2636 byte_count = params + 1 /* pad */ ;
2637 pSMB->TotalParameterCount = cpu_to_le16(params);
2638 pSMB->ParameterCount = pSMB->TotalParameterCount;
2639 pSMB->hdr.smb_buf_length += byte_count;
2640 pSMB->ByteCount = cpu_to_le16(byte_count);
2641
2642 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2643 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2644
2645 if (rc) {
2646 if (rc == -EBADF) {
2647 psrch_inf->endOfSearch = TRUE;
2648 rc = 0; /* search probably was closed at end of search above */
2649 } else
2650 cFYI(1, ("FindNext returned = %d", rc));
2651 } else { /* decode response */
Steve Frenchdfb75332005-06-22 17:13:47 -07002652#ifdef CONFIG_CIFS_STATS
2653 atomic_inc(&tcon->num_fnext);
2654#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2656
2657 if(rc == 0) {
2658 /* BB fixme add lock for file (srch_info) struct here */
2659 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2660 psrch_inf->unicode = TRUE;
2661 else
2662 psrch_inf->unicode = FALSE;
2663 response_data = (char *) &pSMBr->hdr.Protocol +
2664 le16_to_cpu(pSMBr->t2.ParameterOffset);
2665 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2666 response_data = (char *)&pSMBr->hdr.Protocol +
2667 le16_to_cpu(pSMBr->t2.DataOffset);
2668 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2669 psrch_inf->srch_entries_start = response_data;
2670 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2671 if(parms->EndofSearch)
2672 psrch_inf->endOfSearch = TRUE;
2673 else
2674 psrch_inf->endOfSearch = FALSE;
2675
2676 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2677 psrch_inf->index_of_last_entry +=
2678 psrch_inf->entries_in_buffer;
2679/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2680
2681 /* BB fixme add unlock here */
2682 }
2683
2684 }
2685
2686 /* BB On error, should we leave previous search buf (and count and
2687 last entry fields) intact or free the previous one? */
2688
2689 /* Note: On -EAGAIN error only caller can retry on handle based calls
2690 since file handle passed in no longer valid */
2691FNext2_err_exit:
2692 if (rc != 0)
2693 cifs_buf_release(pSMB);
2694
2695 return rc;
2696}
2697
2698int
2699CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2700{
2701 int rc = 0;
2702 FINDCLOSE_REQ *pSMB = NULL;
2703 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2704 int bytes_returned;
2705
2706 cFYI(1, ("In CIFSSMBFindClose"));
2707 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2708
2709 /* no sense returning error if session restarted
2710 as file handle has been closed */
2711 if(rc == -EAGAIN)
2712 return 0;
2713 if (rc)
2714 return rc;
2715
2716 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2717 pSMB->FileID = searchHandle;
2718 pSMB->ByteCount = 0;
2719 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2720 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2721 if (rc) {
2722 cERROR(1, ("Send error in FindClose = %d", rc));
2723 }
Steve Frenchdfb75332005-06-22 17:13:47 -07002724#ifdef CONFIG_CIFS_STATS
2725 atomic_inc(&tcon->num_fclose);
2726#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 cifs_small_buf_release(pSMB);
2728
2729 /* Since session is dead, search handle closed on server already */
2730 if (rc == -EAGAIN)
2731 rc = 0;
2732
2733 return rc;
2734}
2735
2736#ifdef CONFIG_CIFS_EXPERIMENTAL
2737int
2738CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2739 const unsigned char *searchName,
2740 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002741 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742{
2743 int rc = 0;
2744 TRANSACTION2_QPI_REQ *pSMB = NULL;
2745 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2746 int name_len, bytes_returned;
2747 __u16 params, byte_count;
2748
2749 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2750 if(tcon == NULL)
2751 return -ENODEV;
2752
2753GetInodeNumberRetry:
2754 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2755 (void **) &pSMBr);
2756 if (rc)
2757 return rc;
2758
2759
2760 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2761 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002762 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002763 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 name_len++; /* trailing null */
2765 name_len *= 2;
2766 } else { /* BB improve the check for buffer overruns BB */
2767 name_len = strnlen(searchName, PATH_MAX);
2768 name_len++; /* trailing null */
2769 strncpy(pSMB->FileName, searchName, name_len);
2770 }
2771
2772 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2773 pSMB->TotalDataCount = 0;
2774 pSMB->MaxParameterCount = cpu_to_le16(2);
2775 /* BB find exact max data count below from sess structure BB */
2776 pSMB->MaxDataCount = cpu_to_le16(4000);
2777 pSMB->MaxSetupCount = 0;
2778 pSMB->Reserved = 0;
2779 pSMB->Flags = 0;
2780 pSMB->Timeout = 0;
2781 pSMB->Reserved2 = 0;
2782 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2783 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2784 pSMB->DataCount = 0;
2785 pSMB->DataOffset = 0;
2786 pSMB->SetupCount = 1;
2787 pSMB->Reserved3 = 0;
2788 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2789 byte_count = params + 1 /* pad */ ;
2790 pSMB->TotalParameterCount = cpu_to_le16(params);
2791 pSMB->ParameterCount = pSMB->TotalParameterCount;
2792 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2793 pSMB->Reserved4 = 0;
2794 pSMB->hdr.smb_buf_length += byte_count;
2795 pSMB->ByteCount = cpu_to_le16(byte_count);
2796
2797 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2798 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2799 if (rc) {
2800 cFYI(1, ("error %d in QueryInternalInfo", rc));
2801 } else {
2802 /* decode response */
2803 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2804 if (rc || (pSMBr->ByteCount < 2))
2805 /* BB also check enough total bytes returned */
2806 /* If rc should we check for EOPNOSUPP and
2807 disable the srvino flag? or in caller? */
2808 rc = -EIO; /* bad smb */
2809 else {
2810 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2811 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2812 struct file_internal_info * pfinfo;
2813 /* BB Do we need a cast or hash here ? */
2814 if(count < 8) {
2815 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2816 rc = -EIO;
2817 goto GetInodeNumOut;
2818 }
2819 pfinfo = (struct file_internal_info *)
2820 (data_offset + (char *) &pSMBr->hdr.Protocol);
2821 *inode_number = pfinfo->UniqueId;
2822 }
2823 }
2824GetInodeNumOut:
2825 cifs_buf_release(pSMB);
2826 if (rc == -EAGAIN)
2827 goto GetInodeNumberRetry;
2828 return rc;
2829}
2830#endif /* CIFS_EXPERIMENTAL */
2831
2832int
2833CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2834 const unsigned char *searchName,
2835 unsigned char **targetUNCs,
2836 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07002837 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838{
2839/* TRANS2_GET_DFS_REFERRAL */
2840 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2841 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2842 struct dfs_referral_level_3 * referrals = NULL;
2843 int rc = 0;
2844 int bytes_returned;
2845 int name_len;
2846 unsigned int i;
2847 char * temp;
2848 __u16 params, byte_count;
2849 *number_of_UNC_in_array = 0;
2850 *targetUNCs = NULL;
2851
2852 cFYI(1, ("In GetDFSRefer the path %s", searchName));
2853 if (ses == NULL)
2854 return -ENODEV;
2855getDFSRetry:
2856 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2857 (void **) &pSMBr);
2858 if (rc)
2859 return rc;
2860
2861 pSMB->hdr.Tid = ses->ipc_tid;
2862 pSMB->hdr.Uid = ses->Suid;
2863 if (ses->capabilities & CAP_STATUS32) {
2864 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2865 }
2866 if (ses->capabilities & CAP_DFS) {
2867 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2868 }
2869
2870 if (ses->capabilities & CAP_UNICODE) {
2871 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2872 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002873 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07002874 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 name_len++; /* trailing null */
2876 name_len *= 2;
2877 } else { /* BB improve the check for buffer overruns BB */
2878 name_len = strnlen(searchName, PATH_MAX);
2879 name_len++; /* trailing null */
2880 strncpy(pSMB->RequestFileName, searchName, name_len);
2881 }
2882
2883 params = 2 /* level */ + name_len /*includes null */ ;
2884 pSMB->TotalDataCount = 0;
2885 pSMB->DataCount = 0;
2886 pSMB->DataOffset = 0;
2887 pSMB->MaxParameterCount = 0;
2888 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2889 pSMB->MaxSetupCount = 0;
2890 pSMB->Reserved = 0;
2891 pSMB->Flags = 0;
2892 pSMB->Timeout = 0;
2893 pSMB->Reserved2 = 0;
2894 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2895 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2896 pSMB->SetupCount = 1;
2897 pSMB->Reserved3 = 0;
2898 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2899 byte_count = params + 3 /* pad */ ;
2900 pSMB->ParameterCount = cpu_to_le16(params);
2901 pSMB->TotalParameterCount = pSMB->ParameterCount;
2902 pSMB->MaxReferralLevel = cpu_to_le16(3);
2903 pSMB->hdr.smb_buf_length += byte_count;
2904 pSMB->ByteCount = cpu_to_le16(byte_count);
2905
2906 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2908 if (rc) {
2909 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2910 } else { /* decode response */
2911/* BB Add logic to parse referrals here */
2912 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2913
2914 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
2915 rc = -EIO; /* bad smb */
2916 else {
2917 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2918 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2919
2920 cFYI(1,
2921 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
2922 pSMBr->ByteCount, data_offset));
2923 referrals =
2924 (struct dfs_referral_level_3 *)
2925 (8 /* sizeof start of data block */ +
2926 data_offset +
2927 (char *) &pSMBr->hdr.Protocol);
2928 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",
2929 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)));
2930 /* BB This field is actually two bytes in from start of
2931 data block so we could do safety check that DataBlock
2932 begins at address of pSMBr->NumberOfReferrals */
2933 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2934
2935 /* BB Fix below so can return more than one referral */
2936 if(*number_of_UNC_in_array > 1)
2937 *number_of_UNC_in_array = 1;
2938
2939 /* get the length of the strings describing refs */
2940 name_len = 0;
2941 for(i=0;i<*number_of_UNC_in_array;i++) {
2942 /* make sure that DfsPathOffset not past end */
2943 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2944 if (offset > data_count) {
2945 /* if invalid referral, stop here and do
2946 not try to copy any more */
2947 *number_of_UNC_in_array = i;
2948 break;
2949 }
2950 temp = ((char *)referrals) + offset;
2951
2952 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2953 name_len += UniStrnlen((wchar_t *)temp,data_count);
2954 } else {
2955 name_len += strnlen(temp,data_count);
2956 }
2957 referrals++;
2958 /* BB add check that referral pointer does not fall off end PDU */
2959
2960 }
2961 /* BB add check for name_len bigger than bcc */
2962 *targetUNCs =
2963 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2964 if(*targetUNCs == NULL) {
2965 rc = -ENOMEM;
2966 goto GetDFSRefExit;
2967 }
2968 /* copy the ref strings */
2969 referrals =
2970 (struct dfs_referral_level_3 *)
2971 (8 /* sizeof data hdr */ +
2972 data_offset +
2973 (char *) &pSMBr->hdr.Protocol);
2974
2975 for(i=0;i<*number_of_UNC_in_array;i++) {
2976 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2977 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2978 cifs_strfromUCS_le(*targetUNCs,
2979 (wchar_t *) temp, name_len, nls_codepage);
2980 } else {
2981 strncpy(*targetUNCs,temp,name_len);
2982 }
2983 /* BB update target_uncs pointers */
2984 referrals++;
2985 }
2986 temp = *targetUNCs;
2987 temp[name_len] = 0;
2988 }
2989
2990 }
2991GetDFSRefExit:
2992 if (pSMB)
2993 cifs_buf_release(pSMB);
2994
2995 if (rc == -EAGAIN)
2996 goto getDFSRetry;
2997
2998 return rc;
2999}
3000
3001int
Steve French737b7582005-04-28 22:41:06 -07003002CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003{
3004/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3005 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3006 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3007 FILE_SYSTEM_INFO *response_data;
3008 int rc = 0;
3009 int bytes_returned = 0;
3010 __u16 params, byte_count;
3011
3012 cFYI(1, ("In QFSInfo"));
3013QFSInfoRetry:
3014 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3015 (void **) &pSMBr);
3016 if (rc)
3017 return rc;
3018
3019 params = 2; /* level */
3020 pSMB->TotalDataCount = 0;
3021 pSMB->MaxParameterCount = cpu_to_le16(2);
3022 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3023 pSMB->MaxSetupCount = 0;
3024 pSMB->Reserved = 0;
3025 pSMB->Flags = 0;
3026 pSMB->Timeout = 0;
3027 pSMB->Reserved2 = 0;
3028 byte_count = params + 1 /* pad */ ;
3029 pSMB->TotalParameterCount = cpu_to_le16(params);
3030 pSMB->ParameterCount = pSMB->TotalParameterCount;
3031 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3032 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3033 pSMB->DataCount = 0;
3034 pSMB->DataOffset = 0;
3035 pSMB->SetupCount = 1;
3036 pSMB->Reserved3 = 0;
3037 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3038 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3039 pSMB->hdr.smb_buf_length += byte_count;
3040 pSMB->ByteCount = cpu_to_le16(byte_count);
3041
3042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3044 if (rc) {
3045 cERROR(1, ("Send error in QFSInfo = %d", rc));
3046 } else { /* decode response */
3047 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3048
3049 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3050 rc = -EIO; /* bad smb */
3051 else {
3052 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3053 cFYI(1,
3054 ("Decoding qfsinfo response. BCC: %d Offset %d",
3055 pSMBr->ByteCount, data_offset));
3056
3057 response_data =
3058 (FILE_SYSTEM_INFO
3059 *) (((char *) &pSMBr->hdr.Protocol) +
3060 data_offset);
3061 FSData->f_bsize =
3062 le32_to_cpu(response_data->BytesPerSector) *
3063 le32_to_cpu(response_data->
3064 SectorsPerAllocationUnit);
3065 FSData->f_blocks =
3066 le64_to_cpu(response_data->TotalAllocationUnits);
3067 FSData->f_bfree = FSData->f_bavail =
3068 le64_to_cpu(response_data->FreeAllocationUnits);
3069 cFYI(1,
3070 ("Blocks: %lld Free: %lld Block size %ld",
3071 (unsigned long long)FSData->f_blocks,
3072 (unsigned long long)FSData->f_bfree,
3073 FSData->f_bsize));
3074 }
3075 }
3076 cifs_buf_release(pSMB);
3077
3078 if (rc == -EAGAIN)
3079 goto QFSInfoRetry;
3080
3081 return rc;
3082}
3083
3084int
Steve French737b7582005-04-28 22:41:06 -07003085CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086{
3087/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3088 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3089 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3090 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3091 int rc = 0;
3092 int bytes_returned = 0;
3093 __u16 params, byte_count;
3094
3095 cFYI(1, ("In QFSAttributeInfo"));
3096QFSAttributeRetry:
3097 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3098 (void **) &pSMBr);
3099 if (rc)
3100 return rc;
3101
3102 params = 2; /* level */
3103 pSMB->TotalDataCount = 0;
3104 pSMB->MaxParameterCount = cpu_to_le16(2);
3105 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3106 pSMB->MaxSetupCount = 0;
3107 pSMB->Reserved = 0;
3108 pSMB->Flags = 0;
3109 pSMB->Timeout = 0;
3110 pSMB->Reserved2 = 0;
3111 byte_count = params + 1 /* pad */ ;
3112 pSMB->TotalParameterCount = cpu_to_le16(params);
3113 pSMB->ParameterCount = pSMB->TotalParameterCount;
3114 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3115 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3116 pSMB->DataCount = 0;
3117 pSMB->DataOffset = 0;
3118 pSMB->SetupCount = 1;
3119 pSMB->Reserved3 = 0;
3120 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3121 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3122 pSMB->hdr.smb_buf_length += byte_count;
3123 pSMB->ByteCount = cpu_to_le16(byte_count);
3124
3125 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3126 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3127 if (rc) {
3128 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3129 } else { /* decode response */
3130 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3131
3132 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3133 rc = -EIO; /* bad smb */
3134 } else {
3135 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3136 response_data =
3137 (FILE_SYSTEM_ATTRIBUTE_INFO
3138 *) (((char *) &pSMBr->hdr.Protocol) +
3139 data_offset);
3140 memcpy(&tcon->fsAttrInfo, response_data,
3141 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3142 }
3143 }
3144 cifs_buf_release(pSMB);
3145
3146 if (rc == -EAGAIN)
3147 goto QFSAttributeRetry;
3148
3149 return rc;
3150}
3151
3152int
Steve French737b7582005-04-28 22:41:06 -07003153CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154{
3155/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3156 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3157 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3158 FILE_SYSTEM_DEVICE_INFO *response_data;
3159 int rc = 0;
3160 int bytes_returned = 0;
3161 __u16 params, byte_count;
3162
3163 cFYI(1, ("In QFSDeviceInfo"));
3164QFSDeviceRetry:
3165 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3166 (void **) &pSMBr);
3167 if (rc)
3168 return rc;
3169
3170 params = 2; /* level */
3171 pSMB->TotalDataCount = 0;
3172 pSMB->MaxParameterCount = cpu_to_le16(2);
3173 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3174 pSMB->MaxSetupCount = 0;
3175 pSMB->Reserved = 0;
3176 pSMB->Flags = 0;
3177 pSMB->Timeout = 0;
3178 pSMB->Reserved2 = 0;
3179 byte_count = params + 1 /* pad */ ;
3180 pSMB->TotalParameterCount = cpu_to_le16(params);
3181 pSMB->ParameterCount = pSMB->TotalParameterCount;
3182 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3183 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3184
3185 pSMB->DataCount = 0;
3186 pSMB->DataOffset = 0;
3187 pSMB->SetupCount = 1;
3188 pSMB->Reserved3 = 0;
3189 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3190 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3191 pSMB->hdr.smb_buf_length += byte_count;
3192 pSMB->ByteCount = cpu_to_le16(byte_count);
3193
3194 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3195 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3196 if (rc) {
3197 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3198 } else { /* decode response */
3199 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3200
3201 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3202 rc = -EIO; /* bad smb */
3203 else {
3204 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3205 response_data =
Steve French737b7582005-04-28 22:41:06 -07003206 (FILE_SYSTEM_DEVICE_INFO *)
3207 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 data_offset);
3209 memcpy(&tcon->fsDevInfo, response_data,
3210 sizeof (FILE_SYSTEM_DEVICE_INFO));
3211 }
3212 }
3213 cifs_buf_release(pSMB);
3214
3215 if (rc == -EAGAIN)
3216 goto QFSDeviceRetry;
3217
3218 return rc;
3219}
3220
3221int
Steve French737b7582005-04-28 22:41:06 -07003222CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223{
3224/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3225 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3226 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3227 FILE_SYSTEM_UNIX_INFO *response_data;
3228 int rc = 0;
3229 int bytes_returned = 0;
3230 __u16 params, byte_count;
3231
3232 cFYI(1, ("In QFSUnixInfo"));
3233QFSUnixRetry:
3234 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3235 (void **) &pSMBr);
3236 if (rc)
3237 return rc;
3238
3239 params = 2; /* level */
3240 pSMB->TotalDataCount = 0;
3241 pSMB->DataCount = 0;
3242 pSMB->DataOffset = 0;
3243 pSMB->MaxParameterCount = cpu_to_le16(2);
3244 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3245 pSMB->MaxSetupCount = 0;
3246 pSMB->Reserved = 0;
3247 pSMB->Flags = 0;
3248 pSMB->Timeout = 0;
3249 pSMB->Reserved2 = 0;
3250 byte_count = params + 1 /* pad */ ;
3251 pSMB->ParameterCount = cpu_to_le16(params);
3252 pSMB->TotalParameterCount = pSMB->ParameterCount;
3253 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3254 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3255 pSMB->SetupCount = 1;
3256 pSMB->Reserved3 = 0;
3257 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3258 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3259 pSMB->hdr.smb_buf_length += byte_count;
3260 pSMB->ByteCount = cpu_to_le16(byte_count);
3261
3262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3264 if (rc) {
3265 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3266 } else { /* decode response */
3267 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3268
3269 if (rc || (pSMBr->ByteCount < 13)) {
3270 rc = -EIO; /* bad smb */
3271 } else {
3272 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3273 response_data =
3274 (FILE_SYSTEM_UNIX_INFO
3275 *) (((char *) &pSMBr->hdr.Protocol) +
3276 data_offset);
3277 memcpy(&tcon->fsUnixInfo, response_data,
3278 sizeof (FILE_SYSTEM_UNIX_INFO));
3279 }
3280 }
3281 cifs_buf_release(pSMB);
3282
3283 if (rc == -EAGAIN)
3284 goto QFSUnixRetry;
3285
3286
3287 return rc;
3288}
3289
Jeremy Allisonac670552005-06-22 17:26:35 -07003290int
Steve French45abc6e2005-06-23 13:42:03 -05003291CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003292{
3293/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3294 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3295 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3296 int rc = 0;
3297 int bytes_returned = 0;
3298 __u16 params, param_offset, offset, byte_count;
3299
3300 cFYI(1, ("In SETFSUnixInfo"));
3301SETFSUnixRetry:
3302 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3303 (void **) &pSMBr);
3304 if (rc)
3305 return rc;
3306
3307 params = 4; /* 2 bytes zero followed by info level. */
3308 pSMB->MaxSetupCount = 0;
3309 pSMB->Reserved = 0;
3310 pSMB->Flags = 0;
3311 pSMB->Timeout = 0;
3312 pSMB->Reserved2 = 0;
3313 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3314 offset = param_offset + params;
3315
3316 pSMB->MaxParameterCount = cpu_to_le16(4);
3317 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3318 pSMB->SetupCount = 1;
3319 pSMB->Reserved3 = 0;
3320 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3321 byte_count = 1 /* pad */ + params + 12;
3322
3323 pSMB->DataCount = cpu_to_le16(12);
3324 pSMB->ParameterCount = cpu_to_le16(params);
3325 pSMB->TotalDataCount = pSMB->DataCount;
3326 pSMB->TotalParameterCount = pSMB->ParameterCount;
3327 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3328 pSMB->DataOffset = cpu_to_le16(offset);
3329
3330 /* Params. */
3331 pSMB->FileNum = 0;
3332 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3333
3334 /* Data. */
3335 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3336 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3337 pSMB->ClientUnixCap = cpu_to_le64(cap);
3338
3339 pSMB->hdr.smb_buf_length += byte_count;
3340 pSMB->ByteCount = cpu_to_le16(byte_count);
3341
3342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3343 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3344 if (rc) {
3345 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3346 } else { /* decode response */
3347 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3348 if (rc) {
3349 rc = -EIO; /* bad smb */
3350 }
3351 }
3352 cifs_buf_release(pSMB);
3353
3354 if (rc == -EAGAIN)
3355 goto SETFSUnixRetry;
3356
3357 return rc;
3358}
3359
3360
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361
3362int
3363CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003364 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365{
3366/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3367 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3368 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3369 FILE_SYSTEM_POSIX_INFO *response_data;
3370 int rc = 0;
3371 int bytes_returned = 0;
3372 __u16 params, byte_count;
3373
3374 cFYI(1, ("In QFSPosixInfo"));
3375QFSPosixRetry:
3376 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3377 (void **) &pSMBr);
3378 if (rc)
3379 return rc;
3380
3381 params = 2; /* level */
3382 pSMB->TotalDataCount = 0;
3383 pSMB->DataCount = 0;
3384 pSMB->DataOffset = 0;
3385 pSMB->MaxParameterCount = cpu_to_le16(2);
3386 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3387 pSMB->MaxSetupCount = 0;
3388 pSMB->Reserved = 0;
3389 pSMB->Flags = 0;
3390 pSMB->Timeout = 0;
3391 pSMB->Reserved2 = 0;
3392 byte_count = params + 1 /* pad */ ;
3393 pSMB->ParameterCount = cpu_to_le16(params);
3394 pSMB->TotalParameterCount = pSMB->ParameterCount;
3395 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3396 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3397 pSMB->SetupCount = 1;
3398 pSMB->Reserved3 = 0;
3399 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3400 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3401 pSMB->hdr.smb_buf_length += byte_count;
3402 pSMB->ByteCount = cpu_to_le16(byte_count);
3403
3404 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3405 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3406 if (rc) {
3407 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3408 } else { /* decode response */
3409 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3410
3411 if (rc || (pSMBr->ByteCount < 13)) {
3412 rc = -EIO; /* bad smb */
3413 } else {
3414 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3415 response_data =
3416 (FILE_SYSTEM_POSIX_INFO
3417 *) (((char *) &pSMBr->hdr.Protocol) +
3418 data_offset);
3419 FSData->f_bsize =
3420 le32_to_cpu(response_data->BlockSize);
3421 FSData->f_blocks =
3422 le64_to_cpu(response_data->TotalBlocks);
3423 FSData->f_bfree =
3424 le64_to_cpu(response_data->BlocksAvail);
3425 if(response_data->UserBlocksAvail == -1) {
3426 FSData->f_bavail = FSData->f_bfree;
3427 } else {
3428 FSData->f_bavail =
3429 le64_to_cpu(response_data->UserBlocksAvail);
3430 }
3431 if(response_data->TotalFileNodes != -1)
3432 FSData->f_files =
3433 le64_to_cpu(response_data->TotalFileNodes);
3434 if(response_data->FreeFileNodes != -1)
3435 FSData->f_ffree =
3436 le64_to_cpu(response_data->FreeFileNodes);
3437 }
3438 }
3439 cifs_buf_release(pSMB);
3440
3441 if (rc == -EAGAIN)
3442 goto QFSPosixRetry;
3443
3444 return rc;
3445}
3446
3447
3448/* We can not use write of zero bytes trick to
3449 set file size due to need for large file support. Also note that
3450 this SetPathInfo is preferred to SetFileInfo based method in next
3451 routine which is only needed to work around a sharing violation bug
3452 in Samba which this routine can run into */
3453
3454int
3455CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003456 __u64 size, int SetAllocation,
3457 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458{
3459 struct smb_com_transaction2_spi_req *pSMB = NULL;
3460 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3461 struct file_end_of_file_info *parm_data;
3462 int name_len;
3463 int rc = 0;
3464 int bytes_returned = 0;
3465 __u16 params, byte_count, data_count, param_offset, offset;
3466
3467 cFYI(1, ("In SetEOF"));
3468SetEOFRetry:
3469 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3470 (void **) &pSMBr);
3471 if (rc)
3472 return rc;
3473
3474 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3475 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003476 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003477 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 name_len++; /* trailing null */
3479 name_len *= 2;
3480 } else { /* BB improve the check for buffer overruns BB */
3481 name_len = strnlen(fileName, PATH_MAX);
3482 name_len++; /* trailing null */
3483 strncpy(pSMB->FileName, fileName, name_len);
3484 }
3485 params = 6 + name_len;
3486 data_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 size from sess */
3489 pSMB->MaxSetupCount = 0;
3490 pSMB->Reserved = 0;
3491 pSMB->Flags = 0;
3492 pSMB->Timeout = 0;
3493 pSMB->Reserved2 = 0;
3494 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3495 InformationLevel) - 4;
3496 offset = param_offset + params;
3497 if(SetAllocation) {
3498 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3499 pSMB->InformationLevel =
3500 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3501 else
3502 pSMB->InformationLevel =
3503 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3504 } else /* Set File Size */ {
3505 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3506 pSMB->InformationLevel =
3507 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3508 else
3509 pSMB->InformationLevel =
3510 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3511 }
3512
3513 parm_data =
3514 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3515 offset);
3516 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3517 pSMB->DataOffset = cpu_to_le16(offset);
3518 pSMB->SetupCount = 1;
3519 pSMB->Reserved3 = 0;
3520 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3521 byte_count = 3 /* pad */ + params + data_count;
3522 pSMB->DataCount = cpu_to_le16(data_count);
3523 pSMB->TotalDataCount = pSMB->DataCount;
3524 pSMB->ParameterCount = cpu_to_le16(params);
3525 pSMB->TotalParameterCount = pSMB->ParameterCount;
3526 pSMB->Reserved4 = 0;
3527 pSMB->hdr.smb_buf_length += byte_count;
3528 parm_data->FileSize = cpu_to_le64(size);
3529 pSMB->ByteCount = cpu_to_le16(byte_count);
3530 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3531 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3532 if (rc) {
3533 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3534 }
3535
3536 cifs_buf_release(pSMB);
3537
3538 if (rc == -EAGAIN)
3539 goto SetEOFRetry;
3540
3541 return rc;
3542}
3543
3544int
3545CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3546 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3547{
3548 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3549 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3550 char *data_offset;
3551 struct file_end_of_file_info *parm_data;
3552 int rc = 0;
3553 int bytes_returned = 0;
3554 __u16 params, param_offset, offset, byte_count, count;
3555
3556 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3557 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003558 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3559
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 if (rc)
3561 return rc;
3562
Steve Frenchcd634992005-04-28 22:41:10 -07003563 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3564
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3566 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3567
3568 params = 6;
3569 pSMB->MaxSetupCount = 0;
3570 pSMB->Reserved = 0;
3571 pSMB->Flags = 0;
3572 pSMB->Timeout = 0;
3573 pSMB->Reserved2 = 0;
3574 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3575 offset = param_offset + params;
3576
3577 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3578
3579 count = sizeof(struct file_end_of_file_info);
3580 pSMB->MaxParameterCount = cpu_to_le16(2);
3581 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3582 pSMB->SetupCount = 1;
3583 pSMB->Reserved3 = 0;
3584 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3585 byte_count = 3 /* pad */ + params + count;
3586 pSMB->DataCount = cpu_to_le16(count);
3587 pSMB->ParameterCount = cpu_to_le16(params);
3588 pSMB->TotalDataCount = pSMB->DataCount;
3589 pSMB->TotalParameterCount = pSMB->ParameterCount;
3590 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3591 parm_data =
3592 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3593 offset);
3594 pSMB->DataOffset = cpu_to_le16(offset);
3595 parm_data->FileSize = cpu_to_le64(size);
3596 pSMB->Fid = fid;
3597 if(SetAllocation) {
3598 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3599 pSMB->InformationLevel =
3600 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3601 else
3602 pSMB->InformationLevel =
3603 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3604 } else /* Set File Size */ {
3605 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3606 pSMB->InformationLevel =
3607 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3608 else
3609 pSMB->InformationLevel =
3610 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3611 }
3612 pSMB->Reserved4 = 0;
3613 pSMB->hdr.smb_buf_length += byte_count;
3614 pSMB->ByteCount = cpu_to_le16(byte_count);
3615 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3616 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3617 if (rc) {
3618 cFYI(1,
3619 ("Send error in SetFileInfo (SetFileSize) = %d",
3620 rc));
3621 }
3622
3623 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003624 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625
3626 /* Note: On -EAGAIN error only caller can retry on handle based calls
3627 since file handle passed in no longer valid */
3628
3629 return rc;
3630}
3631
3632/* Some legacy servers such as NT4 require that the file times be set on
3633 an open handle, rather than by pathname - this is awkward due to
3634 potential access conflicts on the open, but it is unavoidable for these
3635 old servers since the only other choice is to go from 100 nanosecond DCE
3636 time and resort to the original setpathinfo level which takes the ancient
3637 DOS time format with 2 second granularity */
3638int
3639CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3640 __u16 fid)
3641{
3642 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3643 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3644 char *data_offset;
3645 int rc = 0;
3646 int bytes_returned = 0;
3647 __u16 params, param_offset, offset, byte_count, count;
3648
3649 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003650 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3651
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 if (rc)
3653 return rc;
3654
Steve Frenchcd634992005-04-28 22:41:10 -07003655 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3656
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 /* At this point there is no need to override the current pid
3658 with the pid of the opener, but that could change if we someday
3659 use an existing handle (rather than opening one on the fly) */
3660 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3661 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3662
3663 params = 6;
3664 pSMB->MaxSetupCount = 0;
3665 pSMB->Reserved = 0;
3666 pSMB->Flags = 0;
3667 pSMB->Timeout = 0;
3668 pSMB->Reserved2 = 0;
3669 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3670 offset = param_offset + params;
3671
3672 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3673
3674 count = sizeof (FILE_BASIC_INFO);
3675 pSMB->MaxParameterCount = cpu_to_le16(2);
3676 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3677 pSMB->SetupCount = 1;
3678 pSMB->Reserved3 = 0;
3679 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3680 byte_count = 3 /* pad */ + params + count;
3681 pSMB->DataCount = cpu_to_le16(count);
3682 pSMB->ParameterCount = cpu_to_le16(params);
3683 pSMB->TotalDataCount = pSMB->DataCount;
3684 pSMB->TotalParameterCount = pSMB->ParameterCount;
3685 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3686 pSMB->DataOffset = cpu_to_le16(offset);
3687 pSMB->Fid = fid;
3688 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3689 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3690 else
3691 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3692 pSMB->Reserved4 = 0;
3693 pSMB->hdr.smb_buf_length += byte_count;
3694 pSMB->ByteCount = cpu_to_le16(byte_count);
3695 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3696 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3697 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3698 if (rc) {
3699 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3700 }
3701
Steve Frenchcd634992005-04-28 22:41:10 -07003702 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
3704 /* Note: On -EAGAIN error only caller can retry on handle based calls
3705 since file handle passed in no longer valid */
3706
3707 return rc;
3708}
3709
3710
3711int
3712CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3713 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07003714 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715{
3716 TRANSACTION2_SPI_REQ *pSMB = NULL;
3717 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3718 int name_len;
3719 int rc = 0;
3720 int bytes_returned = 0;
3721 char *data_offset;
3722 __u16 params, param_offset, offset, byte_count, count;
3723
3724 cFYI(1, ("In SetTimes"));
3725
3726SetTimesRetry:
3727 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3728 (void **) &pSMBr);
3729 if (rc)
3730 return rc;
3731
3732 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3733 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003734 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003735 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 name_len++; /* trailing null */
3737 name_len *= 2;
3738 } else { /* BB improve the check for buffer overruns BB */
3739 name_len = strnlen(fileName, PATH_MAX);
3740 name_len++; /* trailing null */
3741 strncpy(pSMB->FileName, fileName, name_len);
3742 }
3743
3744 params = 6 + name_len;
3745 count = sizeof (FILE_BASIC_INFO);
3746 pSMB->MaxParameterCount = cpu_to_le16(2);
3747 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3748 pSMB->MaxSetupCount = 0;
3749 pSMB->Reserved = 0;
3750 pSMB->Flags = 0;
3751 pSMB->Timeout = 0;
3752 pSMB->Reserved2 = 0;
3753 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3754 InformationLevel) - 4;
3755 offset = param_offset + params;
3756 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3757 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3758 pSMB->DataOffset = cpu_to_le16(offset);
3759 pSMB->SetupCount = 1;
3760 pSMB->Reserved3 = 0;
3761 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3762 byte_count = 3 /* pad */ + params + count;
3763
3764 pSMB->DataCount = cpu_to_le16(count);
3765 pSMB->ParameterCount = cpu_to_le16(params);
3766 pSMB->TotalDataCount = pSMB->DataCount;
3767 pSMB->TotalParameterCount = pSMB->ParameterCount;
3768 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3769 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3770 else
3771 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3772 pSMB->Reserved4 = 0;
3773 pSMB->hdr.smb_buf_length += byte_count;
3774 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3775 pSMB->ByteCount = cpu_to_le16(byte_count);
3776 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3777 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3778 if (rc) {
3779 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3780 }
3781
3782 cifs_buf_release(pSMB);
3783
3784 if (rc == -EAGAIN)
3785 goto SetTimesRetry;
3786
3787 return rc;
3788}
3789
3790/* Can not be used to set time stamps yet (due to old DOS time format) */
3791/* Can be used to set attributes */
3792#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
3793 handling it anyway and NT4 was what we thought it would be needed for
3794 Do not delete it until we prove whether needed for Win9x though */
3795int
3796CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3797 __u16 dos_attrs, const struct nls_table *nls_codepage)
3798{
3799 SETATTR_REQ *pSMB = NULL;
3800 SETATTR_RSP *pSMBr = NULL;
3801 int rc = 0;
3802 int bytes_returned;
3803 int name_len;
3804
3805 cFYI(1, ("In SetAttrLegacy"));
3806
3807SetAttrLgcyRetry:
3808 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3809 (void **) &pSMBr);
3810 if (rc)
3811 return rc;
3812
3813 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3814 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003815 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 PATH_MAX, nls_codepage);
3817 name_len++; /* trailing null */
3818 name_len *= 2;
3819 } else { /* BB improve the check for buffer overruns BB */
3820 name_len = strnlen(fileName, PATH_MAX);
3821 name_len++; /* trailing null */
3822 strncpy(pSMB->fileName, fileName, name_len);
3823 }
3824 pSMB->attr = cpu_to_le16(dos_attrs);
3825 pSMB->BufferFormat = 0x04;
3826 pSMB->hdr.smb_buf_length += name_len + 1;
3827 pSMB->ByteCount = cpu_to_le16(name_len + 1);
3828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3830 if (rc) {
3831 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3832 }
3833
3834 cifs_buf_release(pSMB);
3835
3836 if (rc == -EAGAIN)
3837 goto SetAttrLgcyRetry;
3838
3839 return rc;
3840}
3841#endif /* temporarily unneeded SetAttr legacy function */
3842
3843int
3844CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003845 char *fileName, __u64 mode, __u64 uid, __u64 gid,
3846 dev_t device, const struct nls_table *nls_codepage,
3847 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848{
3849 TRANSACTION2_SPI_REQ *pSMB = NULL;
3850 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3851 int name_len;
3852 int rc = 0;
3853 int bytes_returned = 0;
3854 FILE_UNIX_BASIC_INFO *data_offset;
3855 __u16 params, param_offset, offset, count, byte_count;
3856
3857 cFYI(1, ("In SetUID/GID/Mode"));
3858setPermsRetry:
3859 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3860 (void **) &pSMBr);
3861 if (rc)
3862 return rc;
3863
3864 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3865 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003866 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003867 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 name_len++; /* trailing null */
3869 name_len *= 2;
3870 } else { /* BB improve the check for buffer overruns BB */
3871 name_len = strnlen(fileName, PATH_MAX);
3872 name_len++; /* trailing null */
3873 strncpy(pSMB->FileName, fileName, name_len);
3874 }
3875
3876 params = 6 + name_len;
3877 count = sizeof (FILE_UNIX_BASIC_INFO);
3878 pSMB->MaxParameterCount = cpu_to_le16(2);
3879 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3880 pSMB->MaxSetupCount = 0;
3881 pSMB->Reserved = 0;
3882 pSMB->Flags = 0;
3883 pSMB->Timeout = 0;
3884 pSMB->Reserved2 = 0;
3885 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3886 InformationLevel) - 4;
3887 offset = param_offset + params;
3888 data_offset =
3889 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3890 offset);
3891 memset(data_offset, 0, count);
3892 pSMB->DataOffset = cpu_to_le16(offset);
3893 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3894 pSMB->SetupCount = 1;
3895 pSMB->Reserved3 = 0;
3896 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3897 byte_count = 3 /* pad */ + params + count;
3898 pSMB->ParameterCount = cpu_to_le16(params);
3899 pSMB->DataCount = cpu_to_le16(count);
3900 pSMB->TotalParameterCount = pSMB->ParameterCount;
3901 pSMB->TotalDataCount = pSMB->DataCount;
3902 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3903 pSMB->Reserved4 = 0;
3904 pSMB->hdr.smb_buf_length += byte_count;
3905 data_offset->Uid = cpu_to_le64(uid);
3906 data_offset->Gid = cpu_to_le64(gid);
3907 /* better to leave device as zero when it is */
3908 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3909 data_offset->DevMinor = cpu_to_le64(MINOR(device));
3910 data_offset->Permissions = cpu_to_le64(mode);
3911
3912 if(S_ISREG(mode))
3913 data_offset->Type = cpu_to_le32(UNIX_FILE);
3914 else if(S_ISDIR(mode))
3915 data_offset->Type = cpu_to_le32(UNIX_DIR);
3916 else if(S_ISLNK(mode))
3917 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3918 else if(S_ISCHR(mode))
3919 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3920 else if(S_ISBLK(mode))
3921 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3922 else if(S_ISFIFO(mode))
3923 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3924 else if(S_ISSOCK(mode))
3925 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3926
3927
3928 pSMB->ByteCount = cpu_to_le16(byte_count);
3929 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3931 if (rc) {
3932 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3933 }
3934
3935 if (pSMB)
3936 cifs_buf_release(pSMB);
3937 if (rc == -EAGAIN)
3938 goto setPermsRetry;
3939 return rc;
3940}
3941
3942int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
3943 const int notify_subdirs, const __u16 netfid,
3944 __u32 filter, const struct nls_table *nls_codepage)
3945{
3946 int rc = 0;
3947 struct smb_com_transaction_change_notify_req * pSMB = NULL;
3948 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3949 int bytes_returned;
3950
3951 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3952 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3953 (void **) &pSMBr);
3954 if (rc)
3955 return rc;
3956
3957 pSMB->TotalParameterCount = 0 ;
3958 pSMB->TotalDataCount = 0;
3959 pSMB->MaxParameterCount = cpu_to_le32(2);
3960 /* BB find exact data count max from sess structure BB */
3961 pSMB->MaxDataCount = 0; /* same in little endian or be */
3962 pSMB->MaxSetupCount = 4;
3963 pSMB->Reserved = 0;
3964 pSMB->ParameterOffset = 0;
3965 pSMB->DataCount = 0;
3966 pSMB->DataOffset = 0;
3967 pSMB->SetupCount = 4; /* single byte does not need le conversion */
3968 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3969 pSMB->ParameterCount = pSMB->TotalParameterCount;
3970 if(notify_subdirs)
3971 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3972 pSMB->Reserved2 = 0;
3973 pSMB->CompletionFilter = cpu_to_le32(filter);
3974 pSMB->Fid = netfid; /* file handle always le */
3975 pSMB->ByteCount = 0;
3976
3977 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3978 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3979 if (rc) {
3980 cFYI(1, ("Error in Notify = %d", rc));
3981 }
3982 cifs_buf_release(pSMB);
3983 return rc;
3984}
3985#ifdef CONFIG_CIFS_XATTR
3986ssize_t
3987CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3988 const unsigned char *searchName,
3989 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07003990 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991{
3992 /* BB assumes one setup word */
3993 TRANSACTION2_QPI_REQ *pSMB = NULL;
3994 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3995 int rc = 0;
3996 int bytes_returned;
3997 int name_len;
3998 struct fea * temp_fea;
3999 char * temp_ptr;
4000 __u16 params, byte_count;
4001
4002 cFYI(1, ("In Query All EAs path %s", searchName));
4003QAllEAsRetry:
4004 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4005 (void **) &pSMBr);
4006 if (rc)
4007 return rc;
4008
4009 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4010 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004011 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004012 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 name_len++; /* trailing null */
4014 name_len *= 2;
4015 } else { /* BB improve the check for buffer overruns BB */
4016 name_len = strnlen(searchName, PATH_MAX);
4017 name_len++; /* trailing null */
4018 strncpy(pSMB->FileName, searchName, name_len);
4019 }
4020
4021 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4022 pSMB->TotalDataCount = 0;
4023 pSMB->MaxParameterCount = cpu_to_le16(2);
4024 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4025 pSMB->MaxSetupCount = 0;
4026 pSMB->Reserved = 0;
4027 pSMB->Flags = 0;
4028 pSMB->Timeout = 0;
4029 pSMB->Reserved2 = 0;
4030 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4031 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4032 pSMB->DataCount = 0;
4033 pSMB->DataOffset = 0;
4034 pSMB->SetupCount = 1;
4035 pSMB->Reserved3 = 0;
4036 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4037 byte_count = params + 1 /* pad */ ;
4038 pSMB->TotalParameterCount = cpu_to_le16(params);
4039 pSMB->ParameterCount = pSMB->TotalParameterCount;
4040 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4041 pSMB->Reserved4 = 0;
4042 pSMB->hdr.smb_buf_length += byte_count;
4043 pSMB->ByteCount = cpu_to_le16(byte_count);
4044
4045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4047 if (rc) {
4048 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4049 } else { /* decode response */
4050 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4051
4052 /* BB also check enough total bytes returned */
4053 /* BB we need to improve the validity checking
4054 of these trans2 responses */
4055 if (rc || (pSMBr->ByteCount < 4))
4056 rc = -EIO; /* bad smb */
4057 /* else if (pFindData){
4058 memcpy((char *) pFindData,
4059 (char *) &pSMBr->hdr.Protocol +
4060 data_offset, kl);
4061 }*/ else {
4062 /* check that length of list is not more than bcc */
4063 /* check that each entry does not go beyond length
4064 of list */
4065 /* check that each element of each entry does not
4066 go beyond end of list */
4067 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4068 struct fealist * ea_response_data;
4069 rc = 0;
4070 /* validate_trans2_offsets() */
4071 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4072 ea_response_data = (struct fealist *)
4073 (((char *) &pSMBr->hdr.Protocol) +
4074 data_offset);
4075 name_len = le32_to_cpu(ea_response_data->list_len);
4076 cFYI(1,("ea length %d", name_len));
4077 if(name_len <= 8) {
4078 /* returned EA size zeroed at top of function */
4079 cFYI(1,("empty EA list returned from server"));
4080 } else {
4081 /* account for ea list len */
4082 name_len -= 4;
4083 temp_fea = ea_response_data->list;
4084 temp_ptr = (char *)temp_fea;
4085 while(name_len > 0) {
4086 __u16 value_len;
4087 name_len -= 4;
4088 temp_ptr += 4;
4089 rc += temp_fea->name_len;
4090 /* account for prefix user. and trailing null */
4091 rc = rc + 5 + 1;
4092 if(rc<(int)buf_size) {
4093 memcpy(EAData,"user.",5);
4094 EAData+=5;
4095 memcpy(EAData,temp_ptr,temp_fea->name_len);
4096 EAData+=temp_fea->name_len;
4097 /* null terminate name */
4098 *EAData = 0;
4099 EAData = EAData + 1;
4100 } else if(buf_size == 0) {
4101 /* skip copy - calc size only */
4102 } else {
4103 /* stop before overrun buffer */
4104 rc = -ERANGE;
4105 break;
4106 }
4107 name_len -= temp_fea->name_len;
4108 temp_ptr += temp_fea->name_len;
4109 /* account for trailing null */
4110 name_len--;
4111 temp_ptr++;
4112 value_len = le16_to_cpu(temp_fea->value_len);
4113 name_len -= value_len;
4114 temp_ptr += value_len;
4115 /* BB check that temp_ptr is still within smb BB*/
4116 /* no trailing null to account for in value len */
4117 /* go on to next EA */
4118 temp_fea = (struct fea *)temp_ptr;
4119 }
4120 }
4121 }
4122 }
4123 if (pSMB)
4124 cifs_buf_release(pSMB);
4125 if (rc == -EAGAIN)
4126 goto QAllEAsRetry;
4127
4128 return (ssize_t)rc;
4129}
4130
4131ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4132 const unsigned char * searchName,const unsigned char * ea_name,
4133 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004134 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135{
4136 TRANSACTION2_QPI_REQ *pSMB = NULL;
4137 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4138 int rc = 0;
4139 int bytes_returned;
4140 int name_len;
4141 struct fea * temp_fea;
4142 char * temp_ptr;
4143 __u16 params, byte_count;
4144
4145 cFYI(1, ("In Query EA path %s", searchName));
4146QEARetry:
4147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4148 (void **) &pSMBr);
4149 if (rc)
4150 return rc;
4151
4152 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4153 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004154 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004155 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 name_len++; /* trailing null */
4157 name_len *= 2;
4158 } else { /* BB improve the check for buffer overruns BB */
4159 name_len = strnlen(searchName, PATH_MAX);
4160 name_len++; /* trailing null */
4161 strncpy(pSMB->FileName, searchName, name_len);
4162 }
4163
4164 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4165 pSMB->TotalDataCount = 0;
4166 pSMB->MaxParameterCount = cpu_to_le16(2);
4167 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4168 pSMB->MaxSetupCount = 0;
4169 pSMB->Reserved = 0;
4170 pSMB->Flags = 0;
4171 pSMB->Timeout = 0;
4172 pSMB->Reserved2 = 0;
4173 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4174 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4175 pSMB->DataCount = 0;
4176 pSMB->DataOffset = 0;
4177 pSMB->SetupCount = 1;
4178 pSMB->Reserved3 = 0;
4179 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4180 byte_count = params + 1 /* pad */ ;
4181 pSMB->TotalParameterCount = cpu_to_le16(params);
4182 pSMB->ParameterCount = pSMB->TotalParameterCount;
4183 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4184 pSMB->Reserved4 = 0;
4185 pSMB->hdr.smb_buf_length += byte_count;
4186 pSMB->ByteCount = cpu_to_le16(byte_count);
4187
4188 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4189 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4190 if (rc) {
4191 cFYI(1, ("Send error in Query EA = %d", rc));
4192 } else { /* decode response */
4193 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4194
4195 /* BB also check enough total bytes returned */
4196 /* BB we need to improve the validity checking
4197 of these trans2 responses */
4198 if (rc || (pSMBr->ByteCount < 4))
4199 rc = -EIO; /* bad smb */
4200 /* else if (pFindData){
4201 memcpy((char *) pFindData,
4202 (char *) &pSMBr->hdr.Protocol +
4203 data_offset, kl);
4204 }*/ else {
4205 /* check that length of list is not more than bcc */
4206 /* check that each entry does not go beyond length
4207 of list */
4208 /* check that each element of each entry does not
4209 go beyond end of list */
4210 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4211 struct fealist * ea_response_data;
4212 rc = -ENODATA;
4213 /* validate_trans2_offsets() */
4214 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4215 ea_response_data = (struct fealist *)
4216 (((char *) &pSMBr->hdr.Protocol) +
4217 data_offset);
4218 name_len = le32_to_cpu(ea_response_data->list_len);
4219 cFYI(1,("ea length %d", name_len));
4220 if(name_len <= 8) {
4221 /* returned EA size zeroed at top of function */
4222 cFYI(1,("empty EA list returned from server"));
4223 } else {
4224 /* account for ea list len */
4225 name_len -= 4;
4226 temp_fea = ea_response_data->list;
4227 temp_ptr = (char *)temp_fea;
4228 /* loop through checking if we have a matching
4229 name and then return the associated value */
4230 while(name_len > 0) {
4231 __u16 value_len;
4232 name_len -= 4;
4233 temp_ptr += 4;
4234 value_len = le16_to_cpu(temp_fea->value_len);
4235 /* BB validate that value_len falls within SMB,
4236 even though maximum for name_len is 255 */
4237 if(memcmp(temp_fea->name,ea_name,
4238 temp_fea->name_len) == 0) {
4239 /* found a match */
4240 rc = value_len;
4241 /* account for prefix user. and trailing null */
4242 if(rc<=(int)buf_size) {
4243 memcpy(ea_value,
4244 temp_fea->name+temp_fea->name_len+1,
4245 rc);
4246 /* ea values, unlike ea names,
4247 are not null terminated */
4248 } else if(buf_size == 0) {
4249 /* skip copy - calc size only */
4250 } else {
4251 /* stop before overrun buffer */
4252 rc = -ERANGE;
4253 }
4254 break;
4255 }
4256 name_len -= temp_fea->name_len;
4257 temp_ptr += temp_fea->name_len;
4258 /* account for trailing null */
4259 name_len--;
4260 temp_ptr++;
4261 name_len -= value_len;
4262 temp_ptr += value_len;
4263 /* no trailing null to account for in value len */
4264 /* go on to next EA */
4265 temp_fea = (struct fea *)temp_ptr;
4266 }
4267 }
4268 }
4269 }
4270 if (pSMB)
4271 cifs_buf_release(pSMB);
4272 if (rc == -EAGAIN)
4273 goto QEARetry;
4274
4275 return (ssize_t)rc;
4276}
4277
4278int
4279CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4280 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004281 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4282 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283{
4284 struct smb_com_transaction2_spi_req *pSMB = NULL;
4285 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4286 struct fealist *parm_data;
4287 int name_len;
4288 int rc = 0;
4289 int bytes_returned = 0;
4290 __u16 params, param_offset, byte_count, offset, count;
4291
4292 cFYI(1, ("In SetEA"));
4293SetEARetry:
4294 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4295 (void **) &pSMBr);
4296 if (rc)
4297 return rc;
4298
4299 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4300 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004301 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004302 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 name_len++; /* trailing null */
4304 name_len *= 2;
4305 } else { /* BB improve the check for buffer overruns BB */
4306 name_len = strnlen(fileName, PATH_MAX);
4307 name_len++; /* trailing null */
4308 strncpy(pSMB->FileName, fileName, name_len);
4309 }
4310
4311 params = 6 + name_len;
4312
4313 /* done calculating parms using name_len of file name,
4314 now use name_len to calculate length of ea name
4315 we are going to create in the inode xattrs */
4316 if(ea_name == NULL)
4317 name_len = 0;
4318 else
4319 name_len = strnlen(ea_name,255);
4320
4321 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4322 pSMB->MaxParameterCount = cpu_to_le16(2);
4323 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4324 pSMB->MaxSetupCount = 0;
4325 pSMB->Reserved = 0;
4326 pSMB->Flags = 0;
4327 pSMB->Timeout = 0;
4328 pSMB->Reserved2 = 0;
4329 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4330 InformationLevel) - 4;
4331 offset = param_offset + params;
4332 pSMB->InformationLevel =
4333 cpu_to_le16(SMB_SET_FILE_EA);
4334
4335 parm_data =
4336 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4337 offset);
4338 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4339 pSMB->DataOffset = cpu_to_le16(offset);
4340 pSMB->SetupCount = 1;
4341 pSMB->Reserved3 = 0;
4342 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4343 byte_count = 3 /* pad */ + params + count;
4344 pSMB->DataCount = cpu_to_le16(count);
4345 parm_data->list_len = cpu_to_le32(count);
4346 parm_data->list[0].EA_flags = 0;
4347 /* we checked above that name len is less than 255 */
4348 parm_data->list[0].name_len = (__u8)name_len;;
4349 /* EA names are always ASCII */
4350 if(ea_name)
4351 strncpy(parm_data->list[0].name,ea_name,name_len);
4352 parm_data->list[0].name[name_len] = 0;
4353 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4354 /* caller ensures that ea_value_len is less than 64K but
4355 we need to ensure that it fits within the smb */
4356
4357 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4358 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4359 if(ea_value_len)
4360 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4361
4362 pSMB->TotalDataCount = pSMB->DataCount;
4363 pSMB->ParameterCount = cpu_to_le16(params);
4364 pSMB->TotalParameterCount = pSMB->ParameterCount;
4365 pSMB->Reserved4 = 0;
4366 pSMB->hdr.smb_buf_length += byte_count;
4367 pSMB->ByteCount = cpu_to_le16(byte_count);
4368 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4369 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4370 if (rc) {
4371 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4372 }
4373
4374 cifs_buf_release(pSMB);
4375
4376 if (rc == -EAGAIN)
4377 goto SetEARetry;
4378
4379 return rc;
4380}
4381
4382#endif