blob: c8ae3ef422baa4372ad0ab4e14d1ab53db2f73ba [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;
1085 int bytes_returned;
1086 __u32 bytes_sent;
1087 __u16 byte_count;
1088
1089 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1090 rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
1091 (void **) &pSMBr);
1092 if (rc)
1093 return rc;
1094 /* tcon and ses pointer are checked in smb_init */
1095 if (tcon->ses->server == NULL)
1096 return -ECONNABORTED;
1097
1098 pSMB->AndXCommand = 0xFF; /* none */
1099 pSMB->Fid = netfid;
1100 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1101 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1102 pSMB->Reserved = 0xFFFFFFFF;
1103 pSMB->WriteMode = 0;
1104 pSMB->Remaining = 0;
1105
1106 /* Can increase buffer size if buffer is big enough in some cases - ie we
1107 can send more if LARGE_WRITE_X capability returned by the server and if
1108 our buffer is big enough or if we convert to iovecs on socket writes
1109 and eliminate the copy to the CIFS buffer */
1110 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1111 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1112 } else {
1113 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1114 & ~0xFF;
1115 }
1116
1117 if (bytes_sent > count)
1118 bytes_sent = count;
1119 pSMB->DataOffset =
1120 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1121 if(buf)
1122 memcpy(pSMB->Data,buf,bytes_sent);
1123 else if(ubuf) {
1124 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1125 cifs_buf_release(pSMB);
1126 return -EFAULT;
1127 }
1128 } else {
1129 /* No buffer */
1130 cifs_buf_release(pSMB);
1131 return -EINVAL;
1132 }
1133
1134 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1135 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1136 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1137 pSMB->hdr.smb_buf_length += bytes_sent+1;
1138 pSMB->ByteCount = cpu_to_le16(byte_count);
1139
1140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1141 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001142 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 if (rc) {
1144 cFYI(1, ("Send error in write = %d", rc));
1145 *nbytes = 0;
1146 } else {
1147 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1148 *nbytes = (*nbytes) << 16;
1149 *nbytes += le16_to_cpu(pSMBr->Count);
1150 }
1151
1152 cifs_buf_release(pSMB);
1153
1154 /* Note: On -EAGAIN error only caller can retry on handle based calls
1155 since file handle passed in no longer valid */
1156
1157 return rc;
1158}
1159
1160#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001161int
1162CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 const int netfid, const unsigned int count,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001164 const __u64 offset, unsigned int *nbytes, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 const int long_op)
1166{
1167 int rc = -EACCES;
1168 WRITE_REQ *pSMB = NULL;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001169 int bytes_returned;
1170 int smb_hdr_len;
1171 __u32 bytes_sent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 __u16 byte_count;
1173
Steve French0c0ff092005-06-23 19:31:17 -05001174 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (rc)
1177 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 /* tcon and ses pointer are checked in smb_init */
1179 if (tcon->ses->server == NULL)
1180 return -ECONNABORTED;
1181
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001182 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 pSMB->Fid = netfid;
1184 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1185 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1186 pSMB->Reserved = 0xFFFFFFFF;
1187 pSMB->WriteMode = 0;
1188 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001189
1190 /* Can increase buffer size if buffer is big enough in some cases - ie
1191 can send more if LARGE_WRITE_X capability returned by the server and if
1192 our buffer is big enough or if we convert to iovecs on socket writes
1193 and eliminate the copy to the CIFS buffer */
1194 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1195 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1196 } else {
1197 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1198 & ~0xFF;
1199 }
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 if (bytes_sent > count)
1202 bytes_sent = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 pSMB->DataOffset =
1204 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1205
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001206 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1207 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1208 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1209 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1210 pSMB->hdr.smb_buf_length += bytes_sent+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 pSMB->ByteCount = cpu_to_le16(byte_count);
1212
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001213 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1214 buf, bytes_sent, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001215 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 if (rc) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001217 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001219 } else {
1220 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1221 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1222 *nbytes = (*nbytes) << 16;
1223 *nbytes += le16_to_cpu(pSMBr->Count);
1224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226 cifs_small_buf_release(pSMB);
1227
1228 /* Note: On -EAGAIN error only caller can retry on handle based calls
1229 since file handle passed in no longer valid */
1230
1231 return rc;
1232}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001233
1234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235#endif /* CIFS_EXPERIMENTAL */
1236
1237int
1238CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1239 const __u16 smb_file_id, const __u64 len,
1240 const __u64 offset, const __u32 numUnlock,
1241 const __u32 numLock, const __u8 lockType, const int waitFlag)
1242{
1243 int rc = 0;
1244 LOCK_REQ *pSMB = NULL;
1245 LOCK_RSP *pSMBr = NULL;
1246 int bytes_returned;
1247 int timeout = 0;
1248 __u16 count;
1249
1250 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001251 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 if (rc)
1254 return rc;
1255
Steve French46810cb2005-04-28 22:41:09 -07001256 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1259 timeout = -1; /* no response expected */
1260 pSMB->Timeout = 0;
1261 } else if (waitFlag == TRUE) {
1262 timeout = 3; /* blocking operation, no timeout */
1263 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1264 } else {
1265 pSMB->Timeout = 0;
1266 }
1267
1268 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1269 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1270 pSMB->LockType = lockType;
1271 pSMB->AndXCommand = 0xFF; /* none */
1272 pSMB->Fid = smb_file_id; /* netfid stays le */
1273
1274 if((numLock != 0) || (numUnlock != 0)) {
1275 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1276 /* BB where to store pid high? */
1277 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1278 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1279 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1280 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1281 count = sizeof(LOCKING_ANDX_RANGE);
1282 } else {
1283 /* oplock break */
1284 count = 0;
1285 }
1286 pSMB->hdr.smb_buf_length += count;
1287 pSMB->ByteCount = cpu_to_le16(count);
1288
1289 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1290 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001291 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 if (rc) {
1293 cFYI(1, ("Send error in Lock = %d", rc));
1294 }
Steve French46810cb2005-04-28 22:41:09 -07001295 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
1297 /* Note: On -EAGAIN error only caller can retry on handle based calls
1298 since file handle passed in no longer valid */
1299 return rc;
1300}
1301
1302int
1303CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1304{
1305 int rc = 0;
1306 CLOSE_REQ *pSMB = NULL;
1307 CLOSE_RSP *pSMBr = NULL;
1308 int bytes_returned;
1309 cFYI(1, ("In CIFSSMBClose"));
1310
1311/* do not retry on dead session on close */
1312 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1313 if(rc == -EAGAIN)
1314 return 0;
1315 if (rc)
1316 return rc;
1317
1318 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1319
1320 pSMB->FileID = (__u16) smb_file_id;
1321 pSMB->LastWriteTime = 0;
1322 pSMB->ByteCount = 0;
1323 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1324 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001325 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 if (rc) {
1327 if(rc!=-EINTR) {
1328 /* EINTR is expected when user ctl-c to kill app */
1329 cERROR(1, ("Send error in Close = %d", rc));
1330 }
1331 }
1332
1333 cifs_small_buf_release(pSMB);
1334
1335 /* Since session is dead, file will be closed on server already */
1336 if(rc == -EAGAIN)
1337 rc = 0;
1338
1339 return rc;
1340}
1341
1342int
1343CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1344 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001345 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346{
1347 int rc = 0;
1348 RENAME_REQ *pSMB = NULL;
1349 RENAME_RSP *pSMBr = NULL;
1350 int bytes_returned;
1351 int name_len, name_len2;
1352 __u16 count;
1353
1354 cFYI(1, ("In CIFSSMBRename"));
1355renameRetry:
1356 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1357 (void **) &pSMBr);
1358 if (rc)
1359 return rc;
1360
1361 pSMB->BufferFormat = 0x04;
1362 pSMB->SearchAttributes =
1363 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1364 ATTR_DIRECTORY);
1365
1366 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1367 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001368 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001369 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 name_len++; /* trailing null */
1371 name_len *= 2;
1372 pSMB->OldFileName[name_len] = 0x04; /* pad */
1373 /* protocol requires ASCII signature byte on Unicode string */
1374 pSMB->OldFileName[name_len + 1] = 0x00;
1375 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001376 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001377 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1379 name_len2 *= 2; /* convert to bytes */
1380 } else { /* BB improve the check for buffer overruns BB */
1381 name_len = strnlen(fromName, PATH_MAX);
1382 name_len++; /* trailing null */
1383 strncpy(pSMB->OldFileName, fromName, name_len);
1384 name_len2 = strnlen(toName, PATH_MAX);
1385 name_len2++; /* trailing null */
1386 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1387 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1388 name_len2++; /* trailing null */
1389 name_len2++; /* signature byte */
1390 }
1391
1392 count = 1 /* 1st signature byte */ + name_len + name_len2;
1393 pSMB->hdr.smb_buf_length += count;
1394 pSMB->ByteCount = cpu_to_le16(count);
1395
1396 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1397 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001398 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 if (rc) {
1400 cFYI(1, ("Send error in rename = %d", rc));
1401 }
1402
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 cifs_buf_release(pSMB);
1404
1405 if (rc == -EAGAIN)
1406 goto renameRetry;
1407
1408 return rc;
1409}
1410
1411int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001412 int netfid, char * target_name,
1413 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414{
1415 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1416 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1417 struct set_file_rename * rename_info;
1418 char *data_offset;
1419 char dummy_string[30];
1420 int rc = 0;
1421 int bytes_returned = 0;
1422 int len_of_str;
1423 __u16 params, param_offset, offset, count, byte_count;
1424
1425 cFYI(1, ("Rename to File by handle"));
1426 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1427 (void **) &pSMBr);
1428 if (rc)
1429 return rc;
1430
1431 params = 6;
1432 pSMB->MaxSetupCount = 0;
1433 pSMB->Reserved = 0;
1434 pSMB->Flags = 0;
1435 pSMB->Timeout = 0;
1436 pSMB->Reserved2 = 0;
1437 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1438 offset = param_offset + params;
1439
1440 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1441 rename_info = (struct set_file_rename *) data_offset;
1442 pSMB->MaxParameterCount = cpu_to_le16(2);
1443 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1444 pSMB->SetupCount = 1;
1445 pSMB->Reserved3 = 0;
1446 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1447 byte_count = 3 /* pad */ + params;
1448 pSMB->ParameterCount = cpu_to_le16(params);
1449 pSMB->TotalParameterCount = pSMB->ParameterCount;
1450 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1451 pSMB->DataOffset = cpu_to_le16(offset);
1452 /* construct random name ".cifs_tmp<inodenum><mid>" */
1453 rename_info->overwrite = cpu_to_le32(1);
1454 rename_info->root_fid = 0;
1455 /* unicode only call */
1456 if(target_name == NULL) {
1457 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001458 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001459 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001461 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001462 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 }
1464 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1465 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1466 byte_count += count;
1467 pSMB->DataCount = cpu_to_le16(count);
1468 pSMB->TotalDataCount = pSMB->DataCount;
1469 pSMB->Fid = netfid;
1470 pSMB->InformationLevel =
1471 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1472 pSMB->Reserved4 = 0;
1473 pSMB->hdr.smb_buf_length += byte_count;
1474 pSMB->ByteCount = cpu_to_le16(byte_count);
1475 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1476 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001477 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 if (rc) {
1479 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1480 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001481
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 cifs_buf_release(pSMB);
1483
1484 /* Note: On -EAGAIN error only caller can retry on handle based calls
1485 since file handle passed in no longer valid */
1486
1487 return rc;
1488}
1489
1490int
1491CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1492 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001493 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
1495 int rc = 0;
1496 COPY_REQ *pSMB = NULL;
1497 COPY_RSP *pSMBr = NULL;
1498 int bytes_returned;
1499 int name_len, name_len2;
1500 __u16 count;
1501
1502 cFYI(1, ("In CIFSSMBCopy"));
1503copyRetry:
1504 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1505 (void **) &pSMBr);
1506 if (rc)
1507 return rc;
1508
1509 pSMB->BufferFormat = 0x04;
1510 pSMB->Tid2 = target_tid;
1511
1512 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1513
1514 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001515 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001516 fromName, PATH_MAX, nls_codepage,
1517 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 name_len++; /* trailing null */
1519 name_len *= 2;
1520 pSMB->OldFileName[name_len] = 0x04; /* pad */
1521 /* protocol requires ASCII signature byte on Unicode string */
1522 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001523 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001524 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1526 name_len2 *= 2; /* convert to bytes */
1527 } else { /* BB improve the check for buffer overruns BB */
1528 name_len = strnlen(fromName, PATH_MAX);
1529 name_len++; /* trailing null */
1530 strncpy(pSMB->OldFileName, fromName, name_len);
1531 name_len2 = strnlen(toName, PATH_MAX);
1532 name_len2++; /* trailing null */
1533 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1534 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1535 name_len2++; /* trailing null */
1536 name_len2++; /* signature byte */
1537 }
1538
1539 count = 1 /* 1st signature byte */ + name_len + name_len2;
1540 pSMB->hdr.smb_buf_length += count;
1541 pSMB->ByteCount = cpu_to_le16(count);
1542
1543 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1544 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1545 if (rc) {
1546 cFYI(1, ("Send error in copy = %d with %d files copied",
1547 rc, le16_to_cpu(pSMBr->CopyCount)));
1548 }
1549 if (pSMB)
1550 cifs_buf_release(pSMB);
1551
1552 if (rc == -EAGAIN)
1553 goto copyRetry;
1554
1555 return rc;
1556}
1557
1558int
1559CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1560 const char *fromName, const char *toName,
1561 const struct nls_table *nls_codepage)
1562{
1563 TRANSACTION2_SPI_REQ *pSMB = NULL;
1564 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1565 char *data_offset;
1566 int name_len;
1567 int name_len_target;
1568 int rc = 0;
1569 int bytes_returned = 0;
1570 __u16 params, param_offset, offset, byte_count;
1571
1572 cFYI(1, ("In Symlink Unix style"));
1573createSymLinkRetry:
1574 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1575 (void **) &pSMBr);
1576 if (rc)
1577 return rc;
1578
1579 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1580 name_len =
1581 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1582 /* find define for this maxpathcomponent */
1583 , nls_codepage);
1584 name_len++; /* trailing null */
1585 name_len *= 2;
1586
1587 } else { /* BB improve the check for buffer overruns BB */
1588 name_len = strnlen(fromName, PATH_MAX);
1589 name_len++; /* trailing null */
1590 strncpy(pSMB->FileName, fromName, name_len);
1591 }
1592 params = 6 + name_len;
1593 pSMB->MaxSetupCount = 0;
1594 pSMB->Reserved = 0;
1595 pSMB->Flags = 0;
1596 pSMB->Timeout = 0;
1597 pSMB->Reserved2 = 0;
1598 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1599 InformationLevel) - 4;
1600 offset = param_offset + params;
1601
1602 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1603 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1604 name_len_target =
1605 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1606 /* find define for this maxpathcomponent */
1607 , nls_codepage);
1608 name_len_target++; /* trailing null */
1609 name_len_target *= 2;
1610 } else { /* BB improve the check for buffer overruns BB */
1611 name_len_target = strnlen(toName, PATH_MAX);
1612 name_len_target++; /* trailing null */
1613 strncpy(data_offset, toName, name_len_target);
1614 }
1615
1616 pSMB->MaxParameterCount = cpu_to_le16(2);
1617 /* BB find exact max on data count below from sess */
1618 pSMB->MaxDataCount = cpu_to_le16(1000);
1619 pSMB->SetupCount = 1;
1620 pSMB->Reserved3 = 0;
1621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1622 byte_count = 3 /* pad */ + params + name_len_target;
1623 pSMB->DataCount = cpu_to_le16(name_len_target);
1624 pSMB->ParameterCount = cpu_to_le16(params);
1625 pSMB->TotalDataCount = pSMB->DataCount;
1626 pSMB->TotalParameterCount = pSMB->ParameterCount;
1627 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1628 pSMB->DataOffset = cpu_to_le16(offset);
1629 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1630 pSMB->Reserved4 = 0;
1631 pSMB->hdr.smb_buf_length += byte_count;
1632 pSMB->ByteCount = cpu_to_le16(byte_count);
1633 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1634 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001635 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 if (rc) {
1637 cFYI(1,
1638 ("Send error in SetPathInfo (create symlink) = %d",
1639 rc));
1640 }
1641
1642 if (pSMB)
1643 cifs_buf_release(pSMB);
1644
1645 if (rc == -EAGAIN)
1646 goto createSymLinkRetry;
1647
1648 return rc;
1649}
1650
1651int
1652CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1653 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001654 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655{
1656 TRANSACTION2_SPI_REQ *pSMB = NULL;
1657 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1658 char *data_offset;
1659 int name_len;
1660 int name_len_target;
1661 int rc = 0;
1662 int bytes_returned = 0;
1663 __u16 params, param_offset, offset, byte_count;
1664
1665 cFYI(1, ("In Create Hard link Unix style"));
1666createHardLinkRetry:
1667 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1668 (void **) &pSMBr);
1669 if (rc)
1670 return rc;
1671
1672 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001673 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001674 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 name_len++; /* trailing null */
1676 name_len *= 2;
1677
1678 } else { /* BB improve the check for buffer overruns BB */
1679 name_len = strnlen(toName, PATH_MAX);
1680 name_len++; /* trailing null */
1681 strncpy(pSMB->FileName, toName, name_len);
1682 }
1683 params = 6 + name_len;
1684 pSMB->MaxSetupCount = 0;
1685 pSMB->Reserved = 0;
1686 pSMB->Flags = 0;
1687 pSMB->Timeout = 0;
1688 pSMB->Reserved2 = 0;
1689 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1690 InformationLevel) - 4;
1691 offset = param_offset + params;
1692
1693 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1694 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1695 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001696 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001697 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 name_len_target++; /* trailing null */
1699 name_len_target *= 2;
1700 } else { /* BB improve the check for buffer overruns BB */
1701 name_len_target = strnlen(fromName, PATH_MAX);
1702 name_len_target++; /* trailing null */
1703 strncpy(data_offset, fromName, name_len_target);
1704 }
1705
1706 pSMB->MaxParameterCount = cpu_to_le16(2);
1707 /* BB find exact max on data count below from sess*/
1708 pSMB->MaxDataCount = cpu_to_le16(1000);
1709 pSMB->SetupCount = 1;
1710 pSMB->Reserved3 = 0;
1711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1712 byte_count = 3 /* pad */ + params + name_len_target;
1713 pSMB->ParameterCount = cpu_to_le16(params);
1714 pSMB->TotalParameterCount = pSMB->ParameterCount;
1715 pSMB->DataCount = cpu_to_le16(name_len_target);
1716 pSMB->TotalDataCount = pSMB->DataCount;
1717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1718 pSMB->DataOffset = cpu_to_le16(offset);
1719 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1720 pSMB->Reserved4 = 0;
1721 pSMB->hdr.smb_buf_length += byte_count;
1722 pSMB->ByteCount = cpu_to_le16(byte_count);
1723 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001725 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (rc) {
1727 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1728 }
1729
1730 cifs_buf_release(pSMB);
1731 if (rc == -EAGAIN)
1732 goto createHardLinkRetry;
1733
1734 return rc;
1735}
1736
1737int
1738CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1739 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001740 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741{
1742 int rc = 0;
1743 NT_RENAME_REQ *pSMB = NULL;
1744 RENAME_RSP *pSMBr = NULL;
1745 int bytes_returned;
1746 int name_len, name_len2;
1747 __u16 count;
1748
1749 cFYI(1, ("In CIFSCreateHardLink"));
1750winCreateHardLinkRetry:
1751
1752 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1753 (void **) &pSMBr);
1754 if (rc)
1755 return rc;
1756
1757 pSMB->SearchAttributes =
1758 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1759 ATTR_DIRECTORY);
1760 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1761 pSMB->ClusterCount = 0;
1762
1763 pSMB->BufferFormat = 0x04;
1764
1765 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1766 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001767 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001768 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 name_len++; /* trailing null */
1770 name_len *= 2;
1771 pSMB->OldFileName[name_len] = 0; /* pad */
1772 pSMB->OldFileName[name_len + 1] = 0x04;
1773 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001774 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001775 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1777 name_len2 *= 2; /* convert to bytes */
1778 } else { /* BB improve the check for buffer overruns BB */
1779 name_len = strnlen(fromName, PATH_MAX);
1780 name_len++; /* trailing null */
1781 strncpy(pSMB->OldFileName, fromName, name_len);
1782 name_len2 = strnlen(toName, PATH_MAX);
1783 name_len2++; /* trailing null */
1784 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1785 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1786 name_len2++; /* trailing null */
1787 name_len2++; /* signature byte */
1788 }
1789
1790 count = 1 /* string type byte */ + name_len + name_len2;
1791 pSMB->hdr.smb_buf_length += count;
1792 pSMB->ByteCount = cpu_to_le16(count);
1793
1794 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1795 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001796 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 if (rc) {
1798 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1799 }
1800 cifs_buf_release(pSMB);
1801 if (rc == -EAGAIN)
1802 goto winCreateHardLinkRetry;
1803
1804 return rc;
1805}
1806
1807int
1808CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1809 const unsigned char *searchName,
1810 char *symlinkinfo, const int buflen,
1811 const struct nls_table *nls_codepage)
1812{
1813/* SMB_QUERY_FILE_UNIX_LINK */
1814 TRANSACTION2_QPI_REQ *pSMB = NULL;
1815 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1816 int rc = 0;
1817 int bytes_returned;
1818 int name_len;
1819 __u16 params, byte_count;
1820
1821 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1822
1823querySymLinkRetry:
1824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1825 (void **) &pSMBr);
1826 if (rc)
1827 return rc;
1828
1829 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1830 name_len =
1831 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1832 /* find define for this maxpathcomponent */
1833 , nls_codepage);
1834 name_len++; /* trailing null */
1835 name_len *= 2;
1836 } else { /* BB improve the check for buffer overruns BB */
1837 name_len = strnlen(searchName, PATH_MAX);
1838 name_len++; /* trailing null */
1839 strncpy(pSMB->FileName, searchName, name_len);
1840 }
1841
1842 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1843 pSMB->TotalDataCount = 0;
1844 pSMB->MaxParameterCount = cpu_to_le16(2);
1845 /* BB find exact max data count below from sess structure BB */
1846 pSMB->MaxDataCount = cpu_to_le16(4000);
1847 pSMB->MaxSetupCount = 0;
1848 pSMB->Reserved = 0;
1849 pSMB->Flags = 0;
1850 pSMB->Timeout = 0;
1851 pSMB->Reserved2 = 0;
1852 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1853 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1854 pSMB->DataCount = 0;
1855 pSMB->DataOffset = 0;
1856 pSMB->SetupCount = 1;
1857 pSMB->Reserved3 = 0;
1858 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1859 byte_count = params + 1 /* pad */ ;
1860 pSMB->TotalParameterCount = cpu_to_le16(params);
1861 pSMB->ParameterCount = pSMB->TotalParameterCount;
1862 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1863 pSMB->Reserved4 = 0;
1864 pSMB->hdr.smb_buf_length += byte_count;
1865 pSMB->ByteCount = cpu_to_le16(byte_count);
1866
1867 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1868 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1869 if (rc) {
1870 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1871 } else {
1872 /* decode response */
1873
1874 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1875 if (rc || (pSMBr->ByteCount < 2))
1876 /* BB also check enough total bytes returned */
1877 rc = -EIO; /* bad smb */
1878 else {
1879 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1880 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1881
1882 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1883 name_len = UniStrnlen((wchar_t *) ((char *)
1884 &pSMBr->hdr.Protocol +data_offset),
1885 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001886 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 cifs_strfromUCS_le(symlinkinfo,
1888 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1889 data_offset),
1890 name_len, nls_codepage);
1891 } else {
1892 strncpy(symlinkinfo,
1893 (char *) &pSMBr->hdr.Protocol +
1894 data_offset,
1895 min_t(const int, buflen, count));
1896 }
1897 symlinkinfo[buflen] = 0;
1898 /* just in case so calling code does not go off the end of buffer */
1899 }
1900 }
1901 cifs_buf_release(pSMB);
1902 if (rc == -EAGAIN)
1903 goto querySymLinkRetry;
1904 return rc;
1905}
1906
1907int
1908CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1909 const unsigned char *searchName,
1910 char *symlinkinfo, const int buflen,__u16 fid,
1911 const struct nls_table *nls_codepage)
1912{
1913 int rc = 0;
1914 int bytes_returned;
1915 int name_len;
1916 struct smb_com_transaction_ioctl_req * pSMB;
1917 struct smb_com_transaction_ioctl_rsp * pSMBr;
1918
1919 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1920 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1921 (void **) &pSMBr);
1922 if (rc)
1923 return rc;
1924
1925 pSMB->TotalParameterCount = 0 ;
1926 pSMB->TotalDataCount = 0;
1927 pSMB->MaxParameterCount = cpu_to_le32(2);
1928 /* BB find exact data count max from sess structure BB */
1929 pSMB->MaxDataCount = cpu_to_le32(4000);
1930 pSMB->MaxSetupCount = 4;
1931 pSMB->Reserved = 0;
1932 pSMB->ParameterOffset = 0;
1933 pSMB->DataCount = 0;
1934 pSMB->DataOffset = 0;
1935 pSMB->SetupCount = 4;
1936 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1937 pSMB->ParameterCount = pSMB->TotalParameterCount;
1938 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1939 pSMB->IsFsctl = 1; /* FSCTL */
1940 pSMB->IsRootFlag = 0;
1941 pSMB->Fid = fid; /* file handle always le */
1942 pSMB->ByteCount = 0;
1943
1944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1946 if (rc) {
1947 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1948 } else { /* decode response */
1949 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1950 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1951 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1952 /* BB also check enough total bytes returned */
1953 rc = -EIO; /* bad smb */
1954 else {
1955 if(data_count && (data_count < 2048)) {
1956 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1957
1958 struct reparse_data * reparse_buf = (struct reparse_data *)
1959 ((char *)&pSMBr->hdr.Protocol + data_offset);
1960 if((char*)reparse_buf >= end_of_smb) {
1961 rc = -EIO;
1962 goto qreparse_out;
1963 }
1964 if((reparse_buf->LinkNamesBuf +
1965 reparse_buf->TargetNameOffset +
1966 reparse_buf->TargetNameLen) >
1967 end_of_smb) {
1968 cFYI(1,("reparse buf extended beyond SMB"));
1969 rc = -EIO;
1970 goto qreparse_out;
1971 }
1972
1973 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1974 name_len = UniStrnlen((wchar_t *)
1975 (reparse_buf->LinkNamesBuf +
1976 reparse_buf->TargetNameOffset),
1977 min(buflen/2, reparse_buf->TargetNameLen / 2));
1978 cifs_strfromUCS_le(symlinkinfo,
1979 (wchar_t *) (reparse_buf->LinkNamesBuf +
1980 reparse_buf->TargetNameOffset),
1981 name_len, nls_codepage);
1982 } else { /* ASCII names */
1983 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1984 reparse_buf->TargetNameOffset,
1985 min_t(const int, buflen, reparse_buf->TargetNameLen));
1986 }
1987 } else {
1988 rc = -EIO;
1989 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1990 }
1991 symlinkinfo[buflen] = 0; /* just in case so the caller
1992 does not go off the end of the buffer */
1993 cFYI(1,("readlink result - %s ",symlinkinfo));
1994 }
1995 }
1996qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001997 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998
1999 /* Note: On -EAGAIN error only caller can retry on handle based calls
2000 since file handle passed in no longer valid */
2001
2002 return rc;
2003}
2004
2005#ifdef CONFIG_CIFS_POSIX
2006
2007/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2008static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2009{
2010 /* u8 cifs fields do not need le conversion */
2011 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
2012 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
2013 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
2014 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2015
2016 return;
2017}
2018
2019/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002020static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2021 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022{
2023 int size = 0;
2024 int i;
2025 __u16 count;
2026 struct cifs_posix_ace * pACE;
2027 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2028 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2029
2030 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2031 return -EOPNOTSUPP;
2032
2033 if(acl_type & ACL_TYPE_ACCESS) {
2034 count = le16_to_cpu(cifs_acl->access_entry_count);
2035 pACE = &cifs_acl->ace_array[0];
2036 size = sizeof(struct cifs_posix_acl);
2037 size += sizeof(struct cifs_posix_ace) * count;
2038 /* check if we would go beyond end of SMB */
2039 if(size_of_data_area < size) {
2040 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2041 return -EINVAL;
2042 }
2043 } else if(acl_type & ACL_TYPE_DEFAULT) {
2044 count = le16_to_cpu(cifs_acl->access_entry_count);
2045 size = sizeof(struct cifs_posix_acl);
2046 size += sizeof(struct cifs_posix_ace) * count;
2047/* skip past access ACEs to get to default ACEs */
2048 pACE = &cifs_acl->ace_array[count];
2049 count = le16_to_cpu(cifs_acl->default_entry_count);
2050 size += sizeof(struct cifs_posix_ace) * count;
2051 /* check if we would go beyond end of SMB */
2052 if(size_of_data_area < size)
2053 return -EINVAL;
2054 } else {
2055 /* illegal type */
2056 return -EINVAL;
2057 }
2058
2059 size = posix_acl_xattr_size(count);
2060 if((buflen == 0) || (local_acl == NULL)) {
2061 /* used to query ACL EA size */
2062 } else if(size > buflen) {
2063 return -ERANGE;
2064 } else /* buffer big enough */ {
2065 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
2066 for(i = 0;i < count ;i++) {
2067 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2068 pACE ++;
2069 }
2070 }
2071 return size;
2072}
2073
2074static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2075 const posix_acl_xattr_entry * local_ace)
2076{
2077 __u16 rc = 0; /* 0 = ACL converted ok */
2078
2079 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
2080 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
2081 /* BB is there a better way to handle the large uid? */
2082 if(local_ace->e_id == -1) {
2083 /* Probably no need to le convert -1 on any arch but can not hurt */
2084 cifs_ace->cifs_uid = cpu_to_le64(-1);
2085 } else
2086 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
2087 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2088 return rc;
2089}
2090
2091/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2092static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2093 const int acl_type)
2094{
2095 __u16 rc = 0;
2096 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2097 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2098 int count;
2099 int i;
2100
2101 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2102 return 0;
2103
2104 count = posix_acl_xattr_count((size_t)buflen);
2105 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2106 count,buflen,local_acl->a_version));
2107 if(local_acl->a_version != 2) {
2108 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
2109 return 0;
2110 }
2111 cifs_acl->version = cpu_to_le16(1);
2112 if(acl_type == ACL_TYPE_ACCESS)
2113 cifs_acl->access_entry_count = count;
2114 else if(acl_type == ACL_TYPE_DEFAULT)
2115 cifs_acl->default_entry_count = count;
2116 else {
2117 cFYI(1,("unknown ACL type %d",acl_type));
2118 return 0;
2119 }
2120 for(i=0;i<count;i++) {
2121 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2122 &local_acl->a_entries[i]);
2123 if(rc != 0) {
2124 /* ACE not converted */
2125 break;
2126 }
2127 }
2128 if(rc == 0) {
2129 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2130 rc += sizeof(struct cifs_posix_acl);
2131 /* BB add check to make sure ACL does not overflow SMB */
2132 }
2133 return rc;
2134}
2135
2136int
2137CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2138 const unsigned char *searchName,
2139 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002140 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141{
2142/* SMB_QUERY_POSIX_ACL */
2143 TRANSACTION2_QPI_REQ *pSMB = NULL;
2144 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2145 int rc = 0;
2146 int bytes_returned;
2147 int name_len;
2148 __u16 params, byte_count;
2149
2150 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2151
2152queryAclRetry:
2153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154 (void **) &pSMBr);
2155 if (rc)
2156 return rc;
2157
2158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2159 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002160 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002161 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 name_len++; /* trailing null */
2163 name_len *= 2;
2164 pSMB->FileName[name_len] = 0;
2165 pSMB->FileName[name_len+1] = 0;
2166 } else { /* BB improve the check for buffer overruns BB */
2167 name_len = strnlen(searchName, PATH_MAX);
2168 name_len++; /* trailing null */
2169 strncpy(pSMB->FileName, searchName, name_len);
2170 }
2171
2172 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2173 pSMB->TotalDataCount = 0;
2174 pSMB->MaxParameterCount = cpu_to_le16(2);
2175 /* BB find exact max data count below from sess structure BB */
2176 pSMB->MaxDataCount = cpu_to_le16(4000);
2177 pSMB->MaxSetupCount = 0;
2178 pSMB->Reserved = 0;
2179 pSMB->Flags = 0;
2180 pSMB->Timeout = 0;
2181 pSMB->Reserved2 = 0;
2182 pSMB->ParameterOffset = cpu_to_le16(
2183 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2184 pSMB->DataCount = 0;
2185 pSMB->DataOffset = 0;
2186 pSMB->SetupCount = 1;
2187 pSMB->Reserved3 = 0;
2188 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2189 byte_count = params + 1 /* pad */ ;
2190 pSMB->TotalParameterCount = cpu_to_le16(params);
2191 pSMB->ParameterCount = pSMB->TotalParameterCount;
2192 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2193 pSMB->Reserved4 = 0;
2194 pSMB->hdr.smb_buf_length += byte_count;
2195 pSMB->ByteCount = cpu_to_le16(byte_count);
2196
2197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2199 if (rc) {
2200 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2201 } else {
2202 /* decode response */
2203
2204 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2205 if (rc || (pSMBr->ByteCount < 2))
2206 /* BB also check enough total bytes returned */
2207 rc = -EIO; /* bad smb */
2208 else {
2209 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2210 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2211 rc = cifs_copy_posix_acl(acl_inf,
2212 (char *)&pSMBr->hdr.Protocol+data_offset,
2213 buflen,acl_type,count);
2214 }
2215 }
2216 cifs_buf_release(pSMB);
2217 if (rc == -EAGAIN)
2218 goto queryAclRetry;
2219 return rc;
2220}
2221
2222int
2223CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2224 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002225 const char *local_acl, const int buflen,
2226 const int acl_type,
2227 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228{
2229 struct smb_com_transaction2_spi_req *pSMB = NULL;
2230 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2231 char *parm_data;
2232 int name_len;
2233 int rc = 0;
2234 int bytes_returned = 0;
2235 __u16 params, byte_count, data_count, param_offset, offset;
2236
2237 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2238setAclRetry:
2239 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2240 (void **) &pSMBr);
2241 if (rc)
2242 return rc;
2243 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2244 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002245 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002246 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 name_len++; /* trailing null */
2248 name_len *= 2;
2249 } else { /* BB improve the check for buffer overruns BB */
2250 name_len = strnlen(fileName, PATH_MAX);
2251 name_len++; /* trailing null */
2252 strncpy(pSMB->FileName, fileName, name_len);
2253 }
2254 params = 6 + name_len;
2255 pSMB->MaxParameterCount = cpu_to_le16(2);
2256 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2257 pSMB->MaxSetupCount = 0;
2258 pSMB->Reserved = 0;
2259 pSMB->Flags = 0;
2260 pSMB->Timeout = 0;
2261 pSMB->Reserved2 = 0;
2262 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2263 InformationLevel) - 4;
2264 offset = param_offset + params;
2265 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2266 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2267
2268 /* convert to on the wire format for POSIX ACL */
2269 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2270
2271 if(data_count == 0) {
2272 rc = -EOPNOTSUPP;
2273 goto setACLerrorExit;
2274 }
2275 pSMB->DataOffset = cpu_to_le16(offset);
2276 pSMB->SetupCount = 1;
2277 pSMB->Reserved3 = 0;
2278 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2279 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2280 byte_count = 3 /* pad */ + params + data_count;
2281 pSMB->DataCount = cpu_to_le16(data_count);
2282 pSMB->TotalDataCount = pSMB->DataCount;
2283 pSMB->ParameterCount = cpu_to_le16(params);
2284 pSMB->TotalParameterCount = pSMB->ParameterCount;
2285 pSMB->Reserved4 = 0;
2286 pSMB->hdr.smb_buf_length += byte_count;
2287 pSMB->ByteCount = cpu_to_le16(byte_count);
2288 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2289 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2290 if (rc) {
2291 cFYI(1, ("Set POSIX ACL returned %d", rc));
2292 }
2293
2294setACLerrorExit:
2295 cifs_buf_release(pSMB);
2296 if (rc == -EAGAIN)
2297 goto setAclRetry;
2298 return rc;
2299}
2300
Steve Frenchf654bac2005-04-28 22:41:04 -07002301/* BB fix tabs in this function FIXME BB */
2302int
2303CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2304 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2305{
2306 int rc = 0;
2307 struct smb_t2_qfi_req *pSMB = NULL;
2308 struct smb_t2_qfi_rsp *pSMBr = NULL;
2309 int bytes_returned;
2310 __u16 params, byte_count;
2311
2312 cFYI(1,("In GetExtAttr"));
2313 if(tcon == NULL)
2314 return -ENODEV;
2315
2316GetExtAttrRetry:
2317 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2318 (void **) &pSMBr);
2319 if (rc)
2320 return rc;
2321
Steve Frenchc67593a2005-04-28 22:41:04 -07002322 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002323 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002324 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002325 /* BB find exact max data count below from sess structure BB */
2326 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2327 pSMB->t2.MaxSetupCount = 0;
2328 pSMB->t2.Reserved = 0;
2329 pSMB->t2.Flags = 0;
2330 pSMB->t2.Timeout = 0;
2331 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002332 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2333 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002334 pSMB->t2.DataCount = 0;
2335 pSMB->t2.DataOffset = 0;
2336 pSMB->t2.SetupCount = 1;
2337 pSMB->t2.Reserved3 = 0;
2338 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002339 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002340 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2341 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2342 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002343 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002344 pSMB->Fid = netfid;
2345 pSMB->hdr.smb_buf_length += byte_count;
2346 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2347
2348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2350 if (rc) {
2351 cFYI(1, ("error %d in GetExtAttr", rc));
2352 } else {
2353 /* decode response */
2354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2355 if (rc || (pSMBr->ByteCount < 2))
2356 /* BB also check enough total bytes returned */
2357 /* If rc should we check for EOPNOSUPP and
2358 disable the srvino flag? or in caller? */
2359 rc = -EIO; /* bad smb */
2360 else {
2361 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2362 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2363 struct file_chattr_info * pfinfo;
2364 /* BB Do we need a cast or hash here ? */
2365 if(count != 16) {
2366 cFYI(1, ("Illegal size ret in GetExtAttr"));
2367 rc = -EIO;
2368 goto GetExtAttrOut;
2369 }
2370 pfinfo = (struct file_chattr_info *)
2371 (data_offset + (char *) &pSMBr->hdr.Protocol);
2372 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2373 *pMask = le64_to_cpu(pfinfo->mask);
2374 }
2375 }
2376GetExtAttrOut:
2377 cifs_buf_release(pSMB);
2378 if (rc == -EAGAIN)
2379 goto GetExtAttrRetry;
2380 return rc;
2381}
2382
2383
2384#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
Steve French6b8edfe2005-08-23 20:26:03 -07002386/* Legacy Query Path Information call for lookup to old servers such
2387 as Win9x/WinME */
2388int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2389 const unsigned char *searchName,
2390 FILE_ALL_INFO * pFinfo,
2391 const struct nls_table *nls_codepage, int remap)
2392{
2393 QUERY_INFORMATION_REQ * pSMB;
2394 QUERY_INFORMATION_RSP * pSMBr;
2395 int rc = 0;
2396 int bytes_returned;
2397 int name_len;
2398
2399 cFYI(1, ("In SMBQPath path %s", searchName));
2400QInfRetry:
2401 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2402 (void **) &pSMBr);
2403 if (rc)
2404 return rc;
2405
2406 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2407 name_len =
2408 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2409 PATH_MAX, nls_codepage, remap);
2410 name_len++; /* trailing null */
2411 name_len *= 2;
2412 } else {
2413 name_len = strnlen(searchName, PATH_MAX);
2414 name_len++; /* trailing null */
2415 strncpy(pSMB->FileName, searchName, name_len);
2416 }
2417 pSMB->BufferFormat = 0x04;
2418 name_len++; /* account for buffer type byte */
2419 pSMB->hdr.smb_buf_length += (__u16) name_len;
2420 pSMB->ByteCount = cpu_to_le16(name_len);
2421
2422 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2423 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2424 if (rc) {
2425 cFYI(1, ("Send error in QueryInfo = %d", rc));
2426 } else if (pFinfo) { /* decode response */
2427 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2428 pFinfo->AllocationSize = (__le64) pSMBr->size;
2429 pFinfo->EndOfFile = (__le64) pSMBr->size;
2430 pFinfo->Attributes = (__le32) pSMBr->attr;
2431 } else
2432 rc = -EIO; /* bad buffer passed in */
2433
2434 cifs_buf_release(pSMB);
2435
2436 if (rc == -EAGAIN)
2437 goto QInfRetry;
2438
2439 return rc;
2440}
2441
2442
2443
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445int
2446CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2447 const unsigned char *searchName,
2448 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002449 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450{
2451/* level 263 SMB_QUERY_FILE_ALL_INFO */
2452 TRANSACTION2_QPI_REQ *pSMB = NULL;
2453 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2454 int rc = 0;
2455 int bytes_returned;
2456 int name_len;
2457 __u16 params, byte_count;
2458
2459/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2460QPathInfoRetry:
2461 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2462 (void **) &pSMBr);
2463 if (rc)
2464 return rc;
2465
2466 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2467 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002468 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002469 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 name_len++; /* trailing null */
2471 name_len *= 2;
2472 } else { /* BB improve the check for buffer overruns BB */
2473 name_len = strnlen(searchName, PATH_MAX);
2474 name_len++; /* trailing null */
2475 strncpy(pSMB->FileName, searchName, name_len);
2476 }
2477
2478 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2479 pSMB->TotalDataCount = 0;
2480 pSMB->MaxParameterCount = cpu_to_le16(2);
2481 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2482 pSMB->MaxSetupCount = 0;
2483 pSMB->Reserved = 0;
2484 pSMB->Flags = 0;
2485 pSMB->Timeout = 0;
2486 pSMB->Reserved2 = 0;
2487 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2488 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2489 pSMB->DataCount = 0;
2490 pSMB->DataOffset = 0;
2491 pSMB->SetupCount = 1;
2492 pSMB->Reserved3 = 0;
2493 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2494 byte_count = params + 1 /* pad */ ;
2495 pSMB->TotalParameterCount = cpu_to_le16(params);
2496 pSMB->ParameterCount = pSMB->TotalParameterCount;
2497 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2498 pSMB->Reserved4 = 0;
2499 pSMB->hdr.smb_buf_length += byte_count;
2500 pSMB->ByteCount = cpu_to_le16(byte_count);
2501
2502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2504 if (rc) {
2505 cFYI(1, ("Send error in QPathInfo = %d", rc));
2506 } else { /* decode response */
2507 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2508
2509 if (rc || (pSMBr->ByteCount < 40))
2510 rc = -EIO; /* bad smb */
2511 else if (pFindData){
2512 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2513 memcpy((char *) pFindData,
2514 (char *) &pSMBr->hdr.Protocol +
2515 data_offset, sizeof (FILE_ALL_INFO));
2516 } else
2517 rc = -ENOMEM;
2518 }
2519 cifs_buf_release(pSMB);
2520 if (rc == -EAGAIN)
2521 goto QPathInfoRetry;
2522
2523 return rc;
2524}
2525
2526int
2527CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2528 const unsigned char *searchName,
2529 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002530 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531{
2532/* SMB_QUERY_FILE_UNIX_BASIC */
2533 TRANSACTION2_QPI_REQ *pSMB = NULL;
2534 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2535 int rc = 0;
2536 int bytes_returned = 0;
2537 int name_len;
2538 __u16 params, byte_count;
2539
2540 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2541UnixQPathInfoRetry:
2542 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2543 (void **) &pSMBr);
2544 if (rc)
2545 return rc;
2546
2547 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2548 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002549 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002550 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 name_len++; /* trailing null */
2552 name_len *= 2;
2553 } else { /* BB improve the check for buffer overruns BB */
2554 name_len = strnlen(searchName, PATH_MAX);
2555 name_len++; /* trailing null */
2556 strncpy(pSMB->FileName, searchName, name_len);
2557 }
2558
2559 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2560 pSMB->TotalDataCount = 0;
2561 pSMB->MaxParameterCount = cpu_to_le16(2);
2562 /* BB find exact max SMB PDU from sess structure BB */
2563 pSMB->MaxDataCount = cpu_to_le16(4000);
2564 pSMB->MaxSetupCount = 0;
2565 pSMB->Reserved = 0;
2566 pSMB->Flags = 0;
2567 pSMB->Timeout = 0;
2568 pSMB->Reserved2 = 0;
2569 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2570 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2571 pSMB->DataCount = 0;
2572 pSMB->DataOffset = 0;
2573 pSMB->SetupCount = 1;
2574 pSMB->Reserved3 = 0;
2575 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2576 byte_count = params + 1 /* pad */ ;
2577 pSMB->TotalParameterCount = cpu_to_le16(params);
2578 pSMB->ParameterCount = pSMB->TotalParameterCount;
2579 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2580 pSMB->Reserved4 = 0;
2581 pSMB->hdr.smb_buf_length += byte_count;
2582 pSMB->ByteCount = cpu_to_le16(byte_count);
2583
2584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2586 if (rc) {
2587 cFYI(1, ("Send error in QPathInfo = %d", rc));
2588 } else { /* decode response */
2589 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2590
2591 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2592 rc = -EIO; /* bad smb */
2593 } else {
2594 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2595 memcpy((char *) pFindData,
2596 (char *) &pSMBr->hdr.Protocol +
2597 data_offset,
2598 sizeof (FILE_UNIX_BASIC_INFO));
2599 }
2600 }
2601 cifs_buf_release(pSMB);
2602 if (rc == -EAGAIN)
2603 goto UnixQPathInfoRetry;
2604
2605 return rc;
2606}
2607
2608#if 0 /* function unused at present */
2609int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2610 const char *searchName, FILE_ALL_INFO * findData,
2611 const struct nls_table *nls_codepage)
2612{
2613/* level 257 SMB_ */
2614 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2615 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2616 int rc = 0;
2617 int bytes_returned;
2618 int name_len;
2619 __u16 params, byte_count;
2620
2621 cFYI(1, ("In FindUnique"));
2622findUniqueRetry:
2623 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2624 (void **) &pSMBr);
2625 if (rc)
2626 return rc;
2627
2628 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2629 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002630 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 /* find define for this maxpathcomponent */
2632 , nls_codepage);
2633 name_len++; /* trailing null */
2634 name_len *= 2;
2635 } else { /* BB improve the check for buffer overruns BB */
2636 name_len = strnlen(searchName, PATH_MAX);
2637 name_len++; /* trailing null */
2638 strncpy(pSMB->FileName, searchName, name_len);
2639 }
2640
2641 params = 12 + name_len /* includes null */ ;
2642 pSMB->TotalDataCount = 0; /* no EAs */
2643 pSMB->MaxParameterCount = cpu_to_le16(2);
2644 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2645 pSMB->MaxSetupCount = 0;
2646 pSMB->Reserved = 0;
2647 pSMB->Flags = 0;
2648 pSMB->Timeout = 0;
2649 pSMB->Reserved2 = 0;
2650 pSMB->ParameterOffset = cpu_to_le16(
2651 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2652 pSMB->DataCount = 0;
2653 pSMB->DataOffset = 0;
2654 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2655 pSMB->Reserved3 = 0;
2656 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2657 byte_count = params + 1 /* pad */ ;
2658 pSMB->TotalParameterCount = cpu_to_le16(params);
2659 pSMB->ParameterCount = pSMB->TotalParameterCount;
2660 pSMB->SearchAttributes =
2661 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2662 ATTR_DIRECTORY);
2663 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2664 pSMB->SearchFlags = cpu_to_le16(1);
2665 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2666 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2667 pSMB->hdr.smb_buf_length += byte_count;
2668 pSMB->ByteCount = cpu_to_le16(byte_count);
2669
2670 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2671 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2672
2673 if (rc) {
2674 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2675 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07002676 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 /* BB fill in */
2678 }
2679
2680 cifs_buf_release(pSMB);
2681 if (rc == -EAGAIN)
2682 goto findUniqueRetry;
2683
2684 return rc;
2685}
2686#endif /* end unused (temporarily) function */
2687
2688/* xid, tcon, searchName and codepage are input parms, rest are returned */
2689int
2690CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2691 const char *searchName,
2692 const struct nls_table *nls_codepage,
2693 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002694 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695{
2696/* level 257 SMB_ */
2697 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2698 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2699 T2_FFIRST_RSP_PARMS * parms;
2700 int rc = 0;
2701 int bytes_returned = 0;
2702 int name_len;
2703 __u16 params, byte_count;
2704
Steve French737b7582005-04-28 22:41:06 -07002705 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
2707findFirstRetry:
2708 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2709 (void **) &pSMBr);
2710 if (rc)
2711 return rc;
2712
2713 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2714 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002715 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002716 PATH_MAX, nls_codepage, remap);
2717 /* We can not add the asterik earlier in case
2718 it got remapped to 0xF03A as if it were part of the
2719 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002721 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002722 pSMB->FileName[name_len+1] = 0;
2723 pSMB->FileName[name_len+2] = '*';
2724 pSMB->FileName[name_len+3] = 0;
2725 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2727 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002728 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 } else { /* BB add check for overrun of SMB buf BB */
2730 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731/* BB fix here and in unicode clause above ie
2732 if(name_len > buffersize-header)
2733 free buffer exit; BB */
2734 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002735 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002736 pSMB->FileName[name_len+1] = '*';
2737 pSMB->FileName[name_len+2] = 0;
2738 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 }
2740
2741 params = 12 + name_len /* includes null */ ;
2742 pSMB->TotalDataCount = 0; /* no EAs */
2743 pSMB->MaxParameterCount = cpu_to_le16(10);
2744 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2745 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2746 pSMB->MaxSetupCount = 0;
2747 pSMB->Reserved = 0;
2748 pSMB->Flags = 0;
2749 pSMB->Timeout = 0;
2750 pSMB->Reserved2 = 0;
2751 byte_count = params + 1 /* pad */ ;
2752 pSMB->TotalParameterCount = cpu_to_le16(params);
2753 pSMB->ParameterCount = pSMB->TotalParameterCount;
2754 pSMB->ParameterOffset = cpu_to_le16(
2755 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2756 pSMB->DataCount = 0;
2757 pSMB->DataOffset = 0;
2758 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2759 pSMB->Reserved3 = 0;
2760 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2761 pSMB->SearchAttributes =
2762 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2763 ATTR_DIRECTORY);
2764 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2765 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2766 CIFS_SEARCH_RETURN_RESUME);
2767 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2768
2769 /* BB what should we set StorageType to? Does it matter? BB */
2770 pSMB->SearchStorageType = 0;
2771 pSMB->hdr.smb_buf_length += byte_count;
2772 pSMB->ByteCount = cpu_to_le16(byte_count);
2773
2774 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2775 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002776 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777
Steve French1982c342005-08-17 12:38:22 -07002778 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 /* BB Add code to handle unsupported level rc */
2780 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002781
2782 if (pSMB)
2783 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
2785 /* BB eventually could optimize out free and realloc of buf */
2786 /* for this case */
2787 if (rc == -EAGAIN)
2788 goto findFirstRetry;
2789 } else { /* decode response */
2790 /* BB remember to free buffer if error BB */
2791 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2792 if(rc == 0) {
2793 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2794 psrch_inf->unicode = TRUE;
2795 else
2796 psrch_inf->unicode = FALSE;
2797
2798 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2799 psrch_inf->srch_entries_start =
2800 (char *) &pSMBr->hdr.Protocol +
2801 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2803 le16_to_cpu(pSMBr->t2.ParameterOffset));
2804
2805 if(parms->EndofSearch)
2806 psrch_inf->endOfSearch = TRUE;
2807 else
2808 psrch_inf->endOfSearch = FALSE;
2809
2810 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2811 psrch_inf->index_of_last_entry =
2812 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 *pnetfid = parms->SearchHandle;
2814 } else {
2815 cifs_buf_release(pSMB);
2816 }
2817 }
2818
2819 return rc;
2820}
2821
2822int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2823 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2824{
2825 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2826 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2827 T2_FNEXT_RSP_PARMS * parms;
2828 char *response_data;
2829 int rc = 0;
2830 int bytes_returned, name_len;
2831 __u16 params, byte_count;
2832
2833 cFYI(1, ("In FindNext"));
2834
2835 if(psrch_inf->endOfSearch == TRUE)
2836 return -ENOENT;
2837
2838 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2839 (void **) &pSMBr);
2840 if (rc)
2841 return rc;
2842
2843 params = 14; /* includes 2 bytes of null string, converted to LE below */
2844 byte_count = 0;
2845 pSMB->TotalDataCount = 0; /* no EAs */
2846 pSMB->MaxParameterCount = cpu_to_le16(8);
2847 pSMB->MaxDataCount =
2848 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2849 pSMB->MaxSetupCount = 0;
2850 pSMB->Reserved = 0;
2851 pSMB->Flags = 0;
2852 pSMB->Timeout = 0;
2853 pSMB->Reserved2 = 0;
2854 pSMB->ParameterOffset = cpu_to_le16(
2855 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2856 pSMB->DataCount = 0;
2857 pSMB->DataOffset = 0;
2858 pSMB->SetupCount = 1;
2859 pSMB->Reserved3 = 0;
2860 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2861 pSMB->SearchHandle = searchHandle; /* always kept as le */
2862 pSMB->SearchCount =
2863 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2864 /* test for Unix extensions */
2865/* if (tcon->ses->capabilities & CAP_UNIX) {
2866 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2867 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2868 } else {
2869 pSMB->InformationLevel =
2870 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2871 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2872 } */
2873 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2874 pSMB->ResumeKey = psrch_inf->resume_key;
2875 pSMB->SearchFlags =
2876 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2877
2878 name_len = psrch_inf->resume_name_len;
2879 params += name_len;
2880 if(name_len < PATH_MAX) {
2881 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2882 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002883 /* 14 byte parm len above enough for 2 byte null terminator */
2884 pSMB->ResumeFileName[name_len] = 0;
2885 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 } else {
2887 rc = -EINVAL;
2888 goto FNext2_err_exit;
2889 }
2890 byte_count = params + 1 /* pad */ ;
2891 pSMB->TotalParameterCount = cpu_to_le16(params);
2892 pSMB->ParameterCount = pSMB->TotalParameterCount;
2893 pSMB->hdr.smb_buf_length += byte_count;
2894 pSMB->ByteCount = cpu_to_le16(byte_count);
2895
2896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002898 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 if (rc) {
2900 if (rc == -EBADF) {
2901 psrch_inf->endOfSearch = TRUE;
2902 rc = 0; /* search probably was closed at end of search above */
2903 } else
2904 cFYI(1, ("FindNext returned = %d", rc));
2905 } else { /* decode response */
2906 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2907
2908 if(rc == 0) {
2909 /* BB fixme add lock for file (srch_info) struct here */
2910 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2911 psrch_inf->unicode = TRUE;
2912 else
2913 psrch_inf->unicode = FALSE;
2914 response_data = (char *) &pSMBr->hdr.Protocol +
2915 le16_to_cpu(pSMBr->t2.ParameterOffset);
2916 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2917 response_data = (char *)&pSMBr->hdr.Protocol +
2918 le16_to_cpu(pSMBr->t2.DataOffset);
2919 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2920 psrch_inf->srch_entries_start = response_data;
2921 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2922 if(parms->EndofSearch)
2923 psrch_inf->endOfSearch = TRUE;
2924 else
2925 psrch_inf->endOfSearch = FALSE;
2926
2927 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2928 psrch_inf->index_of_last_entry +=
2929 psrch_inf->entries_in_buffer;
2930/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2931
2932 /* BB fixme add unlock here */
2933 }
2934
2935 }
2936
2937 /* BB On error, should we leave previous search buf (and count and
2938 last entry fields) intact or free the previous one? */
2939
2940 /* Note: On -EAGAIN error only caller can retry on handle based calls
2941 since file handle passed in no longer valid */
2942FNext2_err_exit:
2943 if (rc != 0)
2944 cifs_buf_release(pSMB);
2945
2946 return rc;
2947}
2948
2949int
2950CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2951{
2952 int rc = 0;
2953 FINDCLOSE_REQ *pSMB = NULL;
2954 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2955 int bytes_returned;
2956
2957 cFYI(1, ("In CIFSSMBFindClose"));
2958 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2959
2960 /* no sense returning error if session restarted
2961 as file handle has been closed */
2962 if(rc == -EAGAIN)
2963 return 0;
2964 if (rc)
2965 return rc;
2966
2967 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2968 pSMB->FileID = searchHandle;
2969 pSMB->ByteCount = 0;
2970 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2971 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2972 if (rc) {
2973 cERROR(1, ("Send error in FindClose = %d", rc));
2974 }
Steve Frencha4544342005-08-24 13:59:35 -07002975 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 cifs_small_buf_release(pSMB);
2977
2978 /* Since session is dead, search handle closed on server already */
2979 if (rc == -EAGAIN)
2980 rc = 0;
2981
2982 return rc;
2983}
2984
2985#ifdef CONFIG_CIFS_EXPERIMENTAL
2986int
2987CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2988 const unsigned char *searchName,
2989 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002990 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991{
2992 int rc = 0;
2993 TRANSACTION2_QPI_REQ *pSMB = NULL;
2994 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2995 int name_len, bytes_returned;
2996 __u16 params, byte_count;
2997
2998 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2999 if(tcon == NULL)
3000 return -ENODEV;
3001
3002GetInodeNumberRetry:
3003 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3004 (void **) &pSMBr);
3005 if (rc)
3006 return rc;
3007
3008
3009 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3010 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003011 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003012 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 name_len++; /* trailing null */
3014 name_len *= 2;
3015 } else { /* BB improve the check for buffer overruns BB */
3016 name_len = strnlen(searchName, PATH_MAX);
3017 name_len++; /* trailing null */
3018 strncpy(pSMB->FileName, searchName, name_len);
3019 }
3020
3021 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3022 pSMB->TotalDataCount = 0;
3023 pSMB->MaxParameterCount = cpu_to_le16(2);
3024 /* BB find exact max data count below from sess structure BB */
3025 pSMB->MaxDataCount = cpu_to_le16(4000);
3026 pSMB->MaxSetupCount = 0;
3027 pSMB->Reserved = 0;
3028 pSMB->Flags = 0;
3029 pSMB->Timeout = 0;
3030 pSMB->Reserved2 = 0;
3031 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3032 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3033 pSMB->DataCount = 0;
3034 pSMB->DataOffset = 0;
3035 pSMB->SetupCount = 1;
3036 pSMB->Reserved3 = 0;
3037 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3038 byte_count = params + 1 /* pad */ ;
3039 pSMB->TotalParameterCount = cpu_to_le16(params);
3040 pSMB->ParameterCount = pSMB->TotalParameterCount;
3041 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3042 pSMB->Reserved4 = 0;
3043 pSMB->hdr.smb_buf_length += byte_count;
3044 pSMB->ByteCount = cpu_to_le16(byte_count);
3045
3046 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3047 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3048 if (rc) {
3049 cFYI(1, ("error %d in QueryInternalInfo", rc));
3050 } else {
3051 /* decode response */
3052 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3053 if (rc || (pSMBr->ByteCount < 2))
3054 /* BB also check enough total bytes returned */
3055 /* If rc should we check for EOPNOSUPP and
3056 disable the srvino flag? or in caller? */
3057 rc = -EIO; /* bad smb */
3058 else {
3059 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3060 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3061 struct file_internal_info * pfinfo;
3062 /* BB Do we need a cast or hash here ? */
3063 if(count < 8) {
3064 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3065 rc = -EIO;
3066 goto GetInodeNumOut;
3067 }
3068 pfinfo = (struct file_internal_info *)
3069 (data_offset + (char *) &pSMBr->hdr.Protocol);
3070 *inode_number = pfinfo->UniqueId;
3071 }
3072 }
3073GetInodeNumOut:
3074 cifs_buf_release(pSMB);
3075 if (rc == -EAGAIN)
3076 goto GetInodeNumberRetry;
3077 return rc;
3078}
3079#endif /* CIFS_EXPERIMENTAL */
3080
3081int
3082CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3083 const unsigned char *searchName,
3084 unsigned char **targetUNCs,
3085 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003086 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087{
3088/* TRANS2_GET_DFS_REFERRAL */
3089 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3090 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3091 struct dfs_referral_level_3 * referrals = NULL;
3092 int rc = 0;
3093 int bytes_returned;
3094 int name_len;
3095 unsigned int i;
3096 char * temp;
3097 __u16 params, byte_count;
3098 *number_of_UNC_in_array = 0;
3099 *targetUNCs = NULL;
3100
3101 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3102 if (ses == NULL)
3103 return -ENODEV;
3104getDFSRetry:
3105 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3106 (void **) &pSMBr);
3107 if (rc)
3108 return rc;
Steve French1982c342005-08-17 12:38:22 -07003109
3110 /* server pointer checked in called function,
3111 but should never be null here anyway */
3112 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 pSMB->hdr.Tid = ses->ipc_tid;
3114 pSMB->hdr.Uid = ses->Suid;
3115 if (ses->capabilities & CAP_STATUS32) {
3116 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3117 }
3118 if (ses->capabilities & CAP_DFS) {
3119 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3120 }
3121
3122 if (ses->capabilities & CAP_UNICODE) {
3123 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3124 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003125 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003126 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 name_len++; /* trailing null */
3128 name_len *= 2;
3129 } else { /* BB improve the check for buffer overruns BB */
3130 name_len = strnlen(searchName, PATH_MAX);
3131 name_len++; /* trailing null */
3132 strncpy(pSMB->RequestFileName, searchName, name_len);
3133 }
3134
3135 params = 2 /* level */ + name_len /*includes null */ ;
3136 pSMB->TotalDataCount = 0;
3137 pSMB->DataCount = 0;
3138 pSMB->DataOffset = 0;
3139 pSMB->MaxParameterCount = 0;
3140 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3141 pSMB->MaxSetupCount = 0;
3142 pSMB->Reserved = 0;
3143 pSMB->Flags = 0;
3144 pSMB->Timeout = 0;
3145 pSMB->Reserved2 = 0;
3146 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3147 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3148 pSMB->SetupCount = 1;
3149 pSMB->Reserved3 = 0;
3150 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3151 byte_count = params + 3 /* pad */ ;
3152 pSMB->ParameterCount = cpu_to_le16(params);
3153 pSMB->TotalParameterCount = pSMB->ParameterCount;
3154 pSMB->MaxReferralLevel = cpu_to_le16(3);
3155 pSMB->hdr.smb_buf_length += byte_count;
3156 pSMB->ByteCount = cpu_to_le16(byte_count);
3157
3158 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3159 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3160 if (rc) {
3161 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3162 } else { /* decode response */
3163/* BB Add logic to parse referrals here */
3164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3165
3166 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3167 rc = -EIO; /* bad smb */
3168 else {
3169 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3170 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3171
3172 cFYI(1,
3173 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3174 pSMBr->ByteCount, data_offset));
3175 referrals =
3176 (struct dfs_referral_level_3 *)
3177 (8 /* sizeof start of data block */ +
3178 data_offset +
3179 (char *) &pSMBr->hdr.Protocol);
3180 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",
3181 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)));
3182 /* BB This field is actually two bytes in from start of
3183 data block so we could do safety check that DataBlock
3184 begins at address of pSMBr->NumberOfReferrals */
3185 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3186
3187 /* BB Fix below so can return more than one referral */
3188 if(*number_of_UNC_in_array > 1)
3189 *number_of_UNC_in_array = 1;
3190
3191 /* get the length of the strings describing refs */
3192 name_len = 0;
3193 for(i=0;i<*number_of_UNC_in_array;i++) {
3194 /* make sure that DfsPathOffset not past end */
3195 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3196 if (offset > data_count) {
3197 /* if invalid referral, stop here and do
3198 not try to copy any more */
3199 *number_of_UNC_in_array = i;
3200 break;
3201 }
3202 temp = ((char *)referrals) + offset;
3203
3204 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3205 name_len += UniStrnlen((wchar_t *)temp,data_count);
3206 } else {
3207 name_len += strnlen(temp,data_count);
3208 }
3209 referrals++;
3210 /* BB add check that referral pointer does not fall off end PDU */
3211
3212 }
3213 /* BB add check for name_len bigger than bcc */
3214 *targetUNCs =
3215 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3216 if(*targetUNCs == NULL) {
3217 rc = -ENOMEM;
3218 goto GetDFSRefExit;
3219 }
3220 /* copy the ref strings */
3221 referrals =
3222 (struct dfs_referral_level_3 *)
3223 (8 /* sizeof data hdr */ +
3224 data_offset +
3225 (char *) &pSMBr->hdr.Protocol);
3226
3227 for(i=0;i<*number_of_UNC_in_array;i++) {
3228 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3229 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3230 cifs_strfromUCS_le(*targetUNCs,
3231 (wchar_t *) temp, name_len, nls_codepage);
3232 } else {
3233 strncpy(*targetUNCs,temp,name_len);
3234 }
3235 /* BB update target_uncs pointers */
3236 referrals++;
3237 }
3238 temp = *targetUNCs;
3239 temp[name_len] = 0;
3240 }
3241
3242 }
3243GetDFSRefExit:
3244 if (pSMB)
3245 cifs_buf_release(pSMB);
3246
3247 if (rc == -EAGAIN)
3248 goto getDFSRetry;
3249
3250 return rc;
3251}
3252
3253int
Steve French737b7582005-04-28 22:41:06 -07003254CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255{
3256/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3257 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3258 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3259 FILE_SYSTEM_INFO *response_data;
3260 int rc = 0;
3261 int bytes_returned = 0;
3262 __u16 params, byte_count;
3263
3264 cFYI(1, ("In QFSInfo"));
3265QFSInfoRetry:
3266 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3267 (void **) &pSMBr);
3268 if (rc)
3269 return rc;
3270
3271 params = 2; /* level */
3272 pSMB->TotalDataCount = 0;
3273 pSMB->MaxParameterCount = cpu_to_le16(2);
3274 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3275 pSMB->MaxSetupCount = 0;
3276 pSMB->Reserved = 0;
3277 pSMB->Flags = 0;
3278 pSMB->Timeout = 0;
3279 pSMB->Reserved2 = 0;
3280 byte_count = params + 1 /* pad */ ;
3281 pSMB->TotalParameterCount = cpu_to_le16(params);
3282 pSMB->ParameterCount = pSMB->TotalParameterCount;
3283 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3284 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3285 pSMB->DataCount = 0;
3286 pSMB->DataOffset = 0;
3287 pSMB->SetupCount = 1;
3288 pSMB->Reserved3 = 0;
3289 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3290 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3291 pSMB->hdr.smb_buf_length += byte_count;
3292 pSMB->ByteCount = cpu_to_le16(byte_count);
3293
3294 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3295 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3296 if (rc) {
3297 cERROR(1, ("Send error in QFSInfo = %d", rc));
3298 } else { /* decode response */
3299 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3300
3301 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3302 rc = -EIO; /* bad smb */
3303 else {
3304 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3305 cFYI(1,
3306 ("Decoding qfsinfo response. BCC: %d Offset %d",
3307 pSMBr->ByteCount, data_offset));
3308
3309 response_data =
3310 (FILE_SYSTEM_INFO
3311 *) (((char *) &pSMBr->hdr.Protocol) +
3312 data_offset);
3313 FSData->f_bsize =
3314 le32_to_cpu(response_data->BytesPerSector) *
3315 le32_to_cpu(response_data->
3316 SectorsPerAllocationUnit);
3317 FSData->f_blocks =
3318 le64_to_cpu(response_data->TotalAllocationUnits);
3319 FSData->f_bfree = FSData->f_bavail =
3320 le64_to_cpu(response_data->FreeAllocationUnits);
3321 cFYI(1,
3322 ("Blocks: %lld Free: %lld Block size %ld",
3323 (unsigned long long)FSData->f_blocks,
3324 (unsigned long long)FSData->f_bfree,
3325 FSData->f_bsize));
3326 }
3327 }
3328 cifs_buf_release(pSMB);
3329
3330 if (rc == -EAGAIN)
3331 goto QFSInfoRetry;
3332
3333 return rc;
3334}
3335
3336int
Steve French737b7582005-04-28 22:41:06 -07003337CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338{
3339/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3340 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3341 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3342 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3343 int rc = 0;
3344 int bytes_returned = 0;
3345 __u16 params, byte_count;
3346
3347 cFYI(1, ("In QFSAttributeInfo"));
3348QFSAttributeRetry:
3349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3350 (void **) &pSMBr);
3351 if (rc)
3352 return rc;
3353
3354 params = 2; /* level */
3355 pSMB->TotalDataCount = 0;
3356 pSMB->MaxParameterCount = cpu_to_le16(2);
3357 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3358 pSMB->MaxSetupCount = 0;
3359 pSMB->Reserved = 0;
3360 pSMB->Flags = 0;
3361 pSMB->Timeout = 0;
3362 pSMB->Reserved2 = 0;
3363 byte_count = params + 1 /* pad */ ;
3364 pSMB->TotalParameterCount = cpu_to_le16(params);
3365 pSMB->ParameterCount = pSMB->TotalParameterCount;
3366 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3367 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3368 pSMB->DataCount = 0;
3369 pSMB->DataOffset = 0;
3370 pSMB->SetupCount = 1;
3371 pSMB->Reserved3 = 0;
3372 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3373 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3374 pSMB->hdr.smb_buf_length += byte_count;
3375 pSMB->ByteCount = cpu_to_le16(byte_count);
3376
3377 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3378 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3379 if (rc) {
3380 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3381 } else { /* decode response */
3382 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3383
3384 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3385 rc = -EIO; /* bad smb */
3386 } else {
3387 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3388 response_data =
3389 (FILE_SYSTEM_ATTRIBUTE_INFO
3390 *) (((char *) &pSMBr->hdr.Protocol) +
3391 data_offset);
3392 memcpy(&tcon->fsAttrInfo, response_data,
3393 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3394 }
3395 }
3396 cifs_buf_release(pSMB);
3397
3398 if (rc == -EAGAIN)
3399 goto QFSAttributeRetry;
3400
3401 return rc;
3402}
3403
3404int
Steve French737b7582005-04-28 22:41:06 -07003405CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406{
3407/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3408 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3409 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3410 FILE_SYSTEM_DEVICE_INFO *response_data;
3411 int rc = 0;
3412 int bytes_returned = 0;
3413 __u16 params, byte_count;
3414
3415 cFYI(1, ("In QFSDeviceInfo"));
3416QFSDeviceRetry:
3417 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3418 (void **) &pSMBr);
3419 if (rc)
3420 return rc;
3421
3422 params = 2; /* level */
3423 pSMB->TotalDataCount = 0;
3424 pSMB->MaxParameterCount = cpu_to_le16(2);
3425 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3426 pSMB->MaxSetupCount = 0;
3427 pSMB->Reserved = 0;
3428 pSMB->Flags = 0;
3429 pSMB->Timeout = 0;
3430 pSMB->Reserved2 = 0;
3431 byte_count = params + 1 /* pad */ ;
3432 pSMB->TotalParameterCount = cpu_to_le16(params);
3433 pSMB->ParameterCount = pSMB->TotalParameterCount;
3434 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3435 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3436
3437 pSMB->DataCount = 0;
3438 pSMB->DataOffset = 0;
3439 pSMB->SetupCount = 1;
3440 pSMB->Reserved3 = 0;
3441 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3442 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3443 pSMB->hdr.smb_buf_length += byte_count;
3444 pSMB->ByteCount = cpu_to_le16(byte_count);
3445
3446 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3447 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3448 if (rc) {
3449 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3450 } else { /* decode response */
3451 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3452
3453 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3454 rc = -EIO; /* bad smb */
3455 else {
3456 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3457 response_data =
Steve French737b7582005-04-28 22:41:06 -07003458 (FILE_SYSTEM_DEVICE_INFO *)
3459 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 data_offset);
3461 memcpy(&tcon->fsDevInfo, response_data,
3462 sizeof (FILE_SYSTEM_DEVICE_INFO));
3463 }
3464 }
3465 cifs_buf_release(pSMB);
3466
3467 if (rc == -EAGAIN)
3468 goto QFSDeviceRetry;
3469
3470 return rc;
3471}
3472
3473int
Steve French737b7582005-04-28 22:41:06 -07003474CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475{
3476/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3477 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3478 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3479 FILE_SYSTEM_UNIX_INFO *response_data;
3480 int rc = 0;
3481 int bytes_returned = 0;
3482 __u16 params, byte_count;
3483
3484 cFYI(1, ("In QFSUnixInfo"));
3485QFSUnixRetry:
3486 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3487 (void **) &pSMBr);
3488 if (rc)
3489 return rc;
3490
3491 params = 2; /* level */
3492 pSMB->TotalDataCount = 0;
3493 pSMB->DataCount = 0;
3494 pSMB->DataOffset = 0;
3495 pSMB->MaxParameterCount = cpu_to_le16(2);
3496 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3497 pSMB->MaxSetupCount = 0;
3498 pSMB->Reserved = 0;
3499 pSMB->Flags = 0;
3500 pSMB->Timeout = 0;
3501 pSMB->Reserved2 = 0;
3502 byte_count = params + 1 /* pad */ ;
3503 pSMB->ParameterCount = cpu_to_le16(params);
3504 pSMB->TotalParameterCount = pSMB->ParameterCount;
3505 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3506 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3507 pSMB->SetupCount = 1;
3508 pSMB->Reserved3 = 0;
3509 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3510 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3511 pSMB->hdr.smb_buf_length += byte_count;
3512 pSMB->ByteCount = cpu_to_le16(byte_count);
3513
3514 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3515 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3516 if (rc) {
3517 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3518 } else { /* decode response */
3519 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3520
3521 if (rc || (pSMBr->ByteCount < 13)) {
3522 rc = -EIO; /* bad smb */
3523 } else {
3524 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3525 response_data =
3526 (FILE_SYSTEM_UNIX_INFO
3527 *) (((char *) &pSMBr->hdr.Protocol) +
3528 data_offset);
3529 memcpy(&tcon->fsUnixInfo, response_data,
3530 sizeof (FILE_SYSTEM_UNIX_INFO));
3531 }
3532 }
3533 cifs_buf_release(pSMB);
3534
3535 if (rc == -EAGAIN)
3536 goto QFSUnixRetry;
3537
3538
3539 return rc;
3540}
3541
Jeremy Allisonac670552005-06-22 17:26:35 -07003542int
Steve French45abc6e2005-06-23 13:42:03 -05003543CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003544{
3545/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3546 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3547 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3548 int rc = 0;
3549 int bytes_returned = 0;
3550 __u16 params, param_offset, offset, byte_count;
3551
3552 cFYI(1, ("In SETFSUnixInfo"));
3553SETFSUnixRetry:
3554 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3555 (void **) &pSMBr);
3556 if (rc)
3557 return rc;
3558
3559 params = 4; /* 2 bytes zero followed by info level. */
3560 pSMB->MaxSetupCount = 0;
3561 pSMB->Reserved = 0;
3562 pSMB->Flags = 0;
3563 pSMB->Timeout = 0;
3564 pSMB->Reserved2 = 0;
3565 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3566 offset = param_offset + params;
3567
3568 pSMB->MaxParameterCount = cpu_to_le16(4);
3569 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3570 pSMB->SetupCount = 1;
3571 pSMB->Reserved3 = 0;
3572 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3573 byte_count = 1 /* pad */ + params + 12;
3574
3575 pSMB->DataCount = cpu_to_le16(12);
3576 pSMB->ParameterCount = cpu_to_le16(params);
3577 pSMB->TotalDataCount = pSMB->DataCount;
3578 pSMB->TotalParameterCount = pSMB->ParameterCount;
3579 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3580 pSMB->DataOffset = cpu_to_le16(offset);
3581
3582 /* Params. */
3583 pSMB->FileNum = 0;
3584 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3585
3586 /* Data. */
3587 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3588 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3589 pSMB->ClientUnixCap = cpu_to_le64(cap);
3590
3591 pSMB->hdr.smb_buf_length += byte_count;
3592 pSMB->ByteCount = cpu_to_le16(byte_count);
3593
3594 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3595 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3596 if (rc) {
3597 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3598 } else { /* decode response */
3599 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3600 if (rc) {
3601 rc = -EIO; /* bad smb */
3602 }
3603 }
3604 cifs_buf_release(pSMB);
3605
3606 if (rc == -EAGAIN)
3607 goto SETFSUnixRetry;
3608
3609 return rc;
3610}
3611
3612
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613
3614int
3615CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003616 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617{
3618/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3619 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3620 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3621 FILE_SYSTEM_POSIX_INFO *response_data;
3622 int rc = 0;
3623 int bytes_returned = 0;
3624 __u16 params, byte_count;
3625
3626 cFYI(1, ("In QFSPosixInfo"));
3627QFSPosixRetry:
3628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3629 (void **) &pSMBr);
3630 if (rc)
3631 return rc;
3632
3633 params = 2; /* level */
3634 pSMB->TotalDataCount = 0;
3635 pSMB->DataCount = 0;
3636 pSMB->DataOffset = 0;
3637 pSMB->MaxParameterCount = cpu_to_le16(2);
3638 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3639 pSMB->MaxSetupCount = 0;
3640 pSMB->Reserved = 0;
3641 pSMB->Flags = 0;
3642 pSMB->Timeout = 0;
3643 pSMB->Reserved2 = 0;
3644 byte_count = params + 1 /* pad */ ;
3645 pSMB->ParameterCount = cpu_to_le16(params);
3646 pSMB->TotalParameterCount = pSMB->ParameterCount;
3647 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3648 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3649 pSMB->SetupCount = 1;
3650 pSMB->Reserved3 = 0;
3651 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3652 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3653 pSMB->hdr.smb_buf_length += byte_count;
3654 pSMB->ByteCount = cpu_to_le16(byte_count);
3655
3656 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3657 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3658 if (rc) {
3659 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3660 } else { /* decode response */
3661 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3662
3663 if (rc || (pSMBr->ByteCount < 13)) {
3664 rc = -EIO; /* bad smb */
3665 } else {
3666 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3667 response_data =
3668 (FILE_SYSTEM_POSIX_INFO
3669 *) (((char *) &pSMBr->hdr.Protocol) +
3670 data_offset);
3671 FSData->f_bsize =
3672 le32_to_cpu(response_data->BlockSize);
3673 FSData->f_blocks =
3674 le64_to_cpu(response_data->TotalBlocks);
3675 FSData->f_bfree =
3676 le64_to_cpu(response_data->BlocksAvail);
3677 if(response_data->UserBlocksAvail == -1) {
3678 FSData->f_bavail = FSData->f_bfree;
3679 } else {
3680 FSData->f_bavail =
3681 le64_to_cpu(response_data->UserBlocksAvail);
3682 }
3683 if(response_data->TotalFileNodes != -1)
3684 FSData->f_files =
3685 le64_to_cpu(response_data->TotalFileNodes);
3686 if(response_data->FreeFileNodes != -1)
3687 FSData->f_ffree =
3688 le64_to_cpu(response_data->FreeFileNodes);
3689 }
3690 }
3691 cifs_buf_release(pSMB);
3692
3693 if (rc == -EAGAIN)
3694 goto QFSPosixRetry;
3695
3696 return rc;
3697}
3698
3699
3700/* We can not use write of zero bytes trick to
3701 set file size due to need for large file support. Also note that
3702 this SetPathInfo is preferred to SetFileInfo based method in next
3703 routine which is only needed to work around a sharing violation bug
3704 in Samba which this routine can run into */
3705
3706int
3707CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003708 __u64 size, int SetAllocation,
3709 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710{
3711 struct smb_com_transaction2_spi_req *pSMB = NULL;
3712 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3713 struct file_end_of_file_info *parm_data;
3714 int name_len;
3715 int rc = 0;
3716 int bytes_returned = 0;
3717 __u16 params, byte_count, data_count, param_offset, offset;
3718
3719 cFYI(1, ("In SetEOF"));
3720SetEOFRetry:
3721 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3722 (void **) &pSMBr);
3723 if (rc)
3724 return rc;
3725
3726 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3727 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003728 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003729 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 name_len++; /* trailing null */
3731 name_len *= 2;
3732 } else { /* BB improve the check for buffer overruns BB */
3733 name_len = strnlen(fileName, PATH_MAX);
3734 name_len++; /* trailing null */
3735 strncpy(pSMB->FileName, fileName, name_len);
3736 }
3737 params = 6 + name_len;
3738 data_count = sizeof (struct file_end_of_file_info);
3739 pSMB->MaxParameterCount = cpu_to_le16(2);
3740 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3741 pSMB->MaxSetupCount = 0;
3742 pSMB->Reserved = 0;
3743 pSMB->Flags = 0;
3744 pSMB->Timeout = 0;
3745 pSMB->Reserved2 = 0;
3746 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3747 InformationLevel) - 4;
3748 offset = param_offset + params;
3749 if(SetAllocation) {
3750 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3751 pSMB->InformationLevel =
3752 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3753 else
3754 pSMB->InformationLevel =
3755 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3756 } else /* Set File Size */ {
3757 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3758 pSMB->InformationLevel =
3759 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3760 else
3761 pSMB->InformationLevel =
3762 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3763 }
3764
3765 parm_data =
3766 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3767 offset);
3768 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3769 pSMB->DataOffset = cpu_to_le16(offset);
3770 pSMB->SetupCount = 1;
3771 pSMB->Reserved3 = 0;
3772 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3773 byte_count = 3 /* pad */ + params + data_count;
3774 pSMB->DataCount = cpu_to_le16(data_count);
3775 pSMB->TotalDataCount = pSMB->DataCount;
3776 pSMB->ParameterCount = cpu_to_le16(params);
3777 pSMB->TotalParameterCount = pSMB->ParameterCount;
3778 pSMB->Reserved4 = 0;
3779 pSMB->hdr.smb_buf_length += byte_count;
3780 parm_data->FileSize = cpu_to_le64(size);
3781 pSMB->ByteCount = cpu_to_le16(byte_count);
3782 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3783 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3784 if (rc) {
3785 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3786 }
3787
3788 cifs_buf_release(pSMB);
3789
3790 if (rc == -EAGAIN)
3791 goto SetEOFRetry;
3792
3793 return rc;
3794}
3795
3796int
3797CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3798 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3799{
3800 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3801 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3802 char *data_offset;
3803 struct file_end_of_file_info *parm_data;
3804 int rc = 0;
3805 int bytes_returned = 0;
3806 __u16 params, param_offset, offset, byte_count, count;
3807
3808 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3809 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003810 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3811
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 if (rc)
3813 return rc;
3814
Steve Frenchcd634992005-04-28 22:41:10 -07003815 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3816
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3818 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3819
3820 params = 6;
3821 pSMB->MaxSetupCount = 0;
3822 pSMB->Reserved = 0;
3823 pSMB->Flags = 0;
3824 pSMB->Timeout = 0;
3825 pSMB->Reserved2 = 0;
3826 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3827 offset = param_offset + params;
3828
3829 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3830
3831 count = sizeof(struct file_end_of_file_info);
3832 pSMB->MaxParameterCount = cpu_to_le16(2);
3833 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3834 pSMB->SetupCount = 1;
3835 pSMB->Reserved3 = 0;
3836 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3837 byte_count = 3 /* pad */ + params + count;
3838 pSMB->DataCount = cpu_to_le16(count);
3839 pSMB->ParameterCount = cpu_to_le16(params);
3840 pSMB->TotalDataCount = pSMB->DataCount;
3841 pSMB->TotalParameterCount = pSMB->ParameterCount;
3842 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3843 parm_data =
3844 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3845 offset);
3846 pSMB->DataOffset = cpu_to_le16(offset);
3847 parm_data->FileSize = cpu_to_le64(size);
3848 pSMB->Fid = fid;
3849 if(SetAllocation) {
3850 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3851 pSMB->InformationLevel =
3852 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3853 else
3854 pSMB->InformationLevel =
3855 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3856 } else /* Set File Size */ {
3857 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3858 pSMB->InformationLevel =
3859 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3860 else
3861 pSMB->InformationLevel =
3862 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3863 }
3864 pSMB->Reserved4 = 0;
3865 pSMB->hdr.smb_buf_length += byte_count;
3866 pSMB->ByteCount = cpu_to_le16(byte_count);
3867 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3868 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3869 if (rc) {
3870 cFYI(1,
3871 ("Send error in SetFileInfo (SetFileSize) = %d",
3872 rc));
3873 }
3874
3875 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003876 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877
3878 /* Note: On -EAGAIN error only caller can retry on handle based calls
3879 since file handle passed in no longer valid */
3880
3881 return rc;
3882}
3883
3884/* Some legacy servers such as NT4 require that the file times be set on
3885 an open handle, rather than by pathname - this is awkward due to
3886 potential access conflicts on the open, but it is unavoidable for these
3887 old servers since the only other choice is to go from 100 nanosecond DCE
3888 time and resort to the original setpathinfo level which takes the ancient
3889 DOS time format with 2 second granularity */
3890int
3891CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3892 __u16 fid)
3893{
3894 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3895 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3896 char *data_offset;
3897 int rc = 0;
3898 int bytes_returned = 0;
3899 __u16 params, param_offset, offset, byte_count, count;
3900
3901 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003902 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3903
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 if (rc)
3905 return rc;
3906
Steve Frenchcd634992005-04-28 22:41:10 -07003907 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3908
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 /* At this point there is no need to override the current pid
3910 with the pid of the opener, but that could change if we someday
3911 use an existing handle (rather than opening one on the fly) */
3912 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3913 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3914
3915 params = 6;
3916 pSMB->MaxSetupCount = 0;
3917 pSMB->Reserved = 0;
3918 pSMB->Flags = 0;
3919 pSMB->Timeout = 0;
3920 pSMB->Reserved2 = 0;
3921 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3922 offset = param_offset + params;
3923
3924 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3925
3926 count = sizeof (FILE_BASIC_INFO);
3927 pSMB->MaxParameterCount = cpu_to_le16(2);
3928 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3929 pSMB->SetupCount = 1;
3930 pSMB->Reserved3 = 0;
3931 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3932 byte_count = 3 /* pad */ + params + count;
3933 pSMB->DataCount = cpu_to_le16(count);
3934 pSMB->ParameterCount = cpu_to_le16(params);
3935 pSMB->TotalDataCount = pSMB->DataCount;
3936 pSMB->TotalParameterCount = pSMB->ParameterCount;
3937 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3938 pSMB->DataOffset = cpu_to_le16(offset);
3939 pSMB->Fid = fid;
3940 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3941 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3942 else
3943 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3944 pSMB->Reserved4 = 0;
3945 pSMB->hdr.smb_buf_length += byte_count;
3946 pSMB->ByteCount = cpu_to_le16(byte_count);
3947 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3950 if (rc) {
3951 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3952 }
3953
Steve Frenchcd634992005-04-28 22:41:10 -07003954 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955
3956 /* Note: On -EAGAIN error only caller can retry on handle based calls
3957 since file handle passed in no longer valid */
3958
3959 return rc;
3960}
3961
3962
3963int
3964CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3965 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07003966 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967{
3968 TRANSACTION2_SPI_REQ *pSMB = NULL;
3969 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3970 int name_len;
3971 int rc = 0;
3972 int bytes_returned = 0;
3973 char *data_offset;
3974 __u16 params, param_offset, offset, byte_count, count;
3975
3976 cFYI(1, ("In SetTimes"));
3977
3978SetTimesRetry:
3979 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3980 (void **) &pSMBr);
3981 if (rc)
3982 return rc;
3983
3984 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3985 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003986 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003987 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 name_len++; /* trailing null */
3989 name_len *= 2;
3990 } else { /* BB improve the check for buffer overruns BB */
3991 name_len = strnlen(fileName, PATH_MAX);
3992 name_len++; /* trailing null */
3993 strncpy(pSMB->FileName, fileName, name_len);
3994 }
3995
3996 params = 6 + name_len;
3997 count = sizeof (FILE_BASIC_INFO);
3998 pSMB->MaxParameterCount = cpu_to_le16(2);
3999 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4000 pSMB->MaxSetupCount = 0;
4001 pSMB->Reserved = 0;
4002 pSMB->Flags = 0;
4003 pSMB->Timeout = 0;
4004 pSMB->Reserved2 = 0;
4005 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4006 InformationLevel) - 4;
4007 offset = param_offset + params;
4008 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4009 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4010 pSMB->DataOffset = cpu_to_le16(offset);
4011 pSMB->SetupCount = 1;
4012 pSMB->Reserved3 = 0;
4013 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4014 byte_count = 3 /* pad */ + params + count;
4015
4016 pSMB->DataCount = cpu_to_le16(count);
4017 pSMB->ParameterCount = cpu_to_le16(params);
4018 pSMB->TotalDataCount = pSMB->DataCount;
4019 pSMB->TotalParameterCount = pSMB->ParameterCount;
4020 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4021 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4022 else
4023 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4024 pSMB->Reserved4 = 0;
4025 pSMB->hdr.smb_buf_length += byte_count;
4026 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4027 pSMB->ByteCount = cpu_to_le16(byte_count);
4028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4030 if (rc) {
4031 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4032 }
4033
4034 cifs_buf_release(pSMB);
4035
4036 if (rc == -EAGAIN)
4037 goto SetTimesRetry;
4038
4039 return rc;
4040}
4041
4042/* Can not be used to set time stamps yet (due to old DOS time format) */
4043/* Can be used to set attributes */
4044#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4045 handling it anyway and NT4 was what we thought it would be needed for
4046 Do not delete it until we prove whether needed for Win9x though */
4047int
4048CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4049 __u16 dos_attrs, const struct nls_table *nls_codepage)
4050{
4051 SETATTR_REQ *pSMB = NULL;
4052 SETATTR_RSP *pSMBr = NULL;
4053 int rc = 0;
4054 int bytes_returned;
4055 int name_len;
4056
4057 cFYI(1, ("In SetAttrLegacy"));
4058
4059SetAttrLgcyRetry:
4060 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4061 (void **) &pSMBr);
4062 if (rc)
4063 return rc;
4064
4065 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4066 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004067 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 PATH_MAX, nls_codepage);
4069 name_len++; /* trailing null */
4070 name_len *= 2;
4071 } else { /* BB improve the check for buffer overruns BB */
4072 name_len = strnlen(fileName, PATH_MAX);
4073 name_len++; /* trailing null */
4074 strncpy(pSMB->fileName, fileName, name_len);
4075 }
4076 pSMB->attr = cpu_to_le16(dos_attrs);
4077 pSMB->BufferFormat = 0x04;
4078 pSMB->hdr.smb_buf_length += name_len + 1;
4079 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4081 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4082 if (rc) {
4083 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4084 }
4085
4086 cifs_buf_release(pSMB);
4087
4088 if (rc == -EAGAIN)
4089 goto SetAttrLgcyRetry;
4090
4091 return rc;
4092}
4093#endif /* temporarily unneeded SetAttr legacy function */
4094
4095int
4096CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004097 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4098 dev_t device, const struct nls_table *nls_codepage,
4099 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100{
4101 TRANSACTION2_SPI_REQ *pSMB = NULL;
4102 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4103 int name_len;
4104 int rc = 0;
4105 int bytes_returned = 0;
4106 FILE_UNIX_BASIC_INFO *data_offset;
4107 __u16 params, param_offset, offset, count, byte_count;
4108
4109 cFYI(1, ("In SetUID/GID/Mode"));
4110setPermsRetry:
4111 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4112 (void **) &pSMBr);
4113 if (rc)
4114 return rc;
4115
4116 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4117 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004118 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004119 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 name_len++; /* trailing null */
4121 name_len *= 2;
4122 } else { /* BB improve the check for buffer overruns BB */
4123 name_len = strnlen(fileName, PATH_MAX);
4124 name_len++; /* trailing null */
4125 strncpy(pSMB->FileName, fileName, name_len);
4126 }
4127
4128 params = 6 + name_len;
4129 count = sizeof (FILE_UNIX_BASIC_INFO);
4130 pSMB->MaxParameterCount = cpu_to_le16(2);
4131 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4132 pSMB->MaxSetupCount = 0;
4133 pSMB->Reserved = 0;
4134 pSMB->Flags = 0;
4135 pSMB->Timeout = 0;
4136 pSMB->Reserved2 = 0;
4137 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4138 InformationLevel) - 4;
4139 offset = param_offset + params;
4140 data_offset =
4141 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4142 offset);
4143 memset(data_offset, 0, count);
4144 pSMB->DataOffset = cpu_to_le16(offset);
4145 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4146 pSMB->SetupCount = 1;
4147 pSMB->Reserved3 = 0;
4148 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4149 byte_count = 3 /* pad */ + params + count;
4150 pSMB->ParameterCount = cpu_to_le16(params);
4151 pSMB->DataCount = cpu_to_le16(count);
4152 pSMB->TotalParameterCount = pSMB->ParameterCount;
4153 pSMB->TotalDataCount = pSMB->DataCount;
4154 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4155 pSMB->Reserved4 = 0;
4156 pSMB->hdr.smb_buf_length += byte_count;
4157 data_offset->Uid = cpu_to_le64(uid);
4158 data_offset->Gid = cpu_to_le64(gid);
4159 /* better to leave device as zero when it is */
4160 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4161 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4162 data_offset->Permissions = cpu_to_le64(mode);
4163
4164 if(S_ISREG(mode))
4165 data_offset->Type = cpu_to_le32(UNIX_FILE);
4166 else if(S_ISDIR(mode))
4167 data_offset->Type = cpu_to_le32(UNIX_DIR);
4168 else if(S_ISLNK(mode))
4169 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4170 else if(S_ISCHR(mode))
4171 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4172 else if(S_ISBLK(mode))
4173 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4174 else if(S_ISFIFO(mode))
4175 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4176 else if(S_ISSOCK(mode))
4177 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4178
4179
4180 pSMB->ByteCount = cpu_to_le16(byte_count);
4181 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4182 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4183 if (rc) {
4184 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4185 }
4186
4187 if (pSMB)
4188 cifs_buf_release(pSMB);
4189 if (rc == -EAGAIN)
4190 goto setPermsRetry;
4191 return rc;
4192}
4193
4194int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004195 const int notify_subdirs, const __u16 netfid,
4196 __u32 filter, struct file * pfile, int multishot,
4197 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198{
4199 int rc = 0;
4200 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4201 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004202 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 int bytes_returned;
4204
4205 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4206 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4207 (void **) &pSMBr);
4208 if (rc)
4209 return rc;
4210
4211 pSMB->TotalParameterCount = 0 ;
4212 pSMB->TotalDataCount = 0;
4213 pSMB->MaxParameterCount = cpu_to_le32(2);
4214 /* BB find exact data count max from sess structure BB */
4215 pSMB->MaxDataCount = 0; /* same in little endian or be */
4216 pSMB->MaxSetupCount = 4;
4217 pSMB->Reserved = 0;
4218 pSMB->ParameterOffset = 0;
4219 pSMB->DataCount = 0;
4220 pSMB->DataOffset = 0;
4221 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4222 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4223 pSMB->ParameterCount = pSMB->TotalParameterCount;
4224 if(notify_subdirs)
4225 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4226 pSMB->Reserved2 = 0;
4227 pSMB->CompletionFilter = cpu_to_le32(filter);
4228 pSMB->Fid = netfid; /* file handle always le */
4229 pSMB->ByteCount = 0;
4230
4231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4232 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4233 if (rc) {
4234 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004235 } else {
4236 /* Add file to outstanding requests */
4237 dnotify_req = (struct dir_notify_req *) kmalloc(
4238 sizeof(struct dir_notify_req), GFP_KERNEL);
4239 dnotify_req->Pid = pSMB->hdr.Pid;
4240 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4241 dnotify_req->Mid = pSMB->hdr.Mid;
4242 dnotify_req->Tid = pSMB->hdr.Tid;
4243 dnotify_req->Uid = pSMB->hdr.Uid;
4244 dnotify_req->netfid = netfid;
Steve French167a2512005-08-24 20:03:11 -07004245 dnotify_req->pfile = pfile;
Steve Frenchff5dbd92005-08-24 17:10:36 -07004246 dnotify_req->filter = filter;
4247 dnotify_req->multishot = multishot;
4248 spin_lock(&GlobalMid_Lock);
4249 list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
4250 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 }
4252 cifs_buf_release(pSMB);
4253 return rc;
4254}
4255#ifdef CONFIG_CIFS_XATTR
4256ssize_t
4257CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4258 const unsigned char *searchName,
4259 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004260 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261{
4262 /* BB assumes one setup word */
4263 TRANSACTION2_QPI_REQ *pSMB = NULL;
4264 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4265 int rc = 0;
4266 int bytes_returned;
4267 int name_len;
4268 struct fea * temp_fea;
4269 char * temp_ptr;
4270 __u16 params, byte_count;
4271
4272 cFYI(1, ("In Query All EAs path %s", searchName));
4273QAllEAsRetry:
4274 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4275 (void **) &pSMBr);
4276 if (rc)
4277 return rc;
4278
4279 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4280 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004281 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004282 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 name_len++; /* trailing null */
4284 name_len *= 2;
4285 } else { /* BB improve the check for buffer overruns BB */
4286 name_len = strnlen(searchName, PATH_MAX);
4287 name_len++; /* trailing null */
4288 strncpy(pSMB->FileName, searchName, name_len);
4289 }
4290
4291 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4292 pSMB->TotalDataCount = 0;
4293 pSMB->MaxParameterCount = cpu_to_le16(2);
4294 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4295 pSMB->MaxSetupCount = 0;
4296 pSMB->Reserved = 0;
4297 pSMB->Flags = 0;
4298 pSMB->Timeout = 0;
4299 pSMB->Reserved2 = 0;
4300 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4301 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4302 pSMB->DataCount = 0;
4303 pSMB->DataOffset = 0;
4304 pSMB->SetupCount = 1;
4305 pSMB->Reserved3 = 0;
4306 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4307 byte_count = params + 1 /* pad */ ;
4308 pSMB->TotalParameterCount = cpu_to_le16(params);
4309 pSMB->ParameterCount = pSMB->TotalParameterCount;
4310 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4311 pSMB->Reserved4 = 0;
4312 pSMB->hdr.smb_buf_length += byte_count;
4313 pSMB->ByteCount = cpu_to_le16(byte_count);
4314
4315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4317 if (rc) {
4318 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4319 } else { /* decode response */
4320 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4321
4322 /* BB also check enough total bytes returned */
4323 /* BB we need to improve the validity checking
4324 of these trans2 responses */
4325 if (rc || (pSMBr->ByteCount < 4))
4326 rc = -EIO; /* bad smb */
4327 /* else if (pFindData){
4328 memcpy((char *) pFindData,
4329 (char *) &pSMBr->hdr.Protocol +
4330 data_offset, kl);
4331 }*/ else {
4332 /* check that length of list is not more than bcc */
4333 /* check that each entry does not go beyond length
4334 of list */
4335 /* check that each element of each entry does not
4336 go beyond end of list */
4337 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4338 struct fealist * ea_response_data;
4339 rc = 0;
4340 /* validate_trans2_offsets() */
4341 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4342 ea_response_data = (struct fealist *)
4343 (((char *) &pSMBr->hdr.Protocol) +
4344 data_offset);
4345 name_len = le32_to_cpu(ea_response_data->list_len);
4346 cFYI(1,("ea length %d", name_len));
4347 if(name_len <= 8) {
4348 /* returned EA size zeroed at top of function */
4349 cFYI(1,("empty EA list returned from server"));
4350 } else {
4351 /* account for ea list len */
4352 name_len -= 4;
4353 temp_fea = ea_response_data->list;
4354 temp_ptr = (char *)temp_fea;
4355 while(name_len > 0) {
4356 __u16 value_len;
4357 name_len -= 4;
4358 temp_ptr += 4;
4359 rc += temp_fea->name_len;
4360 /* account for prefix user. and trailing null */
4361 rc = rc + 5 + 1;
4362 if(rc<(int)buf_size) {
4363 memcpy(EAData,"user.",5);
4364 EAData+=5;
4365 memcpy(EAData,temp_ptr,temp_fea->name_len);
4366 EAData+=temp_fea->name_len;
4367 /* null terminate name */
4368 *EAData = 0;
4369 EAData = EAData + 1;
4370 } else if(buf_size == 0) {
4371 /* skip copy - calc size only */
4372 } else {
4373 /* stop before overrun buffer */
4374 rc = -ERANGE;
4375 break;
4376 }
4377 name_len -= temp_fea->name_len;
4378 temp_ptr += temp_fea->name_len;
4379 /* account for trailing null */
4380 name_len--;
4381 temp_ptr++;
4382 value_len = le16_to_cpu(temp_fea->value_len);
4383 name_len -= value_len;
4384 temp_ptr += value_len;
4385 /* BB check that temp_ptr is still within smb BB*/
4386 /* no trailing null to account for in value len */
4387 /* go on to next EA */
4388 temp_fea = (struct fea *)temp_ptr;
4389 }
4390 }
4391 }
4392 }
4393 if (pSMB)
4394 cifs_buf_release(pSMB);
4395 if (rc == -EAGAIN)
4396 goto QAllEAsRetry;
4397
4398 return (ssize_t)rc;
4399}
4400
4401ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4402 const unsigned char * searchName,const unsigned char * ea_name,
4403 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004404 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405{
4406 TRANSACTION2_QPI_REQ *pSMB = NULL;
4407 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4408 int rc = 0;
4409 int bytes_returned;
4410 int name_len;
4411 struct fea * temp_fea;
4412 char * temp_ptr;
4413 __u16 params, byte_count;
4414
4415 cFYI(1, ("In Query EA path %s", searchName));
4416QEARetry:
4417 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4418 (void **) &pSMBr);
4419 if (rc)
4420 return rc;
4421
4422 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4423 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004424 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004425 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 name_len++; /* trailing null */
4427 name_len *= 2;
4428 } else { /* BB improve the check for buffer overruns BB */
4429 name_len = strnlen(searchName, PATH_MAX);
4430 name_len++; /* trailing null */
4431 strncpy(pSMB->FileName, searchName, name_len);
4432 }
4433
4434 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4435 pSMB->TotalDataCount = 0;
4436 pSMB->MaxParameterCount = cpu_to_le16(2);
4437 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4438 pSMB->MaxSetupCount = 0;
4439 pSMB->Reserved = 0;
4440 pSMB->Flags = 0;
4441 pSMB->Timeout = 0;
4442 pSMB->Reserved2 = 0;
4443 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4444 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4445 pSMB->DataCount = 0;
4446 pSMB->DataOffset = 0;
4447 pSMB->SetupCount = 1;
4448 pSMB->Reserved3 = 0;
4449 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4450 byte_count = params + 1 /* pad */ ;
4451 pSMB->TotalParameterCount = cpu_to_le16(params);
4452 pSMB->ParameterCount = pSMB->TotalParameterCount;
4453 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4454 pSMB->Reserved4 = 0;
4455 pSMB->hdr.smb_buf_length += byte_count;
4456 pSMB->ByteCount = cpu_to_le16(byte_count);
4457
4458 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4460 if (rc) {
4461 cFYI(1, ("Send error in Query EA = %d", rc));
4462 } else { /* decode response */
4463 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4464
4465 /* BB also check enough total bytes returned */
4466 /* BB we need to improve the validity checking
4467 of these trans2 responses */
4468 if (rc || (pSMBr->ByteCount < 4))
4469 rc = -EIO; /* bad smb */
4470 /* else if (pFindData){
4471 memcpy((char *) pFindData,
4472 (char *) &pSMBr->hdr.Protocol +
4473 data_offset, kl);
4474 }*/ else {
4475 /* check that length of list is not more than bcc */
4476 /* check that each entry does not go beyond length
4477 of list */
4478 /* check that each element of each entry does not
4479 go beyond end of list */
4480 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4481 struct fealist * ea_response_data;
4482 rc = -ENODATA;
4483 /* validate_trans2_offsets() */
4484 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4485 ea_response_data = (struct fealist *)
4486 (((char *) &pSMBr->hdr.Protocol) +
4487 data_offset);
4488 name_len = le32_to_cpu(ea_response_data->list_len);
4489 cFYI(1,("ea length %d", name_len));
4490 if(name_len <= 8) {
4491 /* returned EA size zeroed at top of function */
4492 cFYI(1,("empty EA list returned from server"));
4493 } else {
4494 /* account for ea list len */
4495 name_len -= 4;
4496 temp_fea = ea_response_data->list;
4497 temp_ptr = (char *)temp_fea;
4498 /* loop through checking if we have a matching
4499 name and then return the associated value */
4500 while(name_len > 0) {
4501 __u16 value_len;
4502 name_len -= 4;
4503 temp_ptr += 4;
4504 value_len = le16_to_cpu(temp_fea->value_len);
4505 /* BB validate that value_len falls within SMB,
4506 even though maximum for name_len is 255 */
4507 if(memcmp(temp_fea->name,ea_name,
4508 temp_fea->name_len) == 0) {
4509 /* found a match */
4510 rc = value_len;
4511 /* account for prefix user. and trailing null */
4512 if(rc<=(int)buf_size) {
4513 memcpy(ea_value,
4514 temp_fea->name+temp_fea->name_len+1,
4515 rc);
4516 /* ea values, unlike ea names,
4517 are not null terminated */
4518 } else if(buf_size == 0) {
4519 /* skip copy - calc size only */
4520 } else {
4521 /* stop before overrun buffer */
4522 rc = -ERANGE;
4523 }
4524 break;
4525 }
4526 name_len -= temp_fea->name_len;
4527 temp_ptr += temp_fea->name_len;
4528 /* account for trailing null */
4529 name_len--;
4530 temp_ptr++;
4531 name_len -= value_len;
4532 temp_ptr += value_len;
4533 /* no trailing null to account for in value len */
4534 /* go on to next EA */
4535 temp_fea = (struct fea *)temp_ptr;
4536 }
4537 }
4538 }
4539 }
4540 if (pSMB)
4541 cifs_buf_release(pSMB);
4542 if (rc == -EAGAIN)
4543 goto QEARetry;
4544
4545 return (ssize_t)rc;
4546}
4547
4548int
4549CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4550 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004551 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4552 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553{
4554 struct smb_com_transaction2_spi_req *pSMB = NULL;
4555 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4556 struct fealist *parm_data;
4557 int name_len;
4558 int rc = 0;
4559 int bytes_returned = 0;
4560 __u16 params, param_offset, byte_count, offset, count;
4561
4562 cFYI(1, ("In SetEA"));
4563SetEARetry:
4564 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4565 (void **) &pSMBr);
4566 if (rc)
4567 return rc;
4568
4569 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4570 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004571 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004572 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 name_len++; /* trailing null */
4574 name_len *= 2;
4575 } else { /* BB improve the check for buffer overruns BB */
4576 name_len = strnlen(fileName, PATH_MAX);
4577 name_len++; /* trailing null */
4578 strncpy(pSMB->FileName, fileName, name_len);
4579 }
4580
4581 params = 6 + name_len;
4582
4583 /* done calculating parms using name_len of file name,
4584 now use name_len to calculate length of ea name
4585 we are going to create in the inode xattrs */
4586 if(ea_name == NULL)
4587 name_len = 0;
4588 else
4589 name_len = strnlen(ea_name,255);
4590
4591 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4592 pSMB->MaxParameterCount = cpu_to_le16(2);
4593 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4594 pSMB->MaxSetupCount = 0;
4595 pSMB->Reserved = 0;
4596 pSMB->Flags = 0;
4597 pSMB->Timeout = 0;
4598 pSMB->Reserved2 = 0;
4599 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4600 InformationLevel) - 4;
4601 offset = param_offset + params;
4602 pSMB->InformationLevel =
4603 cpu_to_le16(SMB_SET_FILE_EA);
4604
4605 parm_data =
4606 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4607 offset);
4608 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4609 pSMB->DataOffset = cpu_to_le16(offset);
4610 pSMB->SetupCount = 1;
4611 pSMB->Reserved3 = 0;
4612 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4613 byte_count = 3 /* pad */ + params + count;
4614 pSMB->DataCount = cpu_to_le16(count);
4615 parm_data->list_len = cpu_to_le32(count);
4616 parm_data->list[0].EA_flags = 0;
4617 /* we checked above that name len is less than 255 */
4618 parm_data->list[0].name_len = (__u8)name_len;;
4619 /* EA names are always ASCII */
4620 if(ea_name)
4621 strncpy(parm_data->list[0].name,ea_name,name_len);
4622 parm_data->list[0].name[name_len] = 0;
4623 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4624 /* caller ensures that ea_value_len is less than 64K but
4625 we need to ensure that it fits within the smb */
4626
4627 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4628 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4629 if(ea_value_len)
4630 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4631
4632 pSMB->TotalDataCount = pSMB->DataCount;
4633 pSMB->ParameterCount = cpu_to_le16(params);
4634 pSMB->TotalParameterCount = pSMB->ParameterCount;
4635 pSMB->Reserved4 = 0;
4636 pSMB->hdr.smb_buf_length += byte_count;
4637 pSMB->ByteCount = cpu_to_le16(byte_count);
4638 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4639 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4640 if (rc) {
4641 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4642 }
4643
4644 cifs_buf_release(pSMB);
4645
4646 if (rc == -EAGAIN)
4647 goto SetEARetry;
4648
4649 return rc;
4650}
4651
4652#endif