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