blob: 74733851cfad5f49e78cfc488475e1dca0916297 [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
769 pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL);
770
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 */
780 pSMB->OpenFunction = convert_disposition(openDisposition);
781 count += name_len;
782 pSMB->hdr.smb_buf_length += count;
783
784 pSMB->ByteCount = cpu_to_le16(count);
785 /* long_op set to 1 to allow for oplock break timeouts */
786 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
787 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
788 cifs_stats_inc(&tcon->num_opens);
789 if (rc) {
790 cFYI(1, ("Error in Open = %d", rc));
791 } else {
792 /* BB verify if wct == 15 */
793
794/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
795
796 *netfid = pSMBr->Fid; /* cifs fid stays in le */
797 /* Let caller know file was created so we can set the mode. */
798 /* Do we care about the CreateAction in any other cases? */
799 /* BB FIXME BB */
800/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
801 *pOplock |= CIFS_CREATE_ACTION; */
802 /* BB FIXME END */
803
804 if(pfile_info) {
805 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
806 pfile_info->LastAccessTime = 0; /* BB fixme */
807 pfile_info->LastWriteTime = 0; /* BB fixme */
808 pfile_info->ChangeTime = 0; /* BB fixme */
809 pfile_info->Attributes = pSMBr->FileAttributes;
810 /* the file_info buf is endian converted by caller */
811 pfile_info->AllocationSize = pSMBr->EndOfFile;
812 pfile_info->EndOfFile = pSMBr->EndOfFile;
813 pfile_info->NumberOfLinks = cpu_to_le32(1);
814 }
815 }
816
817 cifs_buf_release(pSMB);
818 if (rc == -EAGAIN)
819 goto OldOpenRetry;
820 return rc;
821}
822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823int
824CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
825 const char *fileName, const int openDisposition,
826 const int access_flags, const int create_options, __u16 * netfid,
827 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700828 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829{
830 int rc = -EACCES;
831 OPEN_REQ *pSMB = NULL;
832 OPEN_RSP *pSMBr = NULL;
833 int bytes_returned;
834 int name_len;
835 __u16 count;
836
837openRetry:
838 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
839 (void **) &pSMBr);
840 if (rc)
841 return rc;
842
843 pSMB->AndXCommand = 0xFF; /* none */
844
845 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
846 count = 1; /* account for one byte pad to word boundary */
847 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500848 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700849 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 name_len++; /* trailing null */
851 name_len *= 2;
852 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700853 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 count = 0; /* no pad */
855 name_len = strnlen(fileName, PATH_MAX);
856 name_len++; /* trailing null */
857 pSMB->NameLength = cpu_to_le16(name_len);
858 strncpy(pSMB->fileName, fileName, name_len);
859 }
860 if (*pOplock & REQ_OPLOCK)
861 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
862 else if (*pOplock & REQ_BATCHOPLOCK) {
863 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
864 }
865 pSMB->DesiredAccess = cpu_to_le32(access_flags);
866 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700867 /* set file as system file if special file such
868 as fifo and server expecting SFU style and
869 no Unix extensions */
870 if(create_options & CREATE_OPTION_SPECIAL)
871 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
872 else
873 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 /* XP does not handle ATTR_POSIX_SEMANTICS */
875 /* but it helps speed up case sensitive checks for other
876 servers such as Samba */
877 if (tcon->ses->capabilities & CAP_UNIX)
878 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
879
880 /* if ((omode & S_IWUGO) == 0)
881 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
882 /* Above line causes problems due to vfs splitting create into two
883 pieces - need to set mode after file created not while it is
884 being created */
885 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
886 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700887 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700888 /* BB Expirement with various impersonation levels and verify */
889 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 pSMB->SecurityFlags =
891 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
892
893 count += name_len;
894 pSMB->hdr.smb_buf_length += count;
895
896 pSMB->ByteCount = cpu_to_le16(count);
897 /* long_op set to 1 to allow for oplock break timeouts */
898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
899 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -0700900 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (rc) {
902 cFYI(1, ("Error in Open = %d", rc));
903 } else {
Steve French09d1db52005-04-28 22:41:08 -0700904 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 *netfid = pSMBr->Fid; /* cifs fid stays in le */
906 /* Let caller know file was created so we can set the mode. */
907 /* Do we care about the CreateAction in any other cases? */
908 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
909 *pOplock |= CIFS_CREATE_ACTION;
910 if(pfile_info) {
911 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
912 36 /* CreationTime to Attributes */);
913 /* the file_info buf is endian converted by caller */
914 pfile_info->AllocationSize = pSMBr->AllocationSize;
915 pfile_info->EndOfFile = pSMBr->EndOfFile;
916 pfile_info->NumberOfLinks = cpu_to_le32(1);
917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 cifs_buf_release(pSMB);
921 if (rc == -EAGAIN)
922 goto openRetry;
923 return rc;
924}
925
Steve Frencha9d02ad2005-08-24 23:06:05 -0700926int
927SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
928 const int netfid, unsigned int count,
929 const __u64 lseek, unsigned int *nbytes, char **buf)
930{
931 int rc = -EACCES;
932 READX_REQ *pSMB = NULL;
933 READ_RSP *pSMBr = NULL;
934 char *pReadData = NULL;
935 int bytes_returned;
936
937 cFYI(1,("Legacy read %d bytes fid %d",count,netfid));
938
939 /* field is shorter in legacy read, only 16 bits */
940 if(count > 2048)
941 count = 2048; /* BB FIXME make this configurable */
942
943 if(lseek > 0xFFFFFFFF)
944 return -EIO; /* can not read that far into file on old server */
945
946 *nbytes = 0;
947 rc = smb_init(SMB_COM_READ_ANDX, 10, tcon, (void **) &pSMB,
948 (void **) &pSMBr);
949 if (rc)
950 return rc;
951
952 /* tcon and ses pointer are checked in smb_init */
953 if (tcon->ses->server == NULL)
954 return -ECONNABORTED;
955
956 pSMB->AndXCommand = 0xFF; /* none */
957 pSMB->Fid = netfid;
958 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
959 pSMB->Remaining = 0;
960 pSMB->MaxCount = cpu_to_le16(count);
961 pSMB->Reserved = 0; /* Must Be Zero */
962 pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
963
964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
966 cifs_stats_inc(&tcon->num_reads);
967 if (rc) {
968 cERROR(1, ("Send error in legacy read = %d", rc));
969 } else {
970 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
971 data_length = data_length << 16;
972 data_length += le16_to_cpu(pSMBr->DataLength);
973 *nbytes = data_length;
974
975 /*check that DataLength would not go beyond end of SMB */
976 if ((data_length > CIFSMaxBufSize) || (data_length > count)) {
977 cFYI(1,("bad length %d for count %d",data_length,count));
978 rc = -EIO;
979 *nbytes = 0;
980 } else {
981 pReadData = (char *) (&pSMBr->hdr.Protocol) +
982 le16_to_cpu(pSMBr->DataOffset);
983/* if(rc = copy_to_user(buf, pReadData, data_length)) {
984 cERROR(1,("Faulting on read rc = %d",rc));
985 rc = -EFAULT;
986 }*/ /* can not use copy_to_user when using page cache*/
987 if(*buf)
988 memcpy(*buf,pReadData,data_length);
989 }
990 }
991 if(*buf)
992 cifs_buf_release(pSMB);
993 else
994 *buf = (char *)pSMB;
995
996 /* Note: On -EAGAIN error only caller can retry on handle based calls
997 since file handle passed in no longer valid */
998 return rc;
999}
1000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001/* If no buffer passed in, then caller wants to do the copy
1002 as in the case of readpages so the SMB buffer must be
1003 freed by the caller */
1004
1005int
1006CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
1007 const int netfid, const unsigned int count,
1008 const __u64 lseek, unsigned int *nbytes, char **buf)
1009{
1010 int rc = -EACCES;
1011 READ_REQ *pSMB = NULL;
1012 READ_RSP *pSMBr = NULL;
1013 char *pReadData = NULL;
1014 int bytes_returned;
1015
1016 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
1017
1018 *nbytes = 0;
1019 rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
1020 (void **) &pSMBr);
1021 if (rc)
1022 return rc;
1023
1024 /* tcon and ses pointer are checked in smb_init */
1025 if (tcon->ses->server == NULL)
1026 return -ECONNABORTED;
1027
1028 pSMB->AndXCommand = 0xFF; /* none */
1029 pSMB->Fid = netfid;
1030 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1031 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1032 pSMB->Remaining = 0;
1033 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1034 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1035 pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
1036
1037 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1038 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001039 cifs_stats_inc(&tcon->num_reads);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 if (rc) {
1041 cERROR(1, ("Send error in read = %d", rc));
1042 } else {
1043 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1044 data_length = data_length << 16;
1045 data_length += le16_to_cpu(pSMBr->DataLength);
1046 *nbytes = data_length;
1047
1048 /*check that DataLength would not go beyond end of SMB */
1049 if ((data_length > CIFSMaxBufSize)
1050 || (data_length > count)) {
1051 cFYI(1,("bad length %d for count %d",data_length,count));
1052 rc = -EIO;
1053 *nbytes = 0;
1054 } else {
1055 pReadData =
1056 (char *) (&pSMBr->hdr.Protocol) +
1057 le16_to_cpu(pSMBr->DataOffset);
1058/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1059 cERROR(1,("Faulting on read rc = %d",rc));
1060 rc = -EFAULT;
1061 }*/ /* can not use copy_to_user when using page cache*/
1062 if(*buf)
1063 memcpy(*buf,pReadData,data_length);
1064 }
1065 }
1066 if(*buf)
1067 cifs_buf_release(pSMB);
1068 else
1069 *buf = (char *)pSMB;
1070
1071 /* Note: On -EAGAIN error only caller can retry on handle based calls
1072 since file handle passed in no longer valid */
1073 return rc;
1074}
1075
1076int
1077CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1078 const int netfid, const unsigned int count,
1079 const __u64 offset, unsigned int *nbytes, const char *buf,
1080 const char __user * ubuf, const int long_op)
1081{
1082 int rc = -EACCES;
1083 WRITE_REQ *pSMB = NULL;
1084 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001085 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 __u32 bytes_sent;
1087 __u16 byte_count;
1088
1089 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001090 if(tcon->ses == NULL)
1091 return -ECONNABORTED;
1092
1093 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1094 wct = 14;
1095 else
1096 wct = 12;
1097
1098 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 (void **) &pSMBr);
1100 if (rc)
1101 return rc;
1102 /* tcon and ses pointer are checked in smb_init */
1103 if (tcon->ses->server == NULL)
1104 return -ECONNABORTED;
1105
1106 pSMB->AndXCommand = 0xFF; /* none */
1107 pSMB->Fid = netfid;
1108 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001109 if(wct == 14)
1110 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1111 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1112 return -EIO;
1113
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 pSMB->Reserved = 0xFFFFFFFF;
1115 pSMB->WriteMode = 0;
1116 pSMB->Remaining = 0;
1117
1118 /* Can increase buffer size if buffer is big enough in some cases - ie we
1119 can send more if LARGE_WRITE_X capability returned by the server and if
1120 our buffer is big enough or if we convert to iovecs on socket writes
1121 and eliminate the copy to the CIFS buffer */
1122 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1123 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1124 } else {
1125 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1126 & ~0xFF;
1127 }
1128
1129 if (bytes_sent > count)
1130 bytes_sent = count;
1131 pSMB->DataOffset =
1132 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1133 if(buf)
1134 memcpy(pSMB->Data,buf,bytes_sent);
1135 else if(ubuf) {
1136 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1137 cifs_buf_release(pSMB);
1138 return -EFAULT;
1139 }
1140 } else {
1141 /* No buffer */
1142 cifs_buf_release(pSMB);
1143 return -EINVAL;
1144 }
1145
1146 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1147 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1148 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1149 pSMB->hdr.smb_buf_length += bytes_sent+1;
Steve French1c955182005-08-30 20:58:07 -07001150
1151 if(wct == 14)
1152 pSMB->ByteCount = cpu_to_le16(byte_count);
1153 else { /* old style write has byte count 4 bytes earlier */
1154 struct smb_com_writex_req * pSMBW =
1155 (struct smb_com_writex_req *)pSMB;
1156 pSMBW->ByteCount = cpu_to_le16(byte_count);
1157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
1159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1160 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001161 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 if (rc) {
1163 cFYI(1, ("Send error in write = %d", rc));
1164 *nbytes = 0;
1165 } else {
1166 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1167 *nbytes = (*nbytes) << 16;
1168 *nbytes += le16_to_cpu(pSMBr->Count);
1169 }
1170
1171 cifs_buf_release(pSMB);
1172
1173 /* Note: On -EAGAIN error only caller can retry on handle based calls
1174 since file handle passed in no longer valid */
1175
1176 return rc;
1177}
1178
1179#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001180int
1181CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 const int netfid, const unsigned int count,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001183 const __u64 offset, unsigned int *nbytes, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 const int long_op)
1185{
1186 int rc = -EACCES;
1187 WRITE_REQ *pSMB = NULL;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001188 int bytes_returned;
1189 int smb_hdr_len;
1190 __u32 bytes_sent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 __u16 byte_count;
1192
Steve French0c0ff092005-06-23 19:31:17 -05001193 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (rc)
1196 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 /* tcon and ses pointer are checked in smb_init */
1198 if (tcon->ses->server == NULL)
1199 return -ECONNABORTED;
1200
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001201 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 pSMB->Fid = netfid;
1203 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1204 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1205 pSMB->Reserved = 0xFFFFFFFF;
1206 pSMB->WriteMode = 0;
1207 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001208
1209 /* Can increase buffer size if buffer is big enough in some cases - ie
1210 can send more if LARGE_WRITE_X capability returned by the server and if
1211 our buffer is big enough or if we convert to iovecs on socket writes
1212 and eliminate the copy to the CIFS buffer */
1213 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1214 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1215 } else {
1216 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1217 & ~0xFF;
1218 }
1219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 if (bytes_sent > count)
1221 bytes_sent = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 pSMB->DataOffset =
1223 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1224
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001225 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1226 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1227 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1228 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1229 pSMB->hdr.smb_buf_length += bytes_sent+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 pSMB->ByteCount = cpu_to_le16(byte_count);
1231
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001232 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1233 buf, bytes_sent, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001234 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 if (rc) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001236 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001238 } else {
1239 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1240 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1241 *nbytes = (*nbytes) << 16;
1242 *nbytes += le16_to_cpu(pSMBr->Count);
1243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245 cifs_small_buf_release(pSMB);
1246
1247 /* Note: On -EAGAIN error only caller can retry on handle based calls
1248 since file handle passed in no longer valid */
1249
1250 return rc;
1251}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001252
1253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254#endif /* CIFS_EXPERIMENTAL */
1255
1256int
1257CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1258 const __u16 smb_file_id, const __u64 len,
1259 const __u64 offset, const __u32 numUnlock,
1260 const __u32 numLock, const __u8 lockType, const int waitFlag)
1261{
1262 int rc = 0;
1263 LOCK_REQ *pSMB = NULL;
1264 LOCK_RSP *pSMBr = NULL;
1265 int bytes_returned;
1266 int timeout = 0;
1267 __u16 count;
1268
1269 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001270 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 if (rc)
1273 return rc;
1274
Steve French46810cb2005-04-28 22:41:09 -07001275 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1276
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1278 timeout = -1; /* no response expected */
1279 pSMB->Timeout = 0;
1280 } else if (waitFlag == TRUE) {
1281 timeout = 3; /* blocking operation, no timeout */
1282 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1283 } else {
1284 pSMB->Timeout = 0;
1285 }
1286
1287 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1288 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1289 pSMB->LockType = lockType;
1290 pSMB->AndXCommand = 0xFF; /* none */
1291 pSMB->Fid = smb_file_id; /* netfid stays le */
1292
1293 if((numLock != 0) || (numUnlock != 0)) {
1294 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1295 /* BB where to store pid high? */
1296 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1297 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1298 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1299 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1300 count = sizeof(LOCKING_ANDX_RANGE);
1301 } else {
1302 /* oplock break */
1303 count = 0;
1304 }
1305 pSMB->hdr.smb_buf_length += count;
1306 pSMB->ByteCount = cpu_to_le16(count);
1307
1308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1309 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001310 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (rc) {
1312 cFYI(1, ("Send error in Lock = %d", rc));
1313 }
Steve French46810cb2005-04-28 22:41:09 -07001314 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
1316 /* Note: On -EAGAIN error only caller can retry on handle based calls
1317 since file handle passed in no longer valid */
1318 return rc;
1319}
1320
1321int
1322CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1323{
1324 int rc = 0;
1325 CLOSE_REQ *pSMB = NULL;
1326 CLOSE_RSP *pSMBr = NULL;
1327 int bytes_returned;
1328 cFYI(1, ("In CIFSSMBClose"));
1329
1330/* do not retry on dead session on close */
1331 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1332 if(rc == -EAGAIN)
1333 return 0;
1334 if (rc)
1335 return rc;
1336
1337 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1338
1339 pSMB->FileID = (__u16) smb_file_id;
1340 pSMB->LastWriteTime = 0;
1341 pSMB->ByteCount = 0;
1342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001344 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 if (rc) {
1346 if(rc!=-EINTR) {
1347 /* EINTR is expected when user ctl-c to kill app */
1348 cERROR(1, ("Send error in Close = %d", rc));
1349 }
1350 }
1351
1352 cifs_small_buf_release(pSMB);
1353
1354 /* Since session is dead, file will be closed on server already */
1355 if(rc == -EAGAIN)
1356 rc = 0;
1357
1358 return rc;
1359}
1360
1361int
1362CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1363 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001364 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
1366 int rc = 0;
1367 RENAME_REQ *pSMB = NULL;
1368 RENAME_RSP *pSMBr = NULL;
1369 int bytes_returned;
1370 int name_len, name_len2;
1371 __u16 count;
1372
1373 cFYI(1, ("In CIFSSMBRename"));
1374renameRetry:
1375 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1376 (void **) &pSMBr);
1377 if (rc)
1378 return rc;
1379
1380 pSMB->BufferFormat = 0x04;
1381 pSMB->SearchAttributes =
1382 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1383 ATTR_DIRECTORY);
1384
1385 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1386 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001387 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001388 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 name_len++; /* trailing null */
1390 name_len *= 2;
1391 pSMB->OldFileName[name_len] = 0x04; /* pad */
1392 /* protocol requires ASCII signature byte on Unicode string */
1393 pSMB->OldFileName[name_len + 1] = 0x00;
1394 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001395 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001396 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1398 name_len2 *= 2; /* convert to bytes */
1399 } else { /* BB improve the check for buffer overruns BB */
1400 name_len = strnlen(fromName, PATH_MAX);
1401 name_len++; /* trailing null */
1402 strncpy(pSMB->OldFileName, fromName, name_len);
1403 name_len2 = strnlen(toName, PATH_MAX);
1404 name_len2++; /* trailing null */
1405 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1406 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1407 name_len2++; /* trailing null */
1408 name_len2++; /* signature byte */
1409 }
1410
1411 count = 1 /* 1st signature byte */ + name_len + name_len2;
1412 pSMB->hdr.smb_buf_length += count;
1413 pSMB->ByteCount = cpu_to_le16(count);
1414
1415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001417 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 if (rc) {
1419 cFYI(1, ("Send error in rename = %d", rc));
1420 }
1421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 cifs_buf_release(pSMB);
1423
1424 if (rc == -EAGAIN)
1425 goto renameRetry;
1426
1427 return rc;
1428}
1429
1430int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001431 int netfid, char * target_name,
1432 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433{
1434 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1435 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1436 struct set_file_rename * rename_info;
1437 char *data_offset;
1438 char dummy_string[30];
1439 int rc = 0;
1440 int bytes_returned = 0;
1441 int len_of_str;
1442 __u16 params, param_offset, offset, count, byte_count;
1443
1444 cFYI(1, ("Rename to File by handle"));
1445 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1446 (void **) &pSMBr);
1447 if (rc)
1448 return rc;
1449
1450 params = 6;
1451 pSMB->MaxSetupCount = 0;
1452 pSMB->Reserved = 0;
1453 pSMB->Flags = 0;
1454 pSMB->Timeout = 0;
1455 pSMB->Reserved2 = 0;
1456 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1457 offset = param_offset + params;
1458
1459 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1460 rename_info = (struct set_file_rename *) data_offset;
1461 pSMB->MaxParameterCount = cpu_to_le16(2);
1462 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1463 pSMB->SetupCount = 1;
1464 pSMB->Reserved3 = 0;
1465 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1466 byte_count = 3 /* pad */ + params;
1467 pSMB->ParameterCount = cpu_to_le16(params);
1468 pSMB->TotalParameterCount = pSMB->ParameterCount;
1469 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1470 pSMB->DataOffset = cpu_to_le16(offset);
1471 /* construct random name ".cifs_tmp<inodenum><mid>" */
1472 rename_info->overwrite = cpu_to_le32(1);
1473 rename_info->root_fid = 0;
1474 /* unicode only call */
1475 if(target_name == NULL) {
1476 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001477 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001478 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001480 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001481 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 }
1483 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1484 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1485 byte_count += count;
1486 pSMB->DataCount = cpu_to_le16(count);
1487 pSMB->TotalDataCount = pSMB->DataCount;
1488 pSMB->Fid = netfid;
1489 pSMB->InformationLevel =
1490 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1491 pSMB->Reserved4 = 0;
1492 pSMB->hdr.smb_buf_length += byte_count;
1493 pSMB->ByteCount = cpu_to_le16(byte_count);
1494 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1495 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001496 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 if (rc) {
1498 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1499 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 cifs_buf_release(pSMB);
1502
1503 /* Note: On -EAGAIN error only caller can retry on handle based calls
1504 since file handle passed in no longer valid */
1505
1506 return rc;
1507}
1508
1509int
1510CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1511 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001512 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513{
1514 int rc = 0;
1515 COPY_REQ *pSMB = NULL;
1516 COPY_RSP *pSMBr = NULL;
1517 int bytes_returned;
1518 int name_len, name_len2;
1519 __u16 count;
1520
1521 cFYI(1, ("In CIFSSMBCopy"));
1522copyRetry:
1523 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1524 (void **) &pSMBr);
1525 if (rc)
1526 return rc;
1527
1528 pSMB->BufferFormat = 0x04;
1529 pSMB->Tid2 = target_tid;
1530
1531 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1532
1533 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001534 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001535 fromName, PATH_MAX, nls_codepage,
1536 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 name_len++; /* trailing null */
1538 name_len *= 2;
1539 pSMB->OldFileName[name_len] = 0x04; /* pad */
1540 /* protocol requires ASCII signature byte on Unicode string */
1541 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001542 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001543 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1545 name_len2 *= 2; /* convert to bytes */
1546 } else { /* BB improve the check for buffer overruns BB */
1547 name_len = strnlen(fromName, PATH_MAX);
1548 name_len++; /* trailing null */
1549 strncpy(pSMB->OldFileName, fromName, name_len);
1550 name_len2 = strnlen(toName, PATH_MAX);
1551 name_len2++; /* trailing null */
1552 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1553 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1554 name_len2++; /* trailing null */
1555 name_len2++; /* signature byte */
1556 }
1557
1558 count = 1 /* 1st signature byte */ + name_len + name_len2;
1559 pSMB->hdr.smb_buf_length += count;
1560 pSMB->ByteCount = cpu_to_le16(count);
1561
1562 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1563 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1564 if (rc) {
1565 cFYI(1, ("Send error in copy = %d with %d files copied",
1566 rc, le16_to_cpu(pSMBr->CopyCount)));
1567 }
1568 if (pSMB)
1569 cifs_buf_release(pSMB);
1570
1571 if (rc == -EAGAIN)
1572 goto copyRetry;
1573
1574 return rc;
1575}
1576
1577int
1578CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1579 const char *fromName, const char *toName,
1580 const struct nls_table *nls_codepage)
1581{
1582 TRANSACTION2_SPI_REQ *pSMB = NULL;
1583 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1584 char *data_offset;
1585 int name_len;
1586 int name_len_target;
1587 int rc = 0;
1588 int bytes_returned = 0;
1589 __u16 params, param_offset, offset, byte_count;
1590
1591 cFYI(1, ("In Symlink Unix style"));
1592createSymLinkRetry:
1593 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1594 (void **) &pSMBr);
1595 if (rc)
1596 return rc;
1597
1598 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1599 name_len =
1600 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1601 /* find define for this maxpathcomponent */
1602 , nls_codepage);
1603 name_len++; /* trailing null */
1604 name_len *= 2;
1605
1606 } else { /* BB improve the check for buffer overruns BB */
1607 name_len = strnlen(fromName, PATH_MAX);
1608 name_len++; /* trailing null */
1609 strncpy(pSMB->FileName, fromName, name_len);
1610 }
1611 params = 6 + name_len;
1612 pSMB->MaxSetupCount = 0;
1613 pSMB->Reserved = 0;
1614 pSMB->Flags = 0;
1615 pSMB->Timeout = 0;
1616 pSMB->Reserved2 = 0;
1617 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1618 InformationLevel) - 4;
1619 offset = param_offset + params;
1620
1621 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1622 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1623 name_len_target =
1624 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1625 /* find define for this maxpathcomponent */
1626 , nls_codepage);
1627 name_len_target++; /* trailing null */
1628 name_len_target *= 2;
1629 } else { /* BB improve the check for buffer overruns BB */
1630 name_len_target = strnlen(toName, PATH_MAX);
1631 name_len_target++; /* trailing null */
1632 strncpy(data_offset, toName, name_len_target);
1633 }
1634
1635 pSMB->MaxParameterCount = cpu_to_le16(2);
1636 /* BB find exact max on data count below from sess */
1637 pSMB->MaxDataCount = cpu_to_le16(1000);
1638 pSMB->SetupCount = 1;
1639 pSMB->Reserved3 = 0;
1640 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1641 byte_count = 3 /* pad */ + params + name_len_target;
1642 pSMB->DataCount = cpu_to_le16(name_len_target);
1643 pSMB->ParameterCount = cpu_to_le16(params);
1644 pSMB->TotalDataCount = pSMB->DataCount;
1645 pSMB->TotalParameterCount = pSMB->ParameterCount;
1646 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1647 pSMB->DataOffset = cpu_to_le16(offset);
1648 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1649 pSMB->Reserved4 = 0;
1650 pSMB->hdr.smb_buf_length += byte_count;
1651 pSMB->ByteCount = cpu_to_le16(byte_count);
1652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001654 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 if (rc) {
1656 cFYI(1,
1657 ("Send error in SetPathInfo (create symlink) = %d",
1658 rc));
1659 }
1660
1661 if (pSMB)
1662 cifs_buf_release(pSMB);
1663
1664 if (rc == -EAGAIN)
1665 goto createSymLinkRetry;
1666
1667 return rc;
1668}
1669
1670int
1671CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1672 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001673 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674{
1675 TRANSACTION2_SPI_REQ *pSMB = NULL;
1676 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1677 char *data_offset;
1678 int name_len;
1679 int name_len_target;
1680 int rc = 0;
1681 int bytes_returned = 0;
1682 __u16 params, param_offset, offset, byte_count;
1683
1684 cFYI(1, ("In Create Hard link Unix style"));
1685createHardLinkRetry:
1686 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1687 (void **) &pSMBr);
1688 if (rc)
1689 return rc;
1690
1691 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001692 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001693 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 name_len++; /* trailing null */
1695 name_len *= 2;
1696
1697 } else { /* BB improve the check for buffer overruns BB */
1698 name_len = strnlen(toName, PATH_MAX);
1699 name_len++; /* trailing null */
1700 strncpy(pSMB->FileName, toName, name_len);
1701 }
1702 params = 6 + name_len;
1703 pSMB->MaxSetupCount = 0;
1704 pSMB->Reserved = 0;
1705 pSMB->Flags = 0;
1706 pSMB->Timeout = 0;
1707 pSMB->Reserved2 = 0;
1708 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1709 InformationLevel) - 4;
1710 offset = param_offset + params;
1711
1712 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1713 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1714 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001715 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001716 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 name_len_target++; /* trailing null */
1718 name_len_target *= 2;
1719 } else { /* BB improve the check for buffer overruns BB */
1720 name_len_target = strnlen(fromName, PATH_MAX);
1721 name_len_target++; /* trailing null */
1722 strncpy(data_offset, fromName, name_len_target);
1723 }
1724
1725 pSMB->MaxParameterCount = cpu_to_le16(2);
1726 /* BB find exact max on data count below from sess*/
1727 pSMB->MaxDataCount = cpu_to_le16(1000);
1728 pSMB->SetupCount = 1;
1729 pSMB->Reserved3 = 0;
1730 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1731 byte_count = 3 /* pad */ + params + name_len_target;
1732 pSMB->ParameterCount = cpu_to_le16(params);
1733 pSMB->TotalParameterCount = pSMB->ParameterCount;
1734 pSMB->DataCount = cpu_to_le16(name_len_target);
1735 pSMB->TotalDataCount = pSMB->DataCount;
1736 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1737 pSMB->DataOffset = cpu_to_le16(offset);
1738 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1739 pSMB->Reserved4 = 0;
1740 pSMB->hdr.smb_buf_length += byte_count;
1741 pSMB->ByteCount = cpu_to_le16(byte_count);
1742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001744 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 if (rc) {
1746 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1747 }
1748
1749 cifs_buf_release(pSMB);
1750 if (rc == -EAGAIN)
1751 goto createHardLinkRetry;
1752
1753 return rc;
1754}
1755
1756int
1757CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1758 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001759 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760{
1761 int rc = 0;
1762 NT_RENAME_REQ *pSMB = NULL;
1763 RENAME_RSP *pSMBr = NULL;
1764 int bytes_returned;
1765 int name_len, name_len2;
1766 __u16 count;
1767
1768 cFYI(1, ("In CIFSCreateHardLink"));
1769winCreateHardLinkRetry:
1770
1771 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1772 (void **) &pSMBr);
1773 if (rc)
1774 return rc;
1775
1776 pSMB->SearchAttributes =
1777 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1778 ATTR_DIRECTORY);
1779 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1780 pSMB->ClusterCount = 0;
1781
1782 pSMB->BufferFormat = 0x04;
1783
1784 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1785 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001786 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001787 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 name_len++; /* trailing null */
1789 name_len *= 2;
1790 pSMB->OldFileName[name_len] = 0; /* pad */
1791 pSMB->OldFileName[name_len + 1] = 0x04;
1792 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001793 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001794 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1796 name_len2 *= 2; /* convert to bytes */
1797 } else { /* BB improve the check for buffer overruns BB */
1798 name_len = strnlen(fromName, PATH_MAX);
1799 name_len++; /* trailing null */
1800 strncpy(pSMB->OldFileName, fromName, name_len);
1801 name_len2 = strnlen(toName, PATH_MAX);
1802 name_len2++; /* trailing null */
1803 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1804 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1805 name_len2++; /* trailing null */
1806 name_len2++; /* signature byte */
1807 }
1808
1809 count = 1 /* string type byte */ + name_len + name_len2;
1810 pSMB->hdr.smb_buf_length += count;
1811 pSMB->ByteCount = cpu_to_le16(count);
1812
1813 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1814 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001815 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 if (rc) {
1817 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1818 }
1819 cifs_buf_release(pSMB);
1820 if (rc == -EAGAIN)
1821 goto winCreateHardLinkRetry;
1822
1823 return rc;
1824}
1825
1826int
1827CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1828 const unsigned char *searchName,
1829 char *symlinkinfo, const int buflen,
1830 const struct nls_table *nls_codepage)
1831{
1832/* SMB_QUERY_FILE_UNIX_LINK */
1833 TRANSACTION2_QPI_REQ *pSMB = NULL;
1834 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1835 int rc = 0;
1836 int bytes_returned;
1837 int name_len;
1838 __u16 params, byte_count;
1839
1840 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1841
1842querySymLinkRetry:
1843 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1844 (void **) &pSMBr);
1845 if (rc)
1846 return rc;
1847
1848 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1849 name_len =
1850 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1851 /* find define for this maxpathcomponent */
1852 , nls_codepage);
1853 name_len++; /* trailing null */
1854 name_len *= 2;
1855 } else { /* BB improve the check for buffer overruns BB */
1856 name_len = strnlen(searchName, PATH_MAX);
1857 name_len++; /* trailing null */
1858 strncpy(pSMB->FileName, searchName, name_len);
1859 }
1860
1861 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1862 pSMB->TotalDataCount = 0;
1863 pSMB->MaxParameterCount = cpu_to_le16(2);
1864 /* BB find exact max data count below from sess structure BB */
1865 pSMB->MaxDataCount = cpu_to_le16(4000);
1866 pSMB->MaxSetupCount = 0;
1867 pSMB->Reserved = 0;
1868 pSMB->Flags = 0;
1869 pSMB->Timeout = 0;
1870 pSMB->Reserved2 = 0;
1871 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1872 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1873 pSMB->DataCount = 0;
1874 pSMB->DataOffset = 0;
1875 pSMB->SetupCount = 1;
1876 pSMB->Reserved3 = 0;
1877 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1878 byte_count = params + 1 /* pad */ ;
1879 pSMB->TotalParameterCount = cpu_to_le16(params);
1880 pSMB->ParameterCount = pSMB->TotalParameterCount;
1881 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1882 pSMB->Reserved4 = 0;
1883 pSMB->hdr.smb_buf_length += byte_count;
1884 pSMB->ByteCount = cpu_to_le16(byte_count);
1885
1886 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1887 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1888 if (rc) {
1889 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1890 } else {
1891 /* decode response */
1892
1893 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1894 if (rc || (pSMBr->ByteCount < 2))
1895 /* BB also check enough total bytes returned */
1896 rc = -EIO; /* bad smb */
1897 else {
1898 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1899 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1900
1901 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1902 name_len = UniStrnlen((wchar_t *) ((char *)
1903 &pSMBr->hdr.Protocol +data_offset),
1904 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001905 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 cifs_strfromUCS_le(symlinkinfo,
1907 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1908 data_offset),
1909 name_len, nls_codepage);
1910 } else {
1911 strncpy(symlinkinfo,
1912 (char *) &pSMBr->hdr.Protocol +
1913 data_offset,
1914 min_t(const int, buflen, count));
1915 }
1916 symlinkinfo[buflen] = 0;
1917 /* just in case so calling code does not go off the end of buffer */
1918 }
1919 }
1920 cifs_buf_release(pSMB);
1921 if (rc == -EAGAIN)
1922 goto querySymLinkRetry;
1923 return rc;
1924}
1925
1926int
1927CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1928 const unsigned char *searchName,
1929 char *symlinkinfo, const int buflen,__u16 fid,
1930 const struct nls_table *nls_codepage)
1931{
1932 int rc = 0;
1933 int bytes_returned;
1934 int name_len;
1935 struct smb_com_transaction_ioctl_req * pSMB;
1936 struct smb_com_transaction_ioctl_rsp * pSMBr;
1937
1938 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1939 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1940 (void **) &pSMBr);
1941 if (rc)
1942 return rc;
1943
1944 pSMB->TotalParameterCount = 0 ;
1945 pSMB->TotalDataCount = 0;
1946 pSMB->MaxParameterCount = cpu_to_le32(2);
1947 /* BB find exact data count max from sess structure BB */
1948 pSMB->MaxDataCount = cpu_to_le32(4000);
1949 pSMB->MaxSetupCount = 4;
1950 pSMB->Reserved = 0;
1951 pSMB->ParameterOffset = 0;
1952 pSMB->DataCount = 0;
1953 pSMB->DataOffset = 0;
1954 pSMB->SetupCount = 4;
1955 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1956 pSMB->ParameterCount = pSMB->TotalParameterCount;
1957 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1958 pSMB->IsFsctl = 1; /* FSCTL */
1959 pSMB->IsRootFlag = 0;
1960 pSMB->Fid = fid; /* file handle always le */
1961 pSMB->ByteCount = 0;
1962
1963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1964 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1965 if (rc) {
1966 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1967 } else { /* decode response */
1968 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1969 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1970 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1971 /* BB also check enough total bytes returned */
1972 rc = -EIO; /* bad smb */
1973 else {
1974 if(data_count && (data_count < 2048)) {
1975 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1976
1977 struct reparse_data * reparse_buf = (struct reparse_data *)
1978 ((char *)&pSMBr->hdr.Protocol + data_offset);
1979 if((char*)reparse_buf >= end_of_smb) {
1980 rc = -EIO;
1981 goto qreparse_out;
1982 }
1983 if((reparse_buf->LinkNamesBuf +
1984 reparse_buf->TargetNameOffset +
1985 reparse_buf->TargetNameLen) >
1986 end_of_smb) {
1987 cFYI(1,("reparse buf extended beyond SMB"));
1988 rc = -EIO;
1989 goto qreparse_out;
1990 }
1991
1992 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1993 name_len = UniStrnlen((wchar_t *)
1994 (reparse_buf->LinkNamesBuf +
1995 reparse_buf->TargetNameOffset),
1996 min(buflen/2, reparse_buf->TargetNameLen / 2));
1997 cifs_strfromUCS_le(symlinkinfo,
1998 (wchar_t *) (reparse_buf->LinkNamesBuf +
1999 reparse_buf->TargetNameOffset),
2000 name_len, nls_codepage);
2001 } else { /* ASCII names */
2002 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2003 reparse_buf->TargetNameOffset,
2004 min_t(const int, buflen, reparse_buf->TargetNameLen));
2005 }
2006 } else {
2007 rc = -EIO;
2008 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2009 }
2010 symlinkinfo[buflen] = 0; /* just in case so the caller
2011 does not go off the end of the buffer */
2012 cFYI(1,("readlink result - %s ",symlinkinfo));
2013 }
2014 }
2015qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002016 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
2018 /* Note: On -EAGAIN error only caller can retry on handle based calls
2019 since file handle passed in no longer valid */
2020
2021 return rc;
2022}
2023
2024#ifdef CONFIG_CIFS_POSIX
2025
2026/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2027static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2028{
2029 /* u8 cifs fields do not need le conversion */
2030 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
2031 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
2032 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
2033 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2034
2035 return;
2036}
2037
2038/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002039static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2040 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041{
2042 int size = 0;
2043 int i;
2044 __u16 count;
2045 struct cifs_posix_ace * pACE;
2046 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2047 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2048
2049 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2050 return -EOPNOTSUPP;
2051
2052 if(acl_type & ACL_TYPE_ACCESS) {
2053 count = le16_to_cpu(cifs_acl->access_entry_count);
2054 pACE = &cifs_acl->ace_array[0];
2055 size = sizeof(struct cifs_posix_acl);
2056 size += sizeof(struct cifs_posix_ace) * count;
2057 /* check if we would go beyond end of SMB */
2058 if(size_of_data_area < size) {
2059 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2060 return -EINVAL;
2061 }
2062 } else if(acl_type & ACL_TYPE_DEFAULT) {
2063 count = le16_to_cpu(cifs_acl->access_entry_count);
2064 size = sizeof(struct cifs_posix_acl);
2065 size += sizeof(struct cifs_posix_ace) * count;
2066/* skip past access ACEs to get to default ACEs */
2067 pACE = &cifs_acl->ace_array[count];
2068 count = le16_to_cpu(cifs_acl->default_entry_count);
2069 size += sizeof(struct cifs_posix_ace) * count;
2070 /* check if we would go beyond end of SMB */
2071 if(size_of_data_area < size)
2072 return -EINVAL;
2073 } else {
2074 /* illegal type */
2075 return -EINVAL;
2076 }
2077
2078 size = posix_acl_xattr_size(count);
2079 if((buflen == 0) || (local_acl == NULL)) {
2080 /* used to query ACL EA size */
2081 } else if(size > buflen) {
2082 return -ERANGE;
2083 } else /* buffer big enough */ {
2084 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
2085 for(i = 0;i < count ;i++) {
2086 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2087 pACE ++;
2088 }
2089 }
2090 return size;
2091}
2092
2093static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2094 const posix_acl_xattr_entry * local_ace)
2095{
2096 __u16 rc = 0; /* 0 = ACL converted ok */
2097
2098 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
2099 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
2100 /* BB is there a better way to handle the large uid? */
2101 if(local_ace->e_id == -1) {
2102 /* Probably no need to le convert -1 on any arch but can not hurt */
2103 cifs_ace->cifs_uid = cpu_to_le64(-1);
2104 } else
2105 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
2106 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2107 return rc;
2108}
2109
2110/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2111static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2112 const int acl_type)
2113{
2114 __u16 rc = 0;
2115 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2116 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2117 int count;
2118 int i;
2119
2120 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2121 return 0;
2122
2123 count = posix_acl_xattr_count((size_t)buflen);
2124 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2125 count,buflen,local_acl->a_version));
2126 if(local_acl->a_version != 2) {
2127 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
2128 return 0;
2129 }
2130 cifs_acl->version = cpu_to_le16(1);
2131 if(acl_type == ACL_TYPE_ACCESS)
2132 cifs_acl->access_entry_count = count;
2133 else if(acl_type == ACL_TYPE_DEFAULT)
2134 cifs_acl->default_entry_count = count;
2135 else {
2136 cFYI(1,("unknown ACL type %d",acl_type));
2137 return 0;
2138 }
2139 for(i=0;i<count;i++) {
2140 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2141 &local_acl->a_entries[i]);
2142 if(rc != 0) {
2143 /* ACE not converted */
2144 break;
2145 }
2146 }
2147 if(rc == 0) {
2148 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2149 rc += sizeof(struct cifs_posix_acl);
2150 /* BB add check to make sure ACL does not overflow SMB */
2151 }
2152 return rc;
2153}
2154
2155int
2156CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2157 const unsigned char *searchName,
2158 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002159 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160{
2161/* SMB_QUERY_POSIX_ACL */
2162 TRANSACTION2_QPI_REQ *pSMB = NULL;
2163 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2164 int rc = 0;
2165 int bytes_returned;
2166 int name_len;
2167 __u16 params, byte_count;
2168
2169 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2170
2171queryAclRetry:
2172 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2173 (void **) &pSMBr);
2174 if (rc)
2175 return rc;
2176
2177 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2178 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002179 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002180 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 name_len++; /* trailing null */
2182 name_len *= 2;
2183 pSMB->FileName[name_len] = 0;
2184 pSMB->FileName[name_len+1] = 0;
2185 } else { /* BB improve the check for buffer overruns BB */
2186 name_len = strnlen(searchName, PATH_MAX);
2187 name_len++; /* trailing null */
2188 strncpy(pSMB->FileName, searchName, name_len);
2189 }
2190
2191 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2192 pSMB->TotalDataCount = 0;
2193 pSMB->MaxParameterCount = cpu_to_le16(2);
2194 /* BB find exact max data count below from sess structure BB */
2195 pSMB->MaxDataCount = cpu_to_le16(4000);
2196 pSMB->MaxSetupCount = 0;
2197 pSMB->Reserved = 0;
2198 pSMB->Flags = 0;
2199 pSMB->Timeout = 0;
2200 pSMB->Reserved2 = 0;
2201 pSMB->ParameterOffset = cpu_to_le16(
2202 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2203 pSMB->DataCount = 0;
2204 pSMB->DataOffset = 0;
2205 pSMB->SetupCount = 1;
2206 pSMB->Reserved3 = 0;
2207 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2208 byte_count = params + 1 /* pad */ ;
2209 pSMB->TotalParameterCount = cpu_to_le16(params);
2210 pSMB->ParameterCount = pSMB->TotalParameterCount;
2211 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2212 pSMB->Reserved4 = 0;
2213 pSMB->hdr.smb_buf_length += byte_count;
2214 pSMB->ByteCount = cpu_to_le16(byte_count);
2215
2216 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2217 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2218 if (rc) {
2219 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2220 } else {
2221 /* decode response */
2222
2223 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2224 if (rc || (pSMBr->ByteCount < 2))
2225 /* BB also check enough total bytes returned */
2226 rc = -EIO; /* bad smb */
2227 else {
2228 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2229 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2230 rc = cifs_copy_posix_acl(acl_inf,
2231 (char *)&pSMBr->hdr.Protocol+data_offset,
2232 buflen,acl_type,count);
2233 }
2234 }
2235 cifs_buf_release(pSMB);
2236 if (rc == -EAGAIN)
2237 goto queryAclRetry;
2238 return rc;
2239}
2240
2241int
2242CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2243 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002244 const char *local_acl, const int buflen,
2245 const int acl_type,
2246 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247{
2248 struct smb_com_transaction2_spi_req *pSMB = NULL;
2249 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2250 char *parm_data;
2251 int name_len;
2252 int rc = 0;
2253 int bytes_returned = 0;
2254 __u16 params, byte_count, data_count, param_offset, offset;
2255
2256 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2257setAclRetry:
2258 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2259 (void **) &pSMBr);
2260 if (rc)
2261 return rc;
2262 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2263 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002264 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002265 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 name_len++; /* trailing null */
2267 name_len *= 2;
2268 } else { /* BB improve the check for buffer overruns BB */
2269 name_len = strnlen(fileName, PATH_MAX);
2270 name_len++; /* trailing null */
2271 strncpy(pSMB->FileName, fileName, name_len);
2272 }
2273 params = 6 + name_len;
2274 pSMB->MaxParameterCount = cpu_to_le16(2);
2275 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2276 pSMB->MaxSetupCount = 0;
2277 pSMB->Reserved = 0;
2278 pSMB->Flags = 0;
2279 pSMB->Timeout = 0;
2280 pSMB->Reserved2 = 0;
2281 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2282 InformationLevel) - 4;
2283 offset = param_offset + params;
2284 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2285 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2286
2287 /* convert to on the wire format for POSIX ACL */
2288 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2289
2290 if(data_count == 0) {
2291 rc = -EOPNOTSUPP;
2292 goto setACLerrorExit;
2293 }
2294 pSMB->DataOffset = cpu_to_le16(offset);
2295 pSMB->SetupCount = 1;
2296 pSMB->Reserved3 = 0;
2297 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2298 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2299 byte_count = 3 /* pad */ + params + data_count;
2300 pSMB->DataCount = cpu_to_le16(data_count);
2301 pSMB->TotalDataCount = pSMB->DataCount;
2302 pSMB->ParameterCount = cpu_to_le16(params);
2303 pSMB->TotalParameterCount = pSMB->ParameterCount;
2304 pSMB->Reserved4 = 0;
2305 pSMB->hdr.smb_buf_length += byte_count;
2306 pSMB->ByteCount = cpu_to_le16(byte_count);
2307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2309 if (rc) {
2310 cFYI(1, ("Set POSIX ACL returned %d", rc));
2311 }
2312
2313setACLerrorExit:
2314 cifs_buf_release(pSMB);
2315 if (rc == -EAGAIN)
2316 goto setAclRetry;
2317 return rc;
2318}
2319
Steve Frenchf654bac2005-04-28 22:41:04 -07002320/* BB fix tabs in this function FIXME BB */
2321int
2322CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2323 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2324{
2325 int rc = 0;
2326 struct smb_t2_qfi_req *pSMB = NULL;
2327 struct smb_t2_qfi_rsp *pSMBr = NULL;
2328 int bytes_returned;
2329 __u16 params, byte_count;
2330
2331 cFYI(1,("In GetExtAttr"));
2332 if(tcon == NULL)
2333 return -ENODEV;
2334
2335GetExtAttrRetry:
2336 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2337 (void **) &pSMBr);
2338 if (rc)
2339 return rc;
2340
Steve Frenchc67593a2005-04-28 22:41:04 -07002341 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002342 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002343 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002344 /* BB find exact max data count below from sess structure BB */
2345 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2346 pSMB->t2.MaxSetupCount = 0;
2347 pSMB->t2.Reserved = 0;
2348 pSMB->t2.Flags = 0;
2349 pSMB->t2.Timeout = 0;
2350 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002351 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2352 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002353 pSMB->t2.DataCount = 0;
2354 pSMB->t2.DataOffset = 0;
2355 pSMB->t2.SetupCount = 1;
2356 pSMB->t2.Reserved3 = 0;
2357 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002358 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002359 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2360 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2361 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002362 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002363 pSMB->Fid = netfid;
2364 pSMB->hdr.smb_buf_length += byte_count;
2365 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2366
2367 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2368 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2369 if (rc) {
2370 cFYI(1, ("error %d in GetExtAttr", rc));
2371 } else {
2372 /* decode response */
2373 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2374 if (rc || (pSMBr->ByteCount < 2))
2375 /* BB also check enough total bytes returned */
2376 /* If rc should we check for EOPNOSUPP and
2377 disable the srvino flag? or in caller? */
2378 rc = -EIO; /* bad smb */
2379 else {
2380 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2381 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2382 struct file_chattr_info * pfinfo;
2383 /* BB Do we need a cast or hash here ? */
2384 if(count != 16) {
2385 cFYI(1, ("Illegal size ret in GetExtAttr"));
2386 rc = -EIO;
2387 goto GetExtAttrOut;
2388 }
2389 pfinfo = (struct file_chattr_info *)
2390 (data_offset + (char *) &pSMBr->hdr.Protocol);
2391 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2392 *pMask = le64_to_cpu(pfinfo->mask);
2393 }
2394 }
2395GetExtAttrOut:
2396 cifs_buf_release(pSMB);
2397 if (rc == -EAGAIN)
2398 goto GetExtAttrRetry;
2399 return rc;
2400}
2401
2402
2403#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Steve French6b8edfe2005-08-23 20:26:03 -07002405/* Legacy Query Path Information call for lookup to old servers such
2406 as Win9x/WinME */
2407int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2408 const unsigned char *searchName,
2409 FILE_ALL_INFO * pFinfo,
2410 const struct nls_table *nls_codepage, int remap)
2411{
2412 QUERY_INFORMATION_REQ * pSMB;
2413 QUERY_INFORMATION_RSP * pSMBr;
2414 int rc = 0;
2415 int bytes_returned;
2416 int name_len;
2417
2418 cFYI(1, ("In SMBQPath path %s", searchName));
2419QInfRetry:
2420 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2421 (void **) &pSMBr);
2422 if (rc)
2423 return rc;
2424
2425 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2426 name_len =
2427 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2428 PATH_MAX, nls_codepage, remap);
2429 name_len++; /* trailing null */
2430 name_len *= 2;
2431 } else {
2432 name_len = strnlen(searchName, PATH_MAX);
2433 name_len++; /* trailing null */
2434 strncpy(pSMB->FileName, searchName, name_len);
2435 }
2436 pSMB->BufferFormat = 0x04;
2437 name_len++; /* account for buffer type byte */
2438 pSMB->hdr.smb_buf_length += (__u16) name_len;
2439 pSMB->ByteCount = cpu_to_le16(name_len);
2440
2441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2443 if (rc) {
2444 cFYI(1, ("Send error in QueryInfo = %d", rc));
2445 } else if (pFinfo) { /* decode response */
2446 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2447 pFinfo->AllocationSize = (__le64) pSMBr->size;
2448 pFinfo->EndOfFile = (__le64) pSMBr->size;
2449 pFinfo->Attributes = (__le32) pSMBr->attr;
2450 } else
2451 rc = -EIO; /* bad buffer passed in */
2452
2453 cifs_buf_release(pSMB);
2454
2455 if (rc == -EAGAIN)
2456 goto QInfRetry;
2457
2458 return rc;
2459}
2460
2461
2462
2463
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464int
2465CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2466 const unsigned char *searchName,
2467 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002468 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469{
2470/* level 263 SMB_QUERY_FILE_ALL_INFO */
2471 TRANSACTION2_QPI_REQ *pSMB = NULL;
2472 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2473 int rc = 0;
2474 int bytes_returned;
2475 int name_len;
2476 __u16 params, byte_count;
2477
2478/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2479QPathInfoRetry:
2480 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2481 (void **) &pSMBr);
2482 if (rc)
2483 return rc;
2484
2485 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2486 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002487 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002488 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 name_len++; /* trailing null */
2490 name_len *= 2;
2491 } else { /* BB improve the check for buffer overruns BB */
2492 name_len = strnlen(searchName, PATH_MAX);
2493 name_len++; /* trailing null */
2494 strncpy(pSMB->FileName, searchName, name_len);
2495 }
2496
2497 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2498 pSMB->TotalDataCount = 0;
2499 pSMB->MaxParameterCount = cpu_to_le16(2);
2500 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2501 pSMB->MaxSetupCount = 0;
2502 pSMB->Reserved = 0;
2503 pSMB->Flags = 0;
2504 pSMB->Timeout = 0;
2505 pSMB->Reserved2 = 0;
2506 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2507 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2508 pSMB->DataCount = 0;
2509 pSMB->DataOffset = 0;
2510 pSMB->SetupCount = 1;
2511 pSMB->Reserved3 = 0;
2512 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2513 byte_count = params + 1 /* pad */ ;
2514 pSMB->TotalParameterCount = cpu_to_le16(params);
2515 pSMB->ParameterCount = pSMB->TotalParameterCount;
2516 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2517 pSMB->Reserved4 = 0;
2518 pSMB->hdr.smb_buf_length += byte_count;
2519 pSMB->ByteCount = cpu_to_le16(byte_count);
2520
2521 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2522 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2523 if (rc) {
2524 cFYI(1, ("Send error in QPathInfo = %d", rc));
2525 } else { /* decode response */
2526 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2527
2528 if (rc || (pSMBr->ByteCount < 40))
2529 rc = -EIO; /* bad smb */
2530 else if (pFindData){
2531 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2532 memcpy((char *) pFindData,
2533 (char *) &pSMBr->hdr.Protocol +
2534 data_offset, sizeof (FILE_ALL_INFO));
2535 } else
2536 rc = -ENOMEM;
2537 }
2538 cifs_buf_release(pSMB);
2539 if (rc == -EAGAIN)
2540 goto QPathInfoRetry;
2541
2542 return rc;
2543}
2544
2545int
2546CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2547 const unsigned char *searchName,
2548 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002549 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550{
2551/* SMB_QUERY_FILE_UNIX_BASIC */
2552 TRANSACTION2_QPI_REQ *pSMB = NULL;
2553 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2554 int rc = 0;
2555 int bytes_returned = 0;
2556 int name_len;
2557 __u16 params, byte_count;
2558
2559 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2560UnixQPathInfoRetry:
2561 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2562 (void **) &pSMBr);
2563 if (rc)
2564 return rc;
2565
2566 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2567 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002568 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002569 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 name_len++; /* trailing null */
2571 name_len *= 2;
2572 } else { /* BB improve the check for buffer overruns BB */
2573 name_len = strnlen(searchName, PATH_MAX);
2574 name_len++; /* trailing null */
2575 strncpy(pSMB->FileName, searchName, name_len);
2576 }
2577
2578 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2579 pSMB->TotalDataCount = 0;
2580 pSMB->MaxParameterCount = cpu_to_le16(2);
2581 /* BB find exact max SMB PDU from sess structure BB */
2582 pSMB->MaxDataCount = cpu_to_le16(4000);
2583 pSMB->MaxSetupCount = 0;
2584 pSMB->Reserved = 0;
2585 pSMB->Flags = 0;
2586 pSMB->Timeout = 0;
2587 pSMB->Reserved2 = 0;
2588 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2589 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2590 pSMB->DataCount = 0;
2591 pSMB->DataOffset = 0;
2592 pSMB->SetupCount = 1;
2593 pSMB->Reserved3 = 0;
2594 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2595 byte_count = params + 1 /* pad */ ;
2596 pSMB->TotalParameterCount = cpu_to_le16(params);
2597 pSMB->ParameterCount = pSMB->TotalParameterCount;
2598 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2599 pSMB->Reserved4 = 0;
2600 pSMB->hdr.smb_buf_length += byte_count;
2601 pSMB->ByteCount = cpu_to_le16(byte_count);
2602
2603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2605 if (rc) {
2606 cFYI(1, ("Send error in QPathInfo = %d", rc));
2607 } else { /* decode response */
2608 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2609
2610 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2611 rc = -EIO; /* bad smb */
2612 } else {
2613 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2614 memcpy((char *) pFindData,
2615 (char *) &pSMBr->hdr.Protocol +
2616 data_offset,
2617 sizeof (FILE_UNIX_BASIC_INFO));
2618 }
2619 }
2620 cifs_buf_release(pSMB);
2621 if (rc == -EAGAIN)
2622 goto UnixQPathInfoRetry;
2623
2624 return rc;
2625}
2626
2627#if 0 /* function unused at present */
2628int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2629 const char *searchName, FILE_ALL_INFO * findData,
2630 const struct nls_table *nls_codepage)
2631{
2632/* level 257 SMB_ */
2633 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2634 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2635 int rc = 0;
2636 int bytes_returned;
2637 int name_len;
2638 __u16 params, byte_count;
2639
2640 cFYI(1, ("In FindUnique"));
2641findUniqueRetry:
2642 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2643 (void **) &pSMBr);
2644 if (rc)
2645 return rc;
2646
2647 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2648 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002649 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 /* find define for this maxpathcomponent */
2651 , nls_codepage);
2652 name_len++; /* trailing null */
2653 name_len *= 2;
2654 } else { /* BB improve the check for buffer overruns BB */
2655 name_len = strnlen(searchName, PATH_MAX);
2656 name_len++; /* trailing null */
2657 strncpy(pSMB->FileName, searchName, name_len);
2658 }
2659
2660 params = 12 + name_len /* includes null */ ;
2661 pSMB->TotalDataCount = 0; /* no EAs */
2662 pSMB->MaxParameterCount = cpu_to_le16(2);
2663 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2664 pSMB->MaxSetupCount = 0;
2665 pSMB->Reserved = 0;
2666 pSMB->Flags = 0;
2667 pSMB->Timeout = 0;
2668 pSMB->Reserved2 = 0;
2669 pSMB->ParameterOffset = cpu_to_le16(
2670 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2671 pSMB->DataCount = 0;
2672 pSMB->DataOffset = 0;
2673 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2674 pSMB->Reserved3 = 0;
2675 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2676 byte_count = params + 1 /* pad */ ;
2677 pSMB->TotalParameterCount = cpu_to_le16(params);
2678 pSMB->ParameterCount = pSMB->TotalParameterCount;
2679 pSMB->SearchAttributes =
2680 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2681 ATTR_DIRECTORY);
2682 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2683 pSMB->SearchFlags = cpu_to_le16(1);
2684 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2685 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2686 pSMB->hdr.smb_buf_length += byte_count;
2687 pSMB->ByteCount = cpu_to_le16(byte_count);
2688
2689 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2690 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2691
2692 if (rc) {
2693 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2694 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07002695 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 /* BB fill in */
2697 }
2698
2699 cifs_buf_release(pSMB);
2700 if (rc == -EAGAIN)
2701 goto findUniqueRetry;
2702
2703 return rc;
2704}
2705#endif /* end unused (temporarily) function */
2706
2707/* xid, tcon, searchName and codepage are input parms, rest are returned */
2708int
2709CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2710 const char *searchName,
2711 const struct nls_table *nls_codepage,
2712 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002713 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714{
2715/* level 257 SMB_ */
2716 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2717 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2718 T2_FFIRST_RSP_PARMS * parms;
2719 int rc = 0;
2720 int bytes_returned = 0;
2721 int name_len;
2722 __u16 params, byte_count;
2723
Steve French737b7582005-04-28 22:41:06 -07002724 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725
2726findFirstRetry:
2727 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2728 (void **) &pSMBr);
2729 if (rc)
2730 return rc;
2731
2732 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2733 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002734 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002735 PATH_MAX, nls_codepage, remap);
2736 /* We can not add the asterik earlier in case
2737 it got remapped to 0xF03A as if it were part of the
2738 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002740 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002741 pSMB->FileName[name_len+1] = 0;
2742 pSMB->FileName[name_len+2] = '*';
2743 pSMB->FileName[name_len+3] = 0;
2744 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2746 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002747 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 } else { /* BB add check for overrun of SMB buf BB */
2749 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750/* BB fix here and in unicode clause above ie
2751 if(name_len > buffersize-header)
2752 free buffer exit; BB */
2753 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002754 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002755 pSMB->FileName[name_len+1] = '*';
2756 pSMB->FileName[name_len+2] = 0;
2757 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 }
2759
2760 params = 12 + name_len /* includes null */ ;
2761 pSMB->TotalDataCount = 0; /* no EAs */
2762 pSMB->MaxParameterCount = cpu_to_le16(10);
2763 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2764 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2765 pSMB->MaxSetupCount = 0;
2766 pSMB->Reserved = 0;
2767 pSMB->Flags = 0;
2768 pSMB->Timeout = 0;
2769 pSMB->Reserved2 = 0;
2770 byte_count = params + 1 /* pad */ ;
2771 pSMB->TotalParameterCount = cpu_to_le16(params);
2772 pSMB->ParameterCount = pSMB->TotalParameterCount;
2773 pSMB->ParameterOffset = cpu_to_le16(
2774 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2775 pSMB->DataCount = 0;
2776 pSMB->DataOffset = 0;
2777 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2778 pSMB->Reserved3 = 0;
2779 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2780 pSMB->SearchAttributes =
2781 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2782 ATTR_DIRECTORY);
2783 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2784 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2785 CIFS_SEARCH_RETURN_RESUME);
2786 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2787
2788 /* BB what should we set StorageType to? Does it matter? BB */
2789 pSMB->SearchStorageType = 0;
2790 pSMB->hdr.smb_buf_length += byte_count;
2791 pSMB->ByteCount = cpu_to_le16(byte_count);
2792
2793 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2794 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002795 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
Steve French1982c342005-08-17 12:38:22 -07002797 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 /* BB Add code to handle unsupported level rc */
2799 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002800
2801 if (pSMB)
2802 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803
2804 /* BB eventually could optimize out free and realloc of buf */
2805 /* for this case */
2806 if (rc == -EAGAIN)
2807 goto findFirstRetry;
2808 } else { /* decode response */
2809 /* BB remember to free buffer if error BB */
2810 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2811 if(rc == 0) {
2812 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2813 psrch_inf->unicode = TRUE;
2814 else
2815 psrch_inf->unicode = FALSE;
2816
2817 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2818 psrch_inf->srch_entries_start =
2819 (char *) &pSMBr->hdr.Protocol +
2820 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2822 le16_to_cpu(pSMBr->t2.ParameterOffset));
2823
2824 if(parms->EndofSearch)
2825 psrch_inf->endOfSearch = TRUE;
2826 else
2827 psrch_inf->endOfSearch = FALSE;
2828
2829 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2830 psrch_inf->index_of_last_entry =
2831 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 *pnetfid = parms->SearchHandle;
2833 } else {
2834 cifs_buf_release(pSMB);
2835 }
2836 }
2837
2838 return rc;
2839}
2840
2841int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2842 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2843{
2844 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2845 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2846 T2_FNEXT_RSP_PARMS * parms;
2847 char *response_data;
2848 int rc = 0;
2849 int bytes_returned, name_len;
2850 __u16 params, byte_count;
2851
2852 cFYI(1, ("In FindNext"));
2853
2854 if(psrch_inf->endOfSearch == TRUE)
2855 return -ENOENT;
2856
2857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2858 (void **) &pSMBr);
2859 if (rc)
2860 return rc;
2861
2862 params = 14; /* includes 2 bytes of null string, converted to LE below */
2863 byte_count = 0;
2864 pSMB->TotalDataCount = 0; /* no EAs */
2865 pSMB->MaxParameterCount = cpu_to_le16(8);
2866 pSMB->MaxDataCount =
2867 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2868 pSMB->MaxSetupCount = 0;
2869 pSMB->Reserved = 0;
2870 pSMB->Flags = 0;
2871 pSMB->Timeout = 0;
2872 pSMB->Reserved2 = 0;
2873 pSMB->ParameterOffset = cpu_to_le16(
2874 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2875 pSMB->DataCount = 0;
2876 pSMB->DataOffset = 0;
2877 pSMB->SetupCount = 1;
2878 pSMB->Reserved3 = 0;
2879 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2880 pSMB->SearchHandle = searchHandle; /* always kept as le */
2881 pSMB->SearchCount =
2882 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2883 /* test for Unix extensions */
2884/* if (tcon->ses->capabilities & CAP_UNIX) {
2885 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2886 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2887 } else {
2888 pSMB->InformationLevel =
2889 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2890 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2891 } */
2892 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2893 pSMB->ResumeKey = psrch_inf->resume_key;
2894 pSMB->SearchFlags =
2895 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2896
2897 name_len = psrch_inf->resume_name_len;
2898 params += name_len;
2899 if(name_len < PATH_MAX) {
2900 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2901 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002902 /* 14 byte parm len above enough for 2 byte null terminator */
2903 pSMB->ResumeFileName[name_len] = 0;
2904 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 } else {
2906 rc = -EINVAL;
2907 goto FNext2_err_exit;
2908 }
2909 byte_count = params + 1 /* pad */ ;
2910 pSMB->TotalParameterCount = cpu_to_le16(params);
2911 pSMB->ParameterCount = pSMB->TotalParameterCount;
2912 pSMB->hdr.smb_buf_length += byte_count;
2913 pSMB->ByteCount = cpu_to_le16(byte_count);
2914
2915 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2916 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002917 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 if (rc) {
2919 if (rc == -EBADF) {
2920 psrch_inf->endOfSearch = TRUE;
2921 rc = 0; /* search probably was closed at end of search above */
2922 } else
2923 cFYI(1, ("FindNext returned = %d", rc));
2924 } else { /* decode response */
2925 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2926
2927 if(rc == 0) {
2928 /* BB fixme add lock for file (srch_info) struct here */
2929 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2930 psrch_inf->unicode = TRUE;
2931 else
2932 psrch_inf->unicode = FALSE;
2933 response_data = (char *) &pSMBr->hdr.Protocol +
2934 le16_to_cpu(pSMBr->t2.ParameterOffset);
2935 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2936 response_data = (char *)&pSMBr->hdr.Protocol +
2937 le16_to_cpu(pSMBr->t2.DataOffset);
2938 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2939 psrch_inf->srch_entries_start = response_data;
2940 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2941 if(parms->EndofSearch)
2942 psrch_inf->endOfSearch = TRUE;
2943 else
2944 psrch_inf->endOfSearch = FALSE;
2945
2946 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2947 psrch_inf->index_of_last_entry +=
2948 psrch_inf->entries_in_buffer;
2949/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2950
2951 /* BB fixme add unlock here */
2952 }
2953
2954 }
2955
2956 /* BB On error, should we leave previous search buf (and count and
2957 last entry fields) intact or free the previous one? */
2958
2959 /* Note: On -EAGAIN error only caller can retry on handle based calls
2960 since file handle passed in no longer valid */
2961FNext2_err_exit:
2962 if (rc != 0)
2963 cifs_buf_release(pSMB);
2964
2965 return rc;
2966}
2967
2968int
2969CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2970{
2971 int rc = 0;
2972 FINDCLOSE_REQ *pSMB = NULL;
2973 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2974 int bytes_returned;
2975
2976 cFYI(1, ("In CIFSSMBFindClose"));
2977 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2978
2979 /* no sense returning error if session restarted
2980 as file handle has been closed */
2981 if(rc == -EAGAIN)
2982 return 0;
2983 if (rc)
2984 return rc;
2985
2986 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2987 pSMB->FileID = searchHandle;
2988 pSMB->ByteCount = 0;
2989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2991 if (rc) {
2992 cERROR(1, ("Send error in FindClose = %d", rc));
2993 }
Steve Frencha4544342005-08-24 13:59:35 -07002994 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 cifs_small_buf_release(pSMB);
2996
2997 /* Since session is dead, search handle closed on server already */
2998 if (rc == -EAGAIN)
2999 rc = 0;
3000
3001 return rc;
3002}
3003
3004#ifdef CONFIG_CIFS_EXPERIMENTAL
3005int
3006CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3007 const unsigned char *searchName,
3008 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003009 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010{
3011 int rc = 0;
3012 TRANSACTION2_QPI_REQ *pSMB = NULL;
3013 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3014 int name_len, bytes_returned;
3015 __u16 params, byte_count;
3016
3017 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3018 if(tcon == NULL)
3019 return -ENODEV;
3020
3021GetInodeNumberRetry:
3022 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3023 (void **) &pSMBr);
3024 if (rc)
3025 return rc;
3026
3027
3028 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3029 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003030 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003031 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 name_len++; /* trailing null */
3033 name_len *= 2;
3034 } else { /* BB improve the check for buffer overruns BB */
3035 name_len = strnlen(searchName, PATH_MAX);
3036 name_len++; /* trailing null */
3037 strncpy(pSMB->FileName, searchName, name_len);
3038 }
3039
3040 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3041 pSMB->TotalDataCount = 0;
3042 pSMB->MaxParameterCount = cpu_to_le16(2);
3043 /* BB find exact max data count below from sess structure BB */
3044 pSMB->MaxDataCount = cpu_to_le16(4000);
3045 pSMB->MaxSetupCount = 0;
3046 pSMB->Reserved = 0;
3047 pSMB->Flags = 0;
3048 pSMB->Timeout = 0;
3049 pSMB->Reserved2 = 0;
3050 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3051 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3052 pSMB->DataCount = 0;
3053 pSMB->DataOffset = 0;
3054 pSMB->SetupCount = 1;
3055 pSMB->Reserved3 = 0;
3056 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3057 byte_count = params + 1 /* pad */ ;
3058 pSMB->TotalParameterCount = cpu_to_le16(params);
3059 pSMB->ParameterCount = pSMB->TotalParameterCount;
3060 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3061 pSMB->Reserved4 = 0;
3062 pSMB->hdr.smb_buf_length += byte_count;
3063 pSMB->ByteCount = cpu_to_le16(byte_count);
3064
3065 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3066 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3067 if (rc) {
3068 cFYI(1, ("error %d in QueryInternalInfo", rc));
3069 } else {
3070 /* decode response */
3071 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3072 if (rc || (pSMBr->ByteCount < 2))
3073 /* BB also check enough total bytes returned */
3074 /* If rc should we check for EOPNOSUPP and
3075 disable the srvino flag? or in caller? */
3076 rc = -EIO; /* bad smb */
3077 else {
3078 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3079 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3080 struct file_internal_info * pfinfo;
3081 /* BB Do we need a cast or hash here ? */
3082 if(count < 8) {
3083 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3084 rc = -EIO;
3085 goto GetInodeNumOut;
3086 }
3087 pfinfo = (struct file_internal_info *)
3088 (data_offset + (char *) &pSMBr->hdr.Protocol);
3089 *inode_number = pfinfo->UniqueId;
3090 }
3091 }
3092GetInodeNumOut:
3093 cifs_buf_release(pSMB);
3094 if (rc == -EAGAIN)
3095 goto GetInodeNumberRetry;
3096 return rc;
3097}
3098#endif /* CIFS_EXPERIMENTAL */
3099
3100int
3101CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3102 const unsigned char *searchName,
3103 unsigned char **targetUNCs,
3104 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003105 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106{
3107/* TRANS2_GET_DFS_REFERRAL */
3108 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3109 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3110 struct dfs_referral_level_3 * referrals = NULL;
3111 int rc = 0;
3112 int bytes_returned;
3113 int name_len;
3114 unsigned int i;
3115 char * temp;
3116 __u16 params, byte_count;
3117 *number_of_UNC_in_array = 0;
3118 *targetUNCs = NULL;
3119
3120 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3121 if (ses == NULL)
3122 return -ENODEV;
3123getDFSRetry:
3124 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3125 (void **) &pSMBr);
3126 if (rc)
3127 return rc;
Steve French1982c342005-08-17 12:38:22 -07003128
3129 /* server pointer checked in called function,
3130 but should never be null here anyway */
3131 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 pSMB->hdr.Tid = ses->ipc_tid;
3133 pSMB->hdr.Uid = ses->Suid;
3134 if (ses->capabilities & CAP_STATUS32) {
3135 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3136 }
3137 if (ses->capabilities & CAP_DFS) {
3138 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3139 }
3140
3141 if (ses->capabilities & CAP_UNICODE) {
3142 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3143 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003144 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003145 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 name_len++; /* trailing null */
3147 name_len *= 2;
3148 } else { /* BB improve the check for buffer overruns BB */
3149 name_len = strnlen(searchName, PATH_MAX);
3150 name_len++; /* trailing null */
3151 strncpy(pSMB->RequestFileName, searchName, name_len);
3152 }
3153
3154 params = 2 /* level */ + name_len /*includes null */ ;
3155 pSMB->TotalDataCount = 0;
3156 pSMB->DataCount = 0;
3157 pSMB->DataOffset = 0;
3158 pSMB->MaxParameterCount = 0;
3159 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3160 pSMB->MaxSetupCount = 0;
3161 pSMB->Reserved = 0;
3162 pSMB->Flags = 0;
3163 pSMB->Timeout = 0;
3164 pSMB->Reserved2 = 0;
3165 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3166 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3167 pSMB->SetupCount = 1;
3168 pSMB->Reserved3 = 0;
3169 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3170 byte_count = params + 3 /* pad */ ;
3171 pSMB->ParameterCount = cpu_to_le16(params);
3172 pSMB->TotalParameterCount = pSMB->ParameterCount;
3173 pSMB->MaxReferralLevel = cpu_to_le16(3);
3174 pSMB->hdr.smb_buf_length += byte_count;
3175 pSMB->ByteCount = cpu_to_le16(byte_count);
3176
3177 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3179 if (rc) {
3180 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3181 } else { /* decode response */
3182/* BB Add logic to parse referrals here */
3183 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3184
3185 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3186 rc = -EIO; /* bad smb */
3187 else {
3188 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3189 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3190
3191 cFYI(1,
3192 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3193 pSMBr->ByteCount, data_offset));
3194 referrals =
3195 (struct dfs_referral_level_3 *)
3196 (8 /* sizeof start of data block */ +
3197 data_offset +
3198 (char *) &pSMBr->hdr.Protocol);
3199 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",
3200 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)));
3201 /* BB This field is actually two bytes in from start of
3202 data block so we could do safety check that DataBlock
3203 begins at address of pSMBr->NumberOfReferrals */
3204 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3205
3206 /* BB Fix below so can return more than one referral */
3207 if(*number_of_UNC_in_array > 1)
3208 *number_of_UNC_in_array = 1;
3209
3210 /* get the length of the strings describing refs */
3211 name_len = 0;
3212 for(i=0;i<*number_of_UNC_in_array;i++) {
3213 /* make sure that DfsPathOffset not past end */
3214 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3215 if (offset > data_count) {
3216 /* if invalid referral, stop here and do
3217 not try to copy any more */
3218 *number_of_UNC_in_array = i;
3219 break;
3220 }
3221 temp = ((char *)referrals) + offset;
3222
3223 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3224 name_len += UniStrnlen((wchar_t *)temp,data_count);
3225 } else {
3226 name_len += strnlen(temp,data_count);
3227 }
3228 referrals++;
3229 /* BB add check that referral pointer does not fall off end PDU */
3230
3231 }
3232 /* BB add check for name_len bigger than bcc */
3233 *targetUNCs =
3234 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3235 if(*targetUNCs == NULL) {
3236 rc = -ENOMEM;
3237 goto GetDFSRefExit;
3238 }
3239 /* copy the ref strings */
3240 referrals =
3241 (struct dfs_referral_level_3 *)
3242 (8 /* sizeof data hdr */ +
3243 data_offset +
3244 (char *) &pSMBr->hdr.Protocol);
3245
3246 for(i=0;i<*number_of_UNC_in_array;i++) {
3247 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3248 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3249 cifs_strfromUCS_le(*targetUNCs,
3250 (wchar_t *) temp, name_len, nls_codepage);
3251 } else {
3252 strncpy(*targetUNCs,temp,name_len);
3253 }
3254 /* BB update target_uncs pointers */
3255 referrals++;
3256 }
3257 temp = *targetUNCs;
3258 temp[name_len] = 0;
3259 }
3260
3261 }
3262GetDFSRefExit:
3263 if (pSMB)
3264 cifs_buf_release(pSMB);
3265
3266 if (rc == -EAGAIN)
3267 goto getDFSRetry;
3268
3269 return rc;
3270}
3271
3272int
Steve French737b7582005-04-28 22:41:06 -07003273CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274{
3275/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3276 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3277 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3278 FILE_SYSTEM_INFO *response_data;
3279 int rc = 0;
3280 int bytes_returned = 0;
3281 __u16 params, byte_count;
3282
3283 cFYI(1, ("In QFSInfo"));
3284QFSInfoRetry:
3285 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3286 (void **) &pSMBr);
3287 if (rc)
3288 return rc;
3289
3290 params = 2; /* level */
3291 pSMB->TotalDataCount = 0;
3292 pSMB->MaxParameterCount = cpu_to_le16(2);
3293 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3294 pSMB->MaxSetupCount = 0;
3295 pSMB->Reserved = 0;
3296 pSMB->Flags = 0;
3297 pSMB->Timeout = 0;
3298 pSMB->Reserved2 = 0;
3299 byte_count = params + 1 /* pad */ ;
3300 pSMB->TotalParameterCount = cpu_to_le16(params);
3301 pSMB->ParameterCount = pSMB->TotalParameterCount;
3302 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3303 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3304 pSMB->DataCount = 0;
3305 pSMB->DataOffset = 0;
3306 pSMB->SetupCount = 1;
3307 pSMB->Reserved3 = 0;
3308 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3309 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3310 pSMB->hdr.smb_buf_length += byte_count;
3311 pSMB->ByteCount = cpu_to_le16(byte_count);
3312
3313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3314 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3315 if (rc) {
3316 cERROR(1, ("Send error in QFSInfo = %d", rc));
3317 } else { /* decode response */
3318 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3319
3320 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3321 rc = -EIO; /* bad smb */
3322 else {
3323 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3324 cFYI(1,
3325 ("Decoding qfsinfo response. BCC: %d Offset %d",
3326 pSMBr->ByteCount, data_offset));
3327
3328 response_data =
3329 (FILE_SYSTEM_INFO
3330 *) (((char *) &pSMBr->hdr.Protocol) +
3331 data_offset);
3332 FSData->f_bsize =
3333 le32_to_cpu(response_data->BytesPerSector) *
3334 le32_to_cpu(response_data->
3335 SectorsPerAllocationUnit);
3336 FSData->f_blocks =
3337 le64_to_cpu(response_data->TotalAllocationUnits);
3338 FSData->f_bfree = FSData->f_bavail =
3339 le64_to_cpu(response_data->FreeAllocationUnits);
3340 cFYI(1,
3341 ("Blocks: %lld Free: %lld Block size %ld",
3342 (unsigned long long)FSData->f_blocks,
3343 (unsigned long long)FSData->f_bfree,
3344 FSData->f_bsize));
3345 }
3346 }
3347 cifs_buf_release(pSMB);
3348
3349 if (rc == -EAGAIN)
3350 goto QFSInfoRetry;
3351
3352 return rc;
3353}
3354
3355int
Steve French737b7582005-04-28 22:41:06 -07003356CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357{
3358/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3359 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3360 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3361 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3362 int rc = 0;
3363 int bytes_returned = 0;
3364 __u16 params, byte_count;
3365
3366 cFYI(1, ("In QFSAttributeInfo"));
3367QFSAttributeRetry:
3368 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3369 (void **) &pSMBr);
3370 if (rc)
3371 return rc;
3372
3373 params = 2; /* level */
3374 pSMB->TotalDataCount = 0;
3375 pSMB->MaxParameterCount = cpu_to_le16(2);
3376 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3377 pSMB->MaxSetupCount = 0;
3378 pSMB->Reserved = 0;
3379 pSMB->Flags = 0;
3380 pSMB->Timeout = 0;
3381 pSMB->Reserved2 = 0;
3382 byte_count = params + 1 /* pad */ ;
3383 pSMB->TotalParameterCount = cpu_to_le16(params);
3384 pSMB->ParameterCount = pSMB->TotalParameterCount;
3385 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3386 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3387 pSMB->DataCount = 0;
3388 pSMB->DataOffset = 0;
3389 pSMB->SetupCount = 1;
3390 pSMB->Reserved3 = 0;
3391 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3392 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3393 pSMB->hdr.smb_buf_length += byte_count;
3394 pSMB->ByteCount = cpu_to_le16(byte_count);
3395
3396 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3397 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3398 if (rc) {
3399 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3400 } else { /* decode response */
3401 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3402
3403 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3404 rc = -EIO; /* bad smb */
3405 } else {
3406 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3407 response_data =
3408 (FILE_SYSTEM_ATTRIBUTE_INFO
3409 *) (((char *) &pSMBr->hdr.Protocol) +
3410 data_offset);
3411 memcpy(&tcon->fsAttrInfo, response_data,
3412 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3413 }
3414 }
3415 cifs_buf_release(pSMB);
3416
3417 if (rc == -EAGAIN)
3418 goto QFSAttributeRetry;
3419
3420 return rc;
3421}
3422
3423int
Steve French737b7582005-04-28 22:41:06 -07003424CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425{
3426/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3427 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3428 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3429 FILE_SYSTEM_DEVICE_INFO *response_data;
3430 int rc = 0;
3431 int bytes_returned = 0;
3432 __u16 params, byte_count;
3433
3434 cFYI(1, ("In QFSDeviceInfo"));
3435QFSDeviceRetry:
3436 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3437 (void **) &pSMBr);
3438 if (rc)
3439 return rc;
3440
3441 params = 2; /* level */
3442 pSMB->TotalDataCount = 0;
3443 pSMB->MaxParameterCount = cpu_to_le16(2);
3444 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3445 pSMB->MaxSetupCount = 0;
3446 pSMB->Reserved = 0;
3447 pSMB->Flags = 0;
3448 pSMB->Timeout = 0;
3449 pSMB->Reserved2 = 0;
3450 byte_count = params + 1 /* pad */ ;
3451 pSMB->TotalParameterCount = cpu_to_le16(params);
3452 pSMB->ParameterCount = pSMB->TotalParameterCount;
3453 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3454 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3455
3456 pSMB->DataCount = 0;
3457 pSMB->DataOffset = 0;
3458 pSMB->SetupCount = 1;
3459 pSMB->Reserved3 = 0;
3460 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3461 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3462 pSMB->hdr.smb_buf_length += byte_count;
3463 pSMB->ByteCount = cpu_to_le16(byte_count);
3464
3465 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3466 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3467 if (rc) {
3468 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3469 } else { /* decode response */
3470 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3471
3472 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3473 rc = -EIO; /* bad smb */
3474 else {
3475 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3476 response_data =
Steve French737b7582005-04-28 22:41:06 -07003477 (FILE_SYSTEM_DEVICE_INFO *)
3478 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 data_offset);
3480 memcpy(&tcon->fsDevInfo, response_data,
3481 sizeof (FILE_SYSTEM_DEVICE_INFO));
3482 }
3483 }
3484 cifs_buf_release(pSMB);
3485
3486 if (rc == -EAGAIN)
3487 goto QFSDeviceRetry;
3488
3489 return rc;
3490}
3491
3492int
Steve French737b7582005-04-28 22:41:06 -07003493CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494{
3495/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3496 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3497 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3498 FILE_SYSTEM_UNIX_INFO *response_data;
3499 int rc = 0;
3500 int bytes_returned = 0;
3501 __u16 params, byte_count;
3502
3503 cFYI(1, ("In QFSUnixInfo"));
3504QFSUnixRetry:
3505 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3506 (void **) &pSMBr);
3507 if (rc)
3508 return rc;
3509
3510 params = 2; /* level */
3511 pSMB->TotalDataCount = 0;
3512 pSMB->DataCount = 0;
3513 pSMB->DataOffset = 0;
3514 pSMB->MaxParameterCount = cpu_to_le16(2);
3515 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3516 pSMB->MaxSetupCount = 0;
3517 pSMB->Reserved = 0;
3518 pSMB->Flags = 0;
3519 pSMB->Timeout = 0;
3520 pSMB->Reserved2 = 0;
3521 byte_count = params + 1 /* pad */ ;
3522 pSMB->ParameterCount = cpu_to_le16(params);
3523 pSMB->TotalParameterCount = pSMB->ParameterCount;
3524 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3525 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3526 pSMB->SetupCount = 1;
3527 pSMB->Reserved3 = 0;
3528 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3529 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3530 pSMB->hdr.smb_buf_length += byte_count;
3531 pSMB->ByteCount = cpu_to_le16(byte_count);
3532
3533 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3534 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3535 if (rc) {
3536 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3537 } else { /* decode response */
3538 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3539
3540 if (rc || (pSMBr->ByteCount < 13)) {
3541 rc = -EIO; /* bad smb */
3542 } else {
3543 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3544 response_data =
3545 (FILE_SYSTEM_UNIX_INFO
3546 *) (((char *) &pSMBr->hdr.Protocol) +
3547 data_offset);
3548 memcpy(&tcon->fsUnixInfo, response_data,
3549 sizeof (FILE_SYSTEM_UNIX_INFO));
3550 }
3551 }
3552 cifs_buf_release(pSMB);
3553
3554 if (rc == -EAGAIN)
3555 goto QFSUnixRetry;
3556
3557
3558 return rc;
3559}
3560
Jeremy Allisonac670552005-06-22 17:26:35 -07003561int
Steve French45abc6e2005-06-23 13:42:03 -05003562CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003563{
3564/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3565 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3566 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3567 int rc = 0;
3568 int bytes_returned = 0;
3569 __u16 params, param_offset, offset, byte_count;
3570
3571 cFYI(1, ("In SETFSUnixInfo"));
3572SETFSUnixRetry:
3573 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3574 (void **) &pSMBr);
3575 if (rc)
3576 return rc;
3577
3578 params = 4; /* 2 bytes zero followed by info level. */
3579 pSMB->MaxSetupCount = 0;
3580 pSMB->Reserved = 0;
3581 pSMB->Flags = 0;
3582 pSMB->Timeout = 0;
3583 pSMB->Reserved2 = 0;
3584 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3585 offset = param_offset + params;
3586
3587 pSMB->MaxParameterCount = cpu_to_le16(4);
3588 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3589 pSMB->SetupCount = 1;
3590 pSMB->Reserved3 = 0;
3591 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3592 byte_count = 1 /* pad */ + params + 12;
3593
3594 pSMB->DataCount = cpu_to_le16(12);
3595 pSMB->ParameterCount = cpu_to_le16(params);
3596 pSMB->TotalDataCount = pSMB->DataCount;
3597 pSMB->TotalParameterCount = pSMB->ParameterCount;
3598 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3599 pSMB->DataOffset = cpu_to_le16(offset);
3600
3601 /* Params. */
3602 pSMB->FileNum = 0;
3603 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3604
3605 /* Data. */
3606 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3607 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3608 pSMB->ClientUnixCap = cpu_to_le64(cap);
3609
3610 pSMB->hdr.smb_buf_length += byte_count;
3611 pSMB->ByteCount = cpu_to_le16(byte_count);
3612
3613 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3614 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3615 if (rc) {
3616 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3617 } else { /* decode response */
3618 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3619 if (rc) {
3620 rc = -EIO; /* bad smb */
3621 }
3622 }
3623 cifs_buf_release(pSMB);
3624
3625 if (rc == -EAGAIN)
3626 goto SETFSUnixRetry;
3627
3628 return rc;
3629}
3630
3631
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632
3633int
3634CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003635 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636{
3637/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3638 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3639 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3640 FILE_SYSTEM_POSIX_INFO *response_data;
3641 int rc = 0;
3642 int bytes_returned = 0;
3643 __u16 params, byte_count;
3644
3645 cFYI(1, ("In QFSPosixInfo"));
3646QFSPosixRetry:
3647 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3648 (void **) &pSMBr);
3649 if (rc)
3650 return rc;
3651
3652 params = 2; /* level */
3653 pSMB->TotalDataCount = 0;
3654 pSMB->DataCount = 0;
3655 pSMB->DataOffset = 0;
3656 pSMB->MaxParameterCount = cpu_to_le16(2);
3657 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3658 pSMB->MaxSetupCount = 0;
3659 pSMB->Reserved = 0;
3660 pSMB->Flags = 0;
3661 pSMB->Timeout = 0;
3662 pSMB->Reserved2 = 0;
3663 byte_count = params + 1 /* pad */ ;
3664 pSMB->ParameterCount = cpu_to_le16(params);
3665 pSMB->TotalParameterCount = pSMB->ParameterCount;
3666 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3667 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3668 pSMB->SetupCount = 1;
3669 pSMB->Reserved3 = 0;
3670 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3671 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3672 pSMB->hdr.smb_buf_length += byte_count;
3673 pSMB->ByteCount = cpu_to_le16(byte_count);
3674
3675 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3677 if (rc) {
3678 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3679 } else { /* decode response */
3680 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3681
3682 if (rc || (pSMBr->ByteCount < 13)) {
3683 rc = -EIO; /* bad smb */
3684 } else {
3685 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3686 response_data =
3687 (FILE_SYSTEM_POSIX_INFO
3688 *) (((char *) &pSMBr->hdr.Protocol) +
3689 data_offset);
3690 FSData->f_bsize =
3691 le32_to_cpu(response_data->BlockSize);
3692 FSData->f_blocks =
3693 le64_to_cpu(response_data->TotalBlocks);
3694 FSData->f_bfree =
3695 le64_to_cpu(response_data->BlocksAvail);
3696 if(response_data->UserBlocksAvail == -1) {
3697 FSData->f_bavail = FSData->f_bfree;
3698 } else {
3699 FSData->f_bavail =
3700 le64_to_cpu(response_data->UserBlocksAvail);
3701 }
3702 if(response_data->TotalFileNodes != -1)
3703 FSData->f_files =
3704 le64_to_cpu(response_data->TotalFileNodes);
3705 if(response_data->FreeFileNodes != -1)
3706 FSData->f_ffree =
3707 le64_to_cpu(response_data->FreeFileNodes);
3708 }
3709 }
3710 cifs_buf_release(pSMB);
3711
3712 if (rc == -EAGAIN)
3713 goto QFSPosixRetry;
3714
3715 return rc;
3716}
3717
3718
3719/* We can not use write of zero bytes trick to
3720 set file size due to need for large file support. Also note that
3721 this SetPathInfo is preferred to SetFileInfo based method in next
3722 routine which is only needed to work around a sharing violation bug
3723 in Samba which this routine can run into */
3724
3725int
3726CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003727 __u64 size, int SetAllocation,
3728 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729{
3730 struct smb_com_transaction2_spi_req *pSMB = NULL;
3731 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3732 struct file_end_of_file_info *parm_data;
3733 int name_len;
3734 int rc = 0;
3735 int bytes_returned = 0;
3736 __u16 params, byte_count, data_count, param_offset, offset;
3737
3738 cFYI(1, ("In SetEOF"));
3739SetEOFRetry:
3740 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3741 (void **) &pSMBr);
3742 if (rc)
3743 return rc;
3744
3745 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3746 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003747 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003748 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 name_len++; /* trailing null */
3750 name_len *= 2;
3751 } else { /* BB improve the check for buffer overruns BB */
3752 name_len = strnlen(fileName, PATH_MAX);
3753 name_len++; /* trailing null */
3754 strncpy(pSMB->FileName, fileName, name_len);
3755 }
3756 params = 6 + name_len;
3757 data_count = sizeof (struct file_end_of_file_info);
3758 pSMB->MaxParameterCount = cpu_to_le16(2);
3759 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3760 pSMB->MaxSetupCount = 0;
3761 pSMB->Reserved = 0;
3762 pSMB->Flags = 0;
3763 pSMB->Timeout = 0;
3764 pSMB->Reserved2 = 0;
3765 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3766 InformationLevel) - 4;
3767 offset = param_offset + params;
3768 if(SetAllocation) {
3769 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3770 pSMB->InformationLevel =
3771 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3772 else
3773 pSMB->InformationLevel =
3774 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3775 } else /* Set File Size */ {
3776 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3777 pSMB->InformationLevel =
3778 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3779 else
3780 pSMB->InformationLevel =
3781 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3782 }
3783
3784 parm_data =
3785 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3786 offset);
3787 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3788 pSMB->DataOffset = cpu_to_le16(offset);
3789 pSMB->SetupCount = 1;
3790 pSMB->Reserved3 = 0;
3791 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3792 byte_count = 3 /* pad */ + params + data_count;
3793 pSMB->DataCount = cpu_to_le16(data_count);
3794 pSMB->TotalDataCount = pSMB->DataCount;
3795 pSMB->ParameterCount = cpu_to_le16(params);
3796 pSMB->TotalParameterCount = pSMB->ParameterCount;
3797 pSMB->Reserved4 = 0;
3798 pSMB->hdr.smb_buf_length += byte_count;
3799 parm_data->FileSize = cpu_to_le64(size);
3800 pSMB->ByteCount = cpu_to_le16(byte_count);
3801 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3802 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3803 if (rc) {
3804 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3805 }
3806
3807 cifs_buf_release(pSMB);
3808
3809 if (rc == -EAGAIN)
3810 goto SetEOFRetry;
3811
3812 return rc;
3813}
3814
3815int
3816CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3817 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3818{
3819 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3820 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3821 char *data_offset;
3822 struct file_end_of_file_info *parm_data;
3823 int rc = 0;
3824 int bytes_returned = 0;
3825 __u16 params, param_offset, offset, byte_count, count;
3826
3827 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3828 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003829 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 if (rc)
3832 return rc;
3833
Steve Frenchcd634992005-04-28 22:41:10 -07003834 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3835
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3837 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3838
3839 params = 6;
3840 pSMB->MaxSetupCount = 0;
3841 pSMB->Reserved = 0;
3842 pSMB->Flags = 0;
3843 pSMB->Timeout = 0;
3844 pSMB->Reserved2 = 0;
3845 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3846 offset = param_offset + params;
3847
3848 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3849
3850 count = sizeof(struct file_end_of_file_info);
3851 pSMB->MaxParameterCount = cpu_to_le16(2);
3852 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3853 pSMB->SetupCount = 1;
3854 pSMB->Reserved3 = 0;
3855 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3856 byte_count = 3 /* pad */ + params + count;
3857 pSMB->DataCount = cpu_to_le16(count);
3858 pSMB->ParameterCount = cpu_to_le16(params);
3859 pSMB->TotalDataCount = pSMB->DataCount;
3860 pSMB->TotalParameterCount = pSMB->ParameterCount;
3861 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3862 parm_data =
3863 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3864 offset);
3865 pSMB->DataOffset = cpu_to_le16(offset);
3866 parm_data->FileSize = cpu_to_le64(size);
3867 pSMB->Fid = fid;
3868 if(SetAllocation) {
3869 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3870 pSMB->InformationLevel =
3871 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3872 else
3873 pSMB->InformationLevel =
3874 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3875 } else /* Set File Size */ {
3876 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3877 pSMB->InformationLevel =
3878 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3879 else
3880 pSMB->InformationLevel =
3881 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3882 }
3883 pSMB->Reserved4 = 0;
3884 pSMB->hdr.smb_buf_length += byte_count;
3885 pSMB->ByteCount = cpu_to_le16(byte_count);
3886 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3887 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3888 if (rc) {
3889 cFYI(1,
3890 ("Send error in SetFileInfo (SetFileSize) = %d",
3891 rc));
3892 }
3893
3894 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003895 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896
3897 /* Note: On -EAGAIN error only caller can retry on handle based calls
3898 since file handle passed in no longer valid */
3899
3900 return rc;
3901}
3902
3903/* Some legacy servers such as NT4 require that the file times be set on
3904 an open handle, rather than by pathname - this is awkward due to
3905 potential access conflicts on the open, but it is unavoidable for these
3906 old servers since the only other choice is to go from 100 nanosecond DCE
3907 time and resort to the original setpathinfo level which takes the ancient
3908 DOS time format with 2 second granularity */
3909int
3910CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3911 __u16 fid)
3912{
3913 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3914 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3915 char *data_offset;
3916 int rc = 0;
3917 int bytes_returned = 0;
3918 __u16 params, param_offset, offset, byte_count, count;
3919
3920 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003921 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3922
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 if (rc)
3924 return rc;
3925
Steve Frenchcd634992005-04-28 22:41:10 -07003926 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3927
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 /* At this point there is no need to override the current pid
3929 with the pid of the opener, but that could change if we someday
3930 use an existing handle (rather than opening one on the fly) */
3931 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3932 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3933
3934 params = 6;
3935 pSMB->MaxSetupCount = 0;
3936 pSMB->Reserved = 0;
3937 pSMB->Flags = 0;
3938 pSMB->Timeout = 0;
3939 pSMB->Reserved2 = 0;
3940 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3941 offset = param_offset + params;
3942
3943 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3944
3945 count = sizeof (FILE_BASIC_INFO);
3946 pSMB->MaxParameterCount = cpu_to_le16(2);
3947 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3948 pSMB->SetupCount = 1;
3949 pSMB->Reserved3 = 0;
3950 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3951 byte_count = 3 /* pad */ + params + count;
3952 pSMB->DataCount = cpu_to_le16(count);
3953 pSMB->ParameterCount = cpu_to_le16(params);
3954 pSMB->TotalDataCount = pSMB->DataCount;
3955 pSMB->TotalParameterCount = pSMB->ParameterCount;
3956 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3957 pSMB->DataOffset = cpu_to_le16(offset);
3958 pSMB->Fid = fid;
3959 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3960 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3961 else
3962 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3963 pSMB->Reserved4 = 0;
3964 pSMB->hdr.smb_buf_length += byte_count;
3965 pSMB->ByteCount = cpu_to_le16(byte_count);
3966 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3967 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3968 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3969 if (rc) {
3970 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3971 }
3972
Steve Frenchcd634992005-04-28 22:41:10 -07003973 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974
3975 /* Note: On -EAGAIN error only caller can retry on handle based calls
3976 since file handle passed in no longer valid */
3977
3978 return rc;
3979}
3980
3981
3982int
3983CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3984 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07003985 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986{
3987 TRANSACTION2_SPI_REQ *pSMB = NULL;
3988 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3989 int name_len;
3990 int rc = 0;
3991 int bytes_returned = 0;
3992 char *data_offset;
3993 __u16 params, param_offset, offset, byte_count, count;
3994
3995 cFYI(1, ("In SetTimes"));
3996
3997SetTimesRetry:
3998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3999 (void **) &pSMBr);
4000 if (rc)
4001 return rc;
4002
4003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4004 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004005 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004006 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 name_len++; /* trailing null */
4008 name_len *= 2;
4009 } else { /* BB improve the check for buffer overruns BB */
4010 name_len = strnlen(fileName, PATH_MAX);
4011 name_len++; /* trailing null */
4012 strncpy(pSMB->FileName, fileName, name_len);
4013 }
4014
4015 params = 6 + name_len;
4016 count = sizeof (FILE_BASIC_INFO);
4017 pSMB->MaxParameterCount = cpu_to_le16(2);
4018 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4019 pSMB->MaxSetupCount = 0;
4020 pSMB->Reserved = 0;
4021 pSMB->Flags = 0;
4022 pSMB->Timeout = 0;
4023 pSMB->Reserved2 = 0;
4024 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4025 InformationLevel) - 4;
4026 offset = param_offset + params;
4027 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4028 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4029 pSMB->DataOffset = cpu_to_le16(offset);
4030 pSMB->SetupCount = 1;
4031 pSMB->Reserved3 = 0;
4032 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4033 byte_count = 3 /* pad */ + params + count;
4034
4035 pSMB->DataCount = cpu_to_le16(count);
4036 pSMB->ParameterCount = cpu_to_le16(params);
4037 pSMB->TotalDataCount = pSMB->DataCount;
4038 pSMB->TotalParameterCount = pSMB->ParameterCount;
4039 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4040 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4041 else
4042 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4043 pSMB->Reserved4 = 0;
4044 pSMB->hdr.smb_buf_length += byte_count;
4045 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4046 pSMB->ByteCount = cpu_to_le16(byte_count);
4047 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4048 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4049 if (rc) {
4050 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4051 }
4052
4053 cifs_buf_release(pSMB);
4054
4055 if (rc == -EAGAIN)
4056 goto SetTimesRetry;
4057
4058 return rc;
4059}
4060
4061/* Can not be used to set time stamps yet (due to old DOS time format) */
4062/* Can be used to set attributes */
4063#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4064 handling it anyway and NT4 was what we thought it would be needed for
4065 Do not delete it until we prove whether needed for Win9x though */
4066int
4067CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4068 __u16 dos_attrs, const struct nls_table *nls_codepage)
4069{
4070 SETATTR_REQ *pSMB = NULL;
4071 SETATTR_RSP *pSMBr = NULL;
4072 int rc = 0;
4073 int bytes_returned;
4074 int name_len;
4075
4076 cFYI(1, ("In SetAttrLegacy"));
4077
4078SetAttrLgcyRetry:
4079 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4080 (void **) &pSMBr);
4081 if (rc)
4082 return rc;
4083
4084 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4085 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004086 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 PATH_MAX, nls_codepage);
4088 name_len++; /* trailing null */
4089 name_len *= 2;
4090 } else { /* BB improve the check for buffer overruns BB */
4091 name_len = strnlen(fileName, PATH_MAX);
4092 name_len++; /* trailing null */
4093 strncpy(pSMB->fileName, fileName, name_len);
4094 }
4095 pSMB->attr = cpu_to_le16(dos_attrs);
4096 pSMB->BufferFormat = 0x04;
4097 pSMB->hdr.smb_buf_length += name_len + 1;
4098 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4101 if (rc) {
4102 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4103 }
4104
4105 cifs_buf_release(pSMB);
4106
4107 if (rc == -EAGAIN)
4108 goto SetAttrLgcyRetry;
4109
4110 return rc;
4111}
4112#endif /* temporarily unneeded SetAttr legacy function */
4113
4114int
4115CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004116 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4117 dev_t device, const struct nls_table *nls_codepage,
4118 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119{
4120 TRANSACTION2_SPI_REQ *pSMB = NULL;
4121 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4122 int name_len;
4123 int rc = 0;
4124 int bytes_returned = 0;
4125 FILE_UNIX_BASIC_INFO *data_offset;
4126 __u16 params, param_offset, offset, count, byte_count;
4127
4128 cFYI(1, ("In SetUID/GID/Mode"));
4129setPermsRetry:
4130 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4131 (void **) &pSMBr);
4132 if (rc)
4133 return rc;
4134
4135 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4136 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004137 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004138 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 name_len++; /* trailing null */
4140 name_len *= 2;
4141 } else { /* BB improve the check for buffer overruns BB */
4142 name_len = strnlen(fileName, PATH_MAX);
4143 name_len++; /* trailing null */
4144 strncpy(pSMB->FileName, fileName, name_len);
4145 }
4146
4147 params = 6 + name_len;
4148 count = sizeof (FILE_UNIX_BASIC_INFO);
4149 pSMB->MaxParameterCount = cpu_to_le16(2);
4150 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4151 pSMB->MaxSetupCount = 0;
4152 pSMB->Reserved = 0;
4153 pSMB->Flags = 0;
4154 pSMB->Timeout = 0;
4155 pSMB->Reserved2 = 0;
4156 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4157 InformationLevel) - 4;
4158 offset = param_offset + params;
4159 data_offset =
4160 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4161 offset);
4162 memset(data_offset, 0, count);
4163 pSMB->DataOffset = cpu_to_le16(offset);
4164 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4165 pSMB->SetupCount = 1;
4166 pSMB->Reserved3 = 0;
4167 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4168 byte_count = 3 /* pad */ + params + count;
4169 pSMB->ParameterCount = cpu_to_le16(params);
4170 pSMB->DataCount = cpu_to_le16(count);
4171 pSMB->TotalParameterCount = pSMB->ParameterCount;
4172 pSMB->TotalDataCount = pSMB->DataCount;
4173 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4174 pSMB->Reserved4 = 0;
4175 pSMB->hdr.smb_buf_length += byte_count;
4176 data_offset->Uid = cpu_to_le64(uid);
4177 data_offset->Gid = cpu_to_le64(gid);
4178 /* better to leave device as zero when it is */
4179 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4180 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4181 data_offset->Permissions = cpu_to_le64(mode);
4182
4183 if(S_ISREG(mode))
4184 data_offset->Type = cpu_to_le32(UNIX_FILE);
4185 else if(S_ISDIR(mode))
4186 data_offset->Type = cpu_to_le32(UNIX_DIR);
4187 else if(S_ISLNK(mode))
4188 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4189 else if(S_ISCHR(mode))
4190 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4191 else if(S_ISBLK(mode))
4192 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4193 else if(S_ISFIFO(mode))
4194 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4195 else if(S_ISSOCK(mode))
4196 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4197
4198
4199 pSMB->ByteCount = cpu_to_le16(byte_count);
4200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4202 if (rc) {
4203 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4204 }
4205
4206 if (pSMB)
4207 cifs_buf_release(pSMB);
4208 if (rc == -EAGAIN)
4209 goto setPermsRetry;
4210 return rc;
4211}
4212
4213int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004214 const int notify_subdirs, const __u16 netfid,
4215 __u32 filter, struct file * pfile, int multishot,
4216 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218 int rc = 0;
4219 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4220 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004221 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 int bytes_returned;
4223
4224 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4225 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4226 (void **) &pSMBr);
4227 if (rc)
4228 return rc;
4229
4230 pSMB->TotalParameterCount = 0 ;
4231 pSMB->TotalDataCount = 0;
4232 pSMB->MaxParameterCount = cpu_to_le32(2);
4233 /* BB find exact data count max from sess structure BB */
4234 pSMB->MaxDataCount = 0; /* same in little endian or be */
4235 pSMB->MaxSetupCount = 4;
4236 pSMB->Reserved = 0;
4237 pSMB->ParameterOffset = 0;
4238 pSMB->DataCount = 0;
4239 pSMB->DataOffset = 0;
4240 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4241 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4242 pSMB->ParameterCount = pSMB->TotalParameterCount;
4243 if(notify_subdirs)
4244 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4245 pSMB->Reserved2 = 0;
4246 pSMB->CompletionFilter = cpu_to_le32(filter);
4247 pSMB->Fid = netfid; /* file handle always le */
4248 pSMB->ByteCount = 0;
4249
4250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4251 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4252 if (rc) {
4253 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004254 } else {
4255 /* Add file to outstanding requests */
4256 dnotify_req = (struct dir_notify_req *) kmalloc(
4257 sizeof(struct dir_notify_req), GFP_KERNEL);
4258 dnotify_req->Pid = pSMB->hdr.Pid;
4259 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4260 dnotify_req->Mid = pSMB->hdr.Mid;
4261 dnotify_req->Tid = pSMB->hdr.Tid;
4262 dnotify_req->Uid = pSMB->hdr.Uid;
4263 dnotify_req->netfid = netfid;
Steve French167a2512005-08-24 20:03:11 -07004264 dnotify_req->pfile = pfile;
Steve Frenchff5dbd92005-08-24 17:10:36 -07004265 dnotify_req->filter = filter;
4266 dnotify_req->multishot = multishot;
4267 spin_lock(&GlobalMid_Lock);
4268 list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
4269 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 }
4271 cifs_buf_release(pSMB);
4272 return rc;
4273}
4274#ifdef CONFIG_CIFS_XATTR
4275ssize_t
4276CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4277 const unsigned char *searchName,
4278 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004279 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280{
4281 /* BB assumes one setup word */
4282 TRANSACTION2_QPI_REQ *pSMB = NULL;
4283 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4284 int rc = 0;
4285 int bytes_returned;
4286 int name_len;
4287 struct fea * temp_fea;
4288 char * temp_ptr;
4289 __u16 params, byte_count;
4290
4291 cFYI(1, ("In Query All EAs path %s", searchName));
4292QAllEAsRetry:
4293 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4294 (void **) &pSMBr);
4295 if (rc)
4296 return rc;
4297
4298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4299 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004300 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004301 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 name_len++; /* trailing null */
4303 name_len *= 2;
4304 } else { /* BB improve the check for buffer overruns BB */
4305 name_len = strnlen(searchName, PATH_MAX);
4306 name_len++; /* trailing null */
4307 strncpy(pSMB->FileName, searchName, name_len);
4308 }
4309
4310 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4311 pSMB->TotalDataCount = 0;
4312 pSMB->MaxParameterCount = cpu_to_le16(2);
4313 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4314 pSMB->MaxSetupCount = 0;
4315 pSMB->Reserved = 0;
4316 pSMB->Flags = 0;
4317 pSMB->Timeout = 0;
4318 pSMB->Reserved2 = 0;
4319 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4320 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4321 pSMB->DataCount = 0;
4322 pSMB->DataOffset = 0;
4323 pSMB->SetupCount = 1;
4324 pSMB->Reserved3 = 0;
4325 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4326 byte_count = params + 1 /* pad */ ;
4327 pSMB->TotalParameterCount = cpu_to_le16(params);
4328 pSMB->ParameterCount = pSMB->TotalParameterCount;
4329 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4330 pSMB->Reserved4 = 0;
4331 pSMB->hdr.smb_buf_length += byte_count;
4332 pSMB->ByteCount = cpu_to_le16(byte_count);
4333
4334 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4335 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4336 if (rc) {
4337 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4338 } else { /* decode response */
4339 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4340
4341 /* BB also check enough total bytes returned */
4342 /* BB we need to improve the validity checking
4343 of these trans2 responses */
4344 if (rc || (pSMBr->ByteCount < 4))
4345 rc = -EIO; /* bad smb */
4346 /* else if (pFindData){
4347 memcpy((char *) pFindData,
4348 (char *) &pSMBr->hdr.Protocol +
4349 data_offset, kl);
4350 }*/ else {
4351 /* check that length of list is not more than bcc */
4352 /* check that each entry does not go beyond length
4353 of list */
4354 /* check that each element of each entry does not
4355 go beyond end of list */
4356 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4357 struct fealist * ea_response_data;
4358 rc = 0;
4359 /* validate_trans2_offsets() */
4360 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4361 ea_response_data = (struct fealist *)
4362 (((char *) &pSMBr->hdr.Protocol) +
4363 data_offset);
4364 name_len = le32_to_cpu(ea_response_data->list_len);
4365 cFYI(1,("ea length %d", name_len));
4366 if(name_len <= 8) {
4367 /* returned EA size zeroed at top of function */
4368 cFYI(1,("empty EA list returned from server"));
4369 } else {
4370 /* account for ea list len */
4371 name_len -= 4;
4372 temp_fea = ea_response_data->list;
4373 temp_ptr = (char *)temp_fea;
4374 while(name_len > 0) {
4375 __u16 value_len;
4376 name_len -= 4;
4377 temp_ptr += 4;
4378 rc += temp_fea->name_len;
4379 /* account for prefix user. and trailing null */
4380 rc = rc + 5 + 1;
4381 if(rc<(int)buf_size) {
4382 memcpy(EAData,"user.",5);
4383 EAData+=5;
4384 memcpy(EAData,temp_ptr,temp_fea->name_len);
4385 EAData+=temp_fea->name_len;
4386 /* null terminate name */
4387 *EAData = 0;
4388 EAData = EAData + 1;
4389 } else if(buf_size == 0) {
4390 /* skip copy - calc size only */
4391 } else {
4392 /* stop before overrun buffer */
4393 rc = -ERANGE;
4394 break;
4395 }
4396 name_len -= temp_fea->name_len;
4397 temp_ptr += temp_fea->name_len;
4398 /* account for trailing null */
4399 name_len--;
4400 temp_ptr++;
4401 value_len = le16_to_cpu(temp_fea->value_len);
4402 name_len -= value_len;
4403 temp_ptr += value_len;
4404 /* BB check that temp_ptr is still within smb BB*/
4405 /* no trailing null to account for in value len */
4406 /* go on to next EA */
4407 temp_fea = (struct fea *)temp_ptr;
4408 }
4409 }
4410 }
4411 }
4412 if (pSMB)
4413 cifs_buf_release(pSMB);
4414 if (rc == -EAGAIN)
4415 goto QAllEAsRetry;
4416
4417 return (ssize_t)rc;
4418}
4419
4420ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4421 const unsigned char * searchName,const unsigned char * ea_name,
4422 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004423 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424{
4425 TRANSACTION2_QPI_REQ *pSMB = NULL;
4426 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4427 int rc = 0;
4428 int bytes_returned;
4429 int name_len;
4430 struct fea * temp_fea;
4431 char * temp_ptr;
4432 __u16 params, byte_count;
4433
4434 cFYI(1, ("In Query EA path %s", searchName));
4435QEARetry:
4436 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4437 (void **) &pSMBr);
4438 if (rc)
4439 return rc;
4440
4441 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4442 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004443 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004444 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 name_len++; /* trailing null */
4446 name_len *= 2;
4447 } else { /* BB improve the check for buffer overruns BB */
4448 name_len = strnlen(searchName, PATH_MAX);
4449 name_len++; /* trailing null */
4450 strncpy(pSMB->FileName, searchName, name_len);
4451 }
4452
4453 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4454 pSMB->TotalDataCount = 0;
4455 pSMB->MaxParameterCount = cpu_to_le16(2);
4456 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4457 pSMB->MaxSetupCount = 0;
4458 pSMB->Reserved = 0;
4459 pSMB->Flags = 0;
4460 pSMB->Timeout = 0;
4461 pSMB->Reserved2 = 0;
4462 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4463 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4464 pSMB->DataCount = 0;
4465 pSMB->DataOffset = 0;
4466 pSMB->SetupCount = 1;
4467 pSMB->Reserved3 = 0;
4468 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4469 byte_count = params + 1 /* pad */ ;
4470 pSMB->TotalParameterCount = cpu_to_le16(params);
4471 pSMB->ParameterCount = pSMB->TotalParameterCount;
4472 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4473 pSMB->Reserved4 = 0;
4474 pSMB->hdr.smb_buf_length += byte_count;
4475 pSMB->ByteCount = cpu_to_le16(byte_count);
4476
4477 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4478 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4479 if (rc) {
4480 cFYI(1, ("Send error in Query EA = %d", rc));
4481 } else { /* decode response */
4482 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4483
4484 /* BB also check enough total bytes returned */
4485 /* BB we need to improve the validity checking
4486 of these trans2 responses */
4487 if (rc || (pSMBr->ByteCount < 4))
4488 rc = -EIO; /* bad smb */
4489 /* else if (pFindData){
4490 memcpy((char *) pFindData,
4491 (char *) &pSMBr->hdr.Protocol +
4492 data_offset, kl);
4493 }*/ else {
4494 /* check that length of list is not more than bcc */
4495 /* check that each entry does not go beyond length
4496 of list */
4497 /* check that each element of each entry does not
4498 go beyond end of list */
4499 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4500 struct fealist * ea_response_data;
4501 rc = -ENODATA;
4502 /* validate_trans2_offsets() */
4503 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4504 ea_response_data = (struct fealist *)
4505 (((char *) &pSMBr->hdr.Protocol) +
4506 data_offset);
4507 name_len = le32_to_cpu(ea_response_data->list_len);
4508 cFYI(1,("ea length %d", name_len));
4509 if(name_len <= 8) {
4510 /* returned EA size zeroed at top of function */
4511 cFYI(1,("empty EA list returned from server"));
4512 } else {
4513 /* account for ea list len */
4514 name_len -= 4;
4515 temp_fea = ea_response_data->list;
4516 temp_ptr = (char *)temp_fea;
4517 /* loop through checking if we have a matching
4518 name and then return the associated value */
4519 while(name_len > 0) {
4520 __u16 value_len;
4521 name_len -= 4;
4522 temp_ptr += 4;
4523 value_len = le16_to_cpu(temp_fea->value_len);
4524 /* BB validate that value_len falls within SMB,
4525 even though maximum for name_len is 255 */
4526 if(memcmp(temp_fea->name,ea_name,
4527 temp_fea->name_len) == 0) {
4528 /* found a match */
4529 rc = value_len;
4530 /* account for prefix user. and trailing null */
4531 if(rc<=(int)buf_size) {
4532 memcpy(ea_value,
4533 temp_fea->name+temp_fea->name_len+1,
4534 rc);
4535 /* ea values, unlike ea names,
4536 are not null terminated */
4537 } else if(buf_size == 0) {
4538 /* skip copy - calc size only */
4539 } else {
4540 /* stop before overrun buffer */
4541 rc = -ERANGE;
4542 }
4543 break;
4544 }
4545 name_len -= temp_fea->name_len;
4546 temp_ptr += temp_fea->name_len;
4547 /* account for trailing null */
4548 name_len--;
4549 temp_ptr++;
4550 name_len -= value_len;
4551 temp_ptr += value_len;
4552 /* no trailing null to account for in value len */
4553 /* go on to next EA */
4554 temp_fea = (struct fea *)temp_ptr;
4555 }
4556 }
4557 }
4558 }
4559 if (pSMB)
4560 cifs_buf_release(pSMB);
4561 if (rc == -EAGAIN)
4562 goto QEARetry;
4563
4564 return (ssize_t)rc;
4565}
4566
4567int
4568CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4569 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004570 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4571 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572{
4573 struct smb_com_transaction2_spi_req *pSMB = NULL;
4574 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4575 struct fealist *parm_data;
4576 int name_len;
4577 int rc = 0;
4578 int bytes_returned = 0;
4579 __u16 params, param_offset, byte_count, offset, count;
4580
4581 cFYI(1, ("In SetEA"));
4582SetEARetry:
4583 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4584 (void **) &pSMBr);
4585 if (rc)
4586 return rc;
4587
4588 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4589 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004590 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004591 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 name_len++; /* trailing null */
4593 name_len *= 2;
4594 } else { /* BB improve the check for buffer overruns BB */
4595 name_len = strnlen(fileName, PATH_MAX);
4596 name_len++; /* trailing null */
4597 strncpy(pSMB->FileName, fileName, name_len);
4598 }
4599
4600 params = 6 + name_len;
4601
4602 /* done calculating parms using name_len of file name,
4603 now use name_len to calculate length of ea name
4604 we are going to create in the inode xattrs */
4605 if(ea_name == NULL)
4606 name_len = 0;
4607 else
4608 name_len = strnlen(ea_name,255);
4609
4610 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4611 pSMB->MaxParameterCount = cpu_to_le16(2);
4612 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4613 pSMB->MaxSetupCount = 0;
4614 pSMB->Reserved = 0;
4615 pSMB->Flags = 0;
4616 pSMB->Timeout = 0;
4617 pSMB->Reserved2 = 0;
4618 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4619 InformationLevel) - 4;
4620 offset = param_offset + params;
4621 pSMB->InformationLevel =
4622 cpu_to_le16(SMB_SET_FILE_EA);
4623
4624 parm_data =
4625 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4626 offset);
4627 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4628 pSMB->DataOffset = cpu_to_le16(offset);
4629 pSMB->SetupCount = 1;
4630 pSMB->Reserved3 = 0;
4631 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4632 byte_count = 3 /* pad */ + params + count;
4633 pSMB->DataCount = cpu_to_le16(count);
4634 parm_data->list_len = cpu_to_le32(count);
4635 parm_data->list[0].EA_flags = 0;
4636 /* we checked above that name len is less than 255 */
4637 parm_data->list[0].name_len = (__u8)name_len;;
4638 /* EA names are always ASCII */
4639 if(ea_name)
4640 strncpy(parm_data->list[0].name,ea_name,name_len);
4641 parm_data->list[0].name[name_len] = 0;
4642 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4643 /* caller ensures that ea_value_len is less than 64K but
4644 we need to ensure that it fits within the smb */
4645
4646 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4647 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4648 if(ea_value_len)
4649 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4650
4651 pSMB->TotalDataCount = pSMB->DataCount;
4652 pSMB->ParameterCount = cpu_to_le16(params);
4653 pSMB->TotalParameterCount = pSMB->ParameterCount;
4654 pSMB->Reserved4 = 0;
4655 pSMB->hdr.smb_buf_length += byte_count;
4656 pSMB->ByteCount = cpu_to_le16(byte_count);
4657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4659 if (rc) {
4660 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4661 }
4662
4663 cifs_buf_release(pSMB);
4664
4665 if (rc == -EAGAIN)
4666 goto SetEARetry;
4667
4668 return rc;
4669}
4670
4671#endif