blob: 9312bfc5668202218f59efda0028f92ac5761f40 [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);
Steve French3e844692005-10-03 13:37:24 -0700128 /* BB FIXME add code to check if wsize needs
129 update due to negotiated smb buffer size
130 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 if(rc == 0)
132 atomic_inc(&tconInfoReconnectCount);
133
134 cFYI(1, ("reconnect tcon rc = %d", rc));
135 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700136 it is safer (and faster) to reopen files
137 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700140 know whether we can continue or not without
141 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 switch(smb_command) {
143 case SMB_COM_READ_ANDX:
144 case SMB_COM_WRITE_ANDX:
145 case SMB_COM_CLOSE:
146 case SMB_COM_FIND_CLOSE2:
147 case SMB_COM_LOCKING_ANDX: {
148 unload_nls(nls_codepage);
149 return -EAGAIN;
150 }
151 }
152 } else {
153 up(&tcon->ses->sesSem);
154 }
155 unload_nls(nls_codepage);
156
157 } else {
158 return -EIO;
159 }
160 }
161 if(rc)
162 return rc;
163
164 *request_buf = cifs_small_buf_get();
165 if (*request_buf == NULL) {
166 /* BB should we add a retry in here if not a writepage? */
167 return -ENOMEM;
168 }
169
170 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
171
Steve Frencha4544342005-08-24 13:59:35 -0700172 if(tcon != NULL)
173 cifs_stats_inc(&tcon->num_smbs_sent);
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 return rc;
176}
177
178/* If the return code is zero, this function must fill in request_buf pointer */
179static int
180smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
181 void **request_buf /* returned */ ,
182 void **response_buf /* returned */ )
183{
184 int rc = 0;
185
186 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
187 check for tcp and smb session status done differently
188 for those three - in the calling routine */
189 if(tcon) {
Steve French31ca3bc2005-04-28 22:41:11 -0700190 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
191 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700193 /* Give Demultiplex thread up to 10 seconds to
194 reconnect, should be greater than cifs socket
195 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
197 wait_event_interruptible_timeout(tcon->ses->server->response_q,
198 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700199 if(tcon->ses->server->tcpStatus ==
200 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 /* on "soft" mounts we wait once */
202 if((tcon->retry == FALSE) ||
203 (tcon->ses->status == CifsExiting)) {
204 cFYI(1,("gave up waiting on reconnect in smb_init"));
205 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700206 } /* else "hard" mount - keep retrying
207 until process is killed or server
208 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 } else /* TCP session is reestablished now */
210 break;
211
212 }
213
214 nls_codepage = load_nls_default();
215 /* need to prevent multiple threads trying to
216 simultaneously reconnect the same SMB session */
217 down(&tcon->ses->sesSem);
218 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700219 rc = cifs_setup_session(0, tcon->ses,
220 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
222 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700223 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
224 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700226 /* BB FIXME add code to check if wsize needs
227 update due to negotiated smb buffer size
228 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 if(rc == 0)
230 atomic_inc(&tconInfoReconnectCount);
231
232 cFYI(1, ("reconnect tcon rc = %d", rc));
233 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700234 it is safer (and faster) to reopen files
235 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700238 know whether we can continue or not without
239 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 switch(smb_command) {
241 case SMB_COM_READ_ANDX:
242 case SMB_COM_WRITE_ANDX:
243 case SMB_COM_CLOSE:
244 case SMB_COM_FIND_CLOSE2:
245 case SMB_COM_LOCKING_ANDX: {
246 unload_nls(nls_codepage);
247 return -EAGAIN;
248 }
249 }
250 } else {
251 up(&tcon->ses->sesSem);
252 }
253 unload_nls(nls_codepage);
254
255 } else {
256 return -EIO;
257 }
258 }
259 if(rc)
260 return rc;
261
262 *request_buf = cifs_buf_get();
263 if (*request_buf == NULL) {
264 /* BB should we add a retry in here if not a writepage? */
265 return -ENOMEM;
266 }
267 /* Although the original thought was we needed the response buf for */
268 /* potential retries of smb operations it turns out we can determine */
269 /* from the mid flags when the request buffer can be resent without */
270 /* having to use a second distinct buffer for the response */
271 *response_buf = *request_buf;
272
273 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
274 wct /*wct */ );
275
Steve Frencha4544342005-08-24 13:59:35 -0700276 if(tcon != NULL)
277 cifs_stats_inc(&tcon->num_smbs_sent);
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return rc;
280}
281
282static int validate_t2(struct smb_t2_rsp * pSMB)
283{
284 int rc = -EINVAL;
285 int total_size;
286 char * pBCC;
287
288 /* check for plausible wct, bcc and t2 data and parm sizes */
289 /* check for parm and data offset going beyond end of smb */
290 if(pSMB->hdr.WordCount >= 10) {
291 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
292 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
293 /* check that bcc is at least as big as parms + data */
294 /* check that bcc is less than negotiated smb buffer */
295 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
296 if(total_size < 512) {
297 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
298 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700299 pBCC = (pSMB->hdr.WordCount * 2) +
300 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 (char *)pSMB;
302 if((total_size <= (*(u16 *)pBCC)) &&
303 (total_size <
304 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
305 return 0;
306 }
307
308 }
309 }
310 }
311 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
312 sizeof(struct smb_t2_rsp) + 16);
313 return rc;
314}
315int
316CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
317{
318 NEGOTIATE_REQ *pSMB;
319 NEGOTIATE_RSP *pSMBr;
320 int rc = 0;
321 int bytes_returned;
322 struct TCP_Server_Info * server;
323 u16 count;
324
325 if(ses->server)
326 server = ses->server;
327 else {
328 rc = -EIO;
329 return rc;
330 }
331 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
332 (void **) &pSMB, (void **) &pSMBr);
333 if (rc)
334 return rc;
Steve French1982c342005-08-17 12:38:22 -0700335 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
337 if (extended_security)
338 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
339
340 count = strlen(protocols[0].name) + 1;
341 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
342 /* null guaranteed to be at end of source and target buffers anyway */
343
344 pSMB->hdr.smb_buf_length += count;
345 pSMB->ByteCount = cpu_to_le16(count);
346
347 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
349 if (rc == 0) {
350 server->secMode = pSMBr->SecurityMode;
Steve French09d1db52005-04-28 22:41:08 -0700351 server->secType = NTLM; /* BB override default for
352 NTLMv2 or kerberos v5 */
353 /* one byte - no need to convert this or EncryptionKeyLen
354 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
356 /* probably no need to store and check maxvcs */
357 server->maxBuf =
358 min(le32_to_cpu(pSMBr->MaxBufferSize),
359 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
360 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
361 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
362 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
363 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
364 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
365 /* BB with UTC do we ever need to be using srvr timezone? */
366 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
367 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
368 CIFS_CRYPTO_KEY_SIZE);
369 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
370 && (pSMBr->EncryptionKeyLength == 0)) {
371 /* decode security blob */
372 } else
373 rc = -EIO;
374
375 /* BB might be helpful to save off the domain of server here */
376
377 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
378 (server->capabilities & CAP_EXTENDED_SECURITY)) {
379 count = pSMBr->ByteCount;
380 if (count < 16)
381 rc = -EIO;
382 else if (count == 16) {
383 server->secType = RawNTLMSSP;
384 if (server->socketUseCount.counter > 1) {
385 if (memcmp
386 (server->server_GUID,
387 pSMBr->u.extended_response.
388 GUID, 16) != 0) {
389 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700390 ("UID of server does not match previous connection to same ip address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 memcpy(server->
392 server_GUID,
393 pSMBr->u.
394 extended_response.
395 GUID, 16);
396 }
397 } else
398 memcpy(server->server_GUID,
399 pSMBr->u.extended_response.
400 GUID, 16);
401 } else {
402 rc = decode_negTokenInit(pSMBr->u.
403 extended_response.
404 SecurityBlob,
405 count - 16,
406 &server->secType);
407 if(rc == 1) {
408 /* BB Need to fill struct for sessetup here */
409 rc = -EOPNOTSUPP;
410 } else {
411 rc = -EINVAL;
412 }
413 }
414 } else
415 server->capabilities &= ~CAP_EXTENDED_SECURITY;
416 if(sign_CIFS_PDUs == FALSE) {
417 if(server->secMode & SECMODE_SIGN_REQUIRED)
418 cERROR(1,
419 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700420 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 } else if(sign_CIFS_PDUs == 1) {
422 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700423 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 }
425
426 }
Steve French1982c342005-08-17 12:38:22 -0700427
Steve French4a6d87f2005-08-13 08:15:54 -0700428 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return rc;
430}
431
432int
433CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
434{
435 struct smb_hdr *smb_buffer;
436 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
437 int rc = 0;
438 int length;
439
440 cFYI(1, ("In tree disconnect"));
441 /*
442 * If last user of the connection and
443 * connection alive - disconnect it
444 * If this is the last connection on the server session disconnect it
445 * (and inside session disconnect we should check if tcp socket needs
446 * to be freed and kernel thread woken up).
447 */
448 if (tcon)
449 down(&tcon->tconSem);
450 else
451 return -EIO;
452
453 atomic_dec(&tcon->useCount);
454 if (atomic_read(&tcon->useCount) > 0) {
455 up(&tcon->tconSem);
456 return -EBUSY;
457 }
458
459 /* No need to return error on this operation if tid invalidated and
460 closed on server already e.g. due to tcp session crashing */
461 if(tcon->tidStatus == CifsNeedReconnect) {
462 up(&tcon->tconSem);
463 return 0;
464 }
465
466 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
467 up(&tcon->tconSem);
468 return -EIO;
469 }
Steve French09d1db52005-04-28 22:41:08 -0700470 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
471 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (rc) {
473 up(&tcon->tconSem);
474 return rc;
475 } else {
476 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
479 &length, 0);
480 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700481 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483 if (smb_buffer)
484 cifs_small_buf_release(smb_buffer);
485 up(&tcon->tconSem);
486
487 /* No need to return error on this operation if tid invalidated and
488 closed on server already e.g. due to tcp session crashing */
489 if (rc == -EAGAIN)
490 rc = 0;
491
492 return rc;
493}
494
495int
496CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
497{
498 struct smb_hdr *smb_buffer_response;
499 LOGOFF_ANDX_REQ *pSMB;
500 int rc = 0;
501 int length;
502
503 cFYI(1, ("In SMBLogoff for session disconnect"));
504 if (ses)
505 down(&ses->sesSem);
506 else
507 return -EIO;
508
509 atomic_dec(&ses->inUse);
510 if (atomic_read(&ses->inUse) > 0) {
511 up(&ses->sesSem);
512 return -EBUSY;
513 }
514 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
515 if (rc) {
516 up(&ses->sesSem);
517 return rc;
518 }
519
520 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
521
522 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700523 pSMB->hdr.Mid = GetNextMid(ses->server);
524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 if(ses->server->secMode &
526 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
527 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
528 }
529
530 pSMB->hdr.Uid = ses->Suid;
531
532 pSMB->AndXCommand = 0xFF;
533 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
534 smb_buffer_response, &length, 0);
535 if (ses->server) {
536 atomic_dec(&ses->server->socketUseCount);
537 if (atomic_read(&ses->server->socketUseCount) == 0) {
538 spin_lock(&GlobalMid_Lock);
539 ses->server->tcpStatus = CifsExiting;
540 spin_unlock(&GlobalMid_Lock);
541 rc = -ESHUTDOWN;
542 }
543 }
Steve Frencha59c6582005-08-17 12:12:19 -0700544 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700545 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 /* if session dead then we do not need to do ulogoff,
548 since server closed smb session, no sense reporting
549 error */
550 if (rc == -EAGAIN)
551 rc = 0;
552 return rc;
553}
554
555int
Steve French737b7582005-04-28 22:41:06 -0700556CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
557 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
559 DELETE_FILE_REQ *pSMB = NULL;
560 DELETE_FILE_RSP *pSMBr = NULL;
561 int rc = 0;
562 int bytes_returned;
563 int name_len;
564
565DelFileRetry:
566 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
567 (void **) &pSMBr);
568 if (rc)
569 return rc;
570
571 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
572 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500573 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700574 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 name_len++; /* trailing null */
576 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700577 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 name_len = strnlen(fileName, PATH_MAX);
579 name_len++; /* trailing null */
580 strncpy(pSMB->fileName, fileName, name_len);
581 }
582 pSMB->SearchAttributes =
583 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
584 pSMB->BufferFormat = 0x04;
585 pSMB->hdr.smb_buf_length += name_len + 1;
586 pSMB->ByteCount = cpu_to_le16(name_len + 1);
587 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
588 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700589 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (rc) {
591 cFYI(1, ("Error in RMFile = %d", rc));
592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 cifs_buf_release(pSMB);
595 if (rc == -EAGAIN)
596 goto DelFileRetry;
597
598 return rc;
599}
600
601int
Steve French737b7582005-04-28 22:41:06 -0700602CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
603 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
605 DELETE_DIRECTORY_REQ *pSMB = NULL;
606 DELETE_DIRECTORY_RSP *pSMBr = NULL;
607 int rc = 0;
608 int bytes_returned;
609 int name_len;
610
611 cFYI(1, ("In CIFSSMBRmDir"));
612RmDirRetry:
613 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
614 (void **) &pSMBr);
615 if (rc)
616 return rc;
617
618 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700619 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
620 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 name_len++; /* trailing null */
622 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700623 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 name_len = strnlen(dirName, PATH_MAX);
625 name_len++; /* trailing null */
626 strncpy(pSMB->DirName, dirName, name_len);
627 }
628
629 pSMB->BufferFormat = 0x04;
630 pSMB->hdr.smb_buf_length += name_len + 1;
631 pSMB->ByteCount = cpu_to_le16(name_len + 1);
632 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
633 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700634 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (rc) {
636 cFYI(1, ("Error in RMDir = %d", rc));
637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 cifs_buf_release(pSMB);
640 if (rc == -EAGAIN)
641 goto RmDirRetry;
642 return rc;
643}
644
645int
646CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700647 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
649 int rc = 0;
650 CREATE_DIRECTORY_REQ *pSMB = NULL;
651 CREATE_DIRECTORY_RSP *pSMBr = NULL;
652 int bytes_returned;
653 int name_len;
654
655 cFYI(1, ("In CIFSSMBMkDir"));
656MkDirRetry:
657 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
658 (void **) &pSMBr);
659 if (rc)
660 return rc;
661
662 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500663 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700664 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 name_len++; /* trailing null */
666 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700667 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 name_len = strnlen(name, PATH_MAX);
669 name_len++; /* trailing null */
670 strncpy(pSMB->DirName, name, name_len);
671 }
672
673 pSMB->BufferFormat = 0x04;
674 pSMB->hdr.smb_buf_length += name_len + 1;
675 pSMB->ByteCount = cpu_to_le16(name_len + 1);
676 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700678 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (rc) {
680 cFYI(1, ("Error in Mkdir = %d", rc));
681 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 cifs_buf_release(pSMB);
684 if (rc == -EAGAIN)
685 goto MkDirRetry;
686 return rc;
687}
688
Steve Frencha9d02ad2005-08-24 23:06:05 -0700689static __u16 convert_disposition(int disposition)
690{
691 __u16 ofun = 0;
692
693 switch (disposition) {
694 case FILE_SUPERSEDE:
695 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
696 break;
697 case FILE_OPEN:
698 ofun = SMBOPEN_OAPPEND;
699 break;
700 case FILE_CREATE:
701 ofun = SMBOPEN_OCREATE;
702 break;
703 case FILE_OPEN_IF:
704 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
705 break;
706 case FILE_OVERWRITE:
707 ofun = SMBOPEN_OTRUNC;
708 break;
709 case FILE_OVERWRITE_IF:
710 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
711 break;
712 default:
713 cFYI(1,("unknown disposition %d",disposition));
714 ofun = SMBOPEN_OAPPEND; /* regular open */
715 }
716 return ofun;
717}
718
719int
720SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
721 const char *fileName, const int openDisposition,
722 const int access_flags, const int create_options, __u16 * netfid,
723 int *pOplock, FILE_ALL_INFO * pfile_info,
724 const struct nls_table *nls_codepage, int remap)
725{
726 int rc = -EACCES;
727 OPENX_REQ *pSMB = NULL;
728 OPENX_RSP *pSMBr = NULL;
729 int bytes_returned;
730 int name_len;
731 __u16 count;
732
733OldOpenRetry:
734 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
735 (void **) &pSMBr);
736 if (rc)
737 return rc;
738
739 pSMB->AndXCommand = 0xFF; /* none */
740
741 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
742 count = 1; /* account for one byte pad to word boundary */
743 name_len =
744 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
745 fileName, PATH_MAX, nls_codepage, remap);
746 name_len++; /* trailing null */
747 name_len *= 2;
748 } else { /* BB improve check for buffer overruns BB */
749 count = 0; /* no pad */
750 name_len = strnlen(fileName, PATH_MAX);
751 name_len++; /* trailing null */
752 strncpy(pSMB->fileName, fileName, name_len);
753 }
754 if (*pOplock & REQ_OPLOCK)
755 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
756 else if (*pOplock & REQ_BATCHOPLOCK) {
757 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
758 }
759 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
760 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
761 /* 0 = read
762 1 = write
763 2 = rw
764 3 = execute
765 */
766 pSMB->Mode = cpu_to_le16(2);
767 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
768 /* set file as system file if special file such
769 as fifo and server expecting SFU style and
770 no Unix extensions */
771
772 if(create_options & CREATE_OPTION_SPECIAL)
773 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
774 else
Steve French3e87d802005-09-18 20:49:21 -0700775 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700776
777 /* if ((omode & S_IWUGO) == 0)
778 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
779 /* Above line causes problems due to vfs splitting create into two
780 pieces - need to set mode after file created not while it is
781 being created */
782
783 /* BB FIXME BB */
784/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
785 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700786
787 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700788 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700789 count += name_len;
790 pSMB->hdr.smb_buf_length += count;
791
792 pSMB->ByteCount = cpu_to_le16(count);
793 /* long_op set to 1 to allow for oplock break timeouts */
794 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
795 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
796 cifs_stats_inc(&tcon->num_opens);
797 if (rc) {
798 cFYI(1, ("Error in Open = %d", rc));
799 } else {
800 /* BB verify if wct == 15 */
801
802/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
803
804 *netfid = pSMBr->Fid; /* cifs fid stays in le */
805 /* Let caller know file was created so we can set the mode. */
806 /* Do we care about the CreateAction in any other cases? */
807 /* BB FIXME BB */
808/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
809 *pOplock |= CIFS_CREATE_ACTION; */
810 /* BB FIXME END */
811
812 if(pfile_info) {
813 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
814 pfile_info->LastAccessTime = 0; /* BB fixme */
815 pfile_info->LastWriteTime = 0; /* BB fixme */
816 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700817 pfile_info->Attributes =
818 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700819 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700820 pfile_info->AllocationSize =
821 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
822 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700823 pfile_info->NumberOfLinks = cpu_to_le32(1);
824 }
825 }
826
827 cifs_buf_release(pSMB);
828 if (rc == -EAGAIN)
829 goto OldOpenRetry;
830 return rc;
831}
832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833int
834CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
835 const char *fileName, const int openDisposition,
836 const int access_flags, const int create_options, __u16 * netfid,
837 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700838 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
840 int rc = -EACCES;
841 OPEN_REQ *pSMB = NULL;
842 OPEN_RSP *pSMBr = NULL;
843 int bytes_returned;
844 int name_len;
845 __u16 count;
846
847openRetry:
848 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
849 (void **) &pSMBr);
850 if (rc)
851 return rc;
852
853 pSMB->AndXCommand = 0xFF; /* none */
854
855 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
856 count = 1; /* account for one byte pad to word boundary */
857 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500858 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700859 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 name_len++; /* trailing null */
861 name_len *= 2;
862 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700863 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 count = 0; /* no pad */
865 name_len = strnlen(fileName, PATH_MAX);
866 name_len++; /* trailing null */
867 pSMB->NameLength = cpu_to_le16(name_len);
868 strncpy(pSMB->fileName, fileName, name_len);
869 }
870 if (*pOplock & REQ_OPLOCK)
871 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
872 else if (*pOplock & REQ_BATCHOPLOCK) {
873 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
874 }
875 pSMB->DesiredAccess = cpu_to_le32(access_flags);
876 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700877 /* set file as system file if special file such
878 as fifo and server expecting SFU style and
879 no Unix extensions */
880 if(create_options & CREATE_OPTION_SPECIAL)
881 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
882 else
883 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 /* XP does not handle ATTR_POSIX_SEMANTICS */
885 /* but it helps speed up case sensitive checks for other
886 servers such as Samba */
887 if (tcon->ses->capabilities & CAP_UNIX)
888 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
889
890 /* if ((omode & S_IWUGO) == 0)
891 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
892 /* Above line causes problems due to vfs splitting create into two
893 pieces - need to set mode after file created not while it is
894 being created */
895 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
896 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700897 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700898 /* BB Expirement with various impersonation levels and verify */
899 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 pSMB->SecurityFlags =
901 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
902
903 count += name_len;
904 pSMB->hdr.smb_buf_length += count;
905
906 pSMB->ByteCount = cpu_to_le16(count);
907 /* long_op set to 1 to allow for oplock break timeouts */
908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
909 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -0700910 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 if (rc) {
912 cFYI(1, ("Error in Open = %d", rc));
913 } else {
Steve French09d1db52005-04-28 22:41:08 -0700914 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 *netfid = pSMBr->Fid; /* cifs fid stays in le */
916 /* Let caller know file was created so we can set the mode. */
917 /* Do we care about the CreateAction in any other cases? */
918 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
919 *pOplock |= CIFS_CREATE_ACTION;
920 if(pfile_info) {
921 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
922 36 /* CreationTime to Attributes */);
923 /* the file_info buf is endian converted by caller */
924 pfile_info->AllocationSize = pSMBr->AllocationSize;
925 pfile_info->EndOfFile = pSMBr->EndOfFile;
926 pfile_info->NumberOfLinks = cpu_to_le32(1);
927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 cifs_buf_release(pSMB);
931 if (rc == -EAGAIN)
932 goto openRetry;
933 return rc;
934}
935
936/* If no buffer passed in, then caller wants to do the copy
937 as in the case of readpages so the SMB buffer must be
938 freed by the caller */
939
940int
941CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
942 const int netfid, const unsigned int count,
943 const __u64 lseek, unsigned int *nbytes, char **buf)
944{
945 int rc = -EACCES;
946 READ_REQ *pSMB = NULL;
947 READ_RSP *pSMBr = NULL;
948 char *pReadData = NULL;
949 int bytes_returned;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700950 int wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -0700953 if(tcon->ses->capabilities & CAP_LARGE_FILES)
954 wct = 12;
955 else
956 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 *nbytes = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700959 rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 (void **) &pSMBr);
961 if (rc)
962 return rc;
963
964 /* tcon and ses pointer are checked in smb_init */
965 if (tcon->ses->server == NULL)
966 return -ECONNABORTED;
967
968 pSMB->AndXCommand = 0xFF; /* none */
969 pSMB->Fid = netfid;
970 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700971 if(wct == 12)
972 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
973 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
974 return -EIO;
975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 pSMB->Remaining = 0;
977 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
978 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700979 if(wct == 12)
980 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
981 else {
982 /* old style read */
983 struct smb_com_readx_req * pSMBW =
984 (struct smb_com_readx_req *)pSMB;
985 pSMBW->ByteCount = 0;
986 }
987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700990 cifs_stats_inc(&tcon->num_reads);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (rc) {
992 cERROR(1, ("Send error in read = %d", rc));
993 } else {
994 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
995 data_length = data_length << 16;
996 data_length += le16_to_cpu(pSMBr->DataLength);
997 *nbytes = data_length;
998
999 /*check that DataLength would not go beyond end of SMB */
1000 if ((data_length > CIFSMaxBufSize)
1001 || (data_length > count)) {
1002 cFYI(1,("bad length %d for count %d",data_length,count));
1003 rc = -EIO;
1004 *nbytes = 0;
1005 } else {
1006 pReadData =
1007 (char *) (&pSMBr->hdr.Protocol) +
1008 le16_to_cpu(pSMBr->DataOffset);
1009/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1010 cERROR(1,("Faulting on read rc = %d",rc));
1011 rc = -EFAULT;
1012 }*/ /* can not use copy_to_user when using page cache*/
1013 if(*buf)
1014 memcpy(*buf,pReadData,data_length);
1015 }
1016 }
1017 if(*buf)
1018 cifs_buf_release(pSMB);
1019 else
1020 *buf = (char *)pSMB;
1021
1022 /* Note: On -EAGAIN error only caller can retry on handle based calls
1023 since file handle passed in no longer valid */
1024 return rc;
1025}
1026
1027int
1028CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1029 const int netfid, const unsigned int count,
1030 const __u64 offset, unsigned int *nbytes, const char *buf,
1031 const char __user * ubuf, const int long_op)
1032{
1033 int rc = -EACCES;
1034 WRITE_REQ *pSMB = NULL;
1035 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001036 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 __u32 bytes_sent;
1038 __u16 byte_count;
1039
1040 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001041 if(tcon->ses == NULL)
1042 return -ECONNABORTED;
1043
1044 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1045 wct = 14;
1046 else
1047 wct = 12;
1048
1049 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 (void **) &pSMBr);
1051 if (rc)
1052 return rc;
1053 /* tcon and ses pointer are checked in smb_init */
1054 if (tcon->ses->server == NULL)
1055 return -ECONNABORTED;
1056
1057 pSMB->AndXCommand = 0xFF; /* none */
1058 pSMB->Fid = netfid;
1059 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001060 if(wct == 14)
1061 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1062 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1063 return -EIO;
1064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 pSMB->Reserved = 0xFFFFFFFF;
1066 pSMB->WriteMode = 0;
1067 pSMB->Remaining = 0;
1068
1069 /* Can increase buffer size if buffer is big enough in some cases - ie we
1070 can send more if LARGE_WRITE_X capability returned by the server and if
1071 our buffer is big enough or if we convert to iovecs on socket writes
1072 and eliminate the copy to the CIFS buffer */
1073 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1074 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1075 } else {
1076 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1077 & ~0xFF;
1078 }
1079
1080 if (bytes_sent > count)
1081 bytes_sent = count;
1082 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001083 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 if(buf)
1085 memcpy(pSMB->Data,buf,bytes_sent);
1086 else if(ubuf) {
1087 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1088 cifs_buf_release(pSMB);
1089 return -EFAULT;
1090 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001091 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 /* No buffer */
1093 cifs_buf_release(pSMB);
1094 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001095 } /* else setting file size with write of zero bytes */
1096 if(wct == 14)
1097 byte_count = bytes_sent + 1; /* pad */
1098 else /* wct == 12 */ {
1099 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1102 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001103 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001104
1105 if(wct == 14)
1106 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001107 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001108 struct smb_com_writex_req * pSMBW =
1109 (struct smb_com_writex_req *)pSMB;
1110 pSMBW->ByteCount = cpu_to_le16(byte_count);
1111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1114 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001115 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 if (rc) {
1117 cFYI(1, ("Send error in write = %d", rc));
1118 *nbytes = 0;
1119 } else {
1120 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1121 *nbytes = (*nbytes) << 16;
1122 *nbytes += le16_to_cpu(pSMBr->Count);
1123 }
1124
1125 cifs_buf_release(pSMB);
1126
1127 /* Note: On -EAGAIN error only caller can retry on handle based calls
1128 since file handle passed in no longer valid */
1129
1130 return rc;
1131}
1132
1133#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001134int
1135CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001137 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1138 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
1140 int rc = -EACCES;
1141 WRITE_REQ *pSMB = NULL;
Steve French8cc64c62005-10-03 13:49:43 -07001142 int bytes_returned, wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001143 int smb_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Steve French0c0ff092005-06-23 19:31:17 -05001145 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Steve French8cc64c62005-10-03 13:49:43 -07001146 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1147 wct = 14;
1148 else
1149 wct = 12;
1150 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 if (rc)
1152 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 /* tcon and ses pointer are checked in smb_init */
1154 if (tcon->ses->server == NULL)
1155 return -ECONNABORTED;
1156
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001157 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 pSMB->Fid = netfid;
1159 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001160 if(wct == 14)
1161 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1162 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1163 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 pSMB->Reserved = 0xFFFFFFFF;
1165 pSMB->WriteMode = 0;
1166 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 pSMB->DataOffset =
1169 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1170
Steve French3e844692005-10-03 13:37:24 -07001171 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1172 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001173 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001174 if(wct == 14)
1175 pSMB->hdr.smb_buf_length += count+1;
1176 else /* wct == 12 */
1177 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1178 if(wct == 14)
1179 pSMB->ByteCount = cpu_to_le16(count + 1);
1180 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1181 struct smb_com_writex_req * pSMBW =
1182 (struct smb_com_writex_req *)pSMB;
1183 pSMBW->ByteCount = cpu_to_le16(count + 5);
1184 }
Steve French3e844692005-10-03 13:37:24 -07001185 iov[0].iov_base = pSMB;
1186 iov[0].iov_len = smb_hdr_len + 4;
1187
1188 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned,
1189 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001190 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001192 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001194 } else {
1195 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1196 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1197 *nbytes = (*nbytes) << 16;
1198 *nbytes += le16_to_cpu(pSMBr->Count);
1199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 cifs_small_buf_release(pSMB);
1202
1203 /* Note: On -EAGAIN error only caller can retry on handle based calls
1204 since file handle passed in no longer valid */
1205
1206 return rc;
1207}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001208
1209
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210#endif /* CIFS_EXPERIMENTAL */
1211
1212int
1213CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1214 const __u16 smb_file_id, const __u64 len,
1215 const __u64 offset, const __u32 numUnlock,
1216 const __u32 numLock, const __u8 lockType, const int waitFlag)
1217{
1218 int rc = 0;
1219 LOCK_REQ *pSMB = NULL;
1220 LOCK_RSP *pSMBr = NULL;
1221 int bytes_returned;
1222 int timeout = 0;
1223 __u16 count;
1224
1225 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001226 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 if (rc)
1229 return rc;
1230
Steve French46810cb2005-04-28 22:41:09 -07001231 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1232
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1234 timeout = -1; /* no response expected */
1235 pSMB->Timeout = 0;
1236 } else if (waitFlag == TRUE) {
1237 timeout = 3; /* blocking operation, no timeout */
1238 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1239 } else {
1240 pSMB->Timeout = 0;
1241 }
1242
1243 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1244 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1245 pSMB->LockType = lockType;
1246 pSMB->AndXCommand = 0xFF; /* none */
1247 pSMB->Fid = smb_file_id; /* netfid stays le */
1248
1249 if((numLock != 0) || (numUnlock != 0)) {
1250 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1251 /* BB where to store pid high? */
1252 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1253 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1254 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1255 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1256 count = sizeof(LOCKING_ANDX_RANGE);
1257 } else {
1258 /* oplock break */
1259 count = 0;
1260 }
1261 pSMB->hdr.smb_buf_length += count;
1262 pSMB->ByteCount = cpu_to_le16(count);
1263
1264 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1265 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001266 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 if (rc) {
1268 cFYI(1, ("Send error in Lock = %d", rc));
1269 }
Steve French46810cb2005-04-28 22:41:09 -07001270 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
1272 /* Note: On -EAGAIN error only caller can retry on handle based calls
1273 since file handle passed in no longer valid */
1274 return rc;
1275}
1276
1277int
1278CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1279{
1280 int rc = 0;
1281 CLOSE_REQ *pSMB = NULL;
1282 CLOSE_RSP *pSMBr = NULL;
1283 int bytes_returned;
1284 cFYI(1, ("In CIFSSMBClose"));
1285
1286/* do not retry on dead session on close */
1287 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1288 if(rc == -EAGAIN)
1289 return 0;
1290 if (rc)
1291 return rc;
1292
1293 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1294
1295 pSMB->FileID = (__u16) smb_file_id;
1296 pSMB->LastWriteTime = 0;
1297 pSMB->ByteCount = 0;
1298 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1299 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001300 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 if (rc) {
1302 if(rc!=-EINTR) {
1303 /* EINTR is expected when user ctl-c to kill app */
1304 cERROR(1, ("Send error in Close = %d", rc));
1305 }
1306 }
1307
1308 cifs_small_buf_release(pSMB);
1309
1310 /* Since session is dead, file will be closed on server already */
1311 if(rc == -EAGAIN)
1312 rc = 0;
1313
1314 return rc;
1315}
1316
1317int
1318CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1319 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001320 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321{
1322 int rc = 0;
1323 RENAME_REQ *pSMB = NULL;
1324 RENAME_RSP *pSMBr = NULL;
1325 int bytes_returned;
1326 int name_len, name_len2;
1327 __u16 count;
1328
1329 cFYI(1, ("In CIFSSMBRename"));
1330renameRetry:
1331 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1332 (void **) &pSMBr);
1333 if (rc)
1334 return rc;
1335
1336 pSMB->BufferFormat = 0x04;
1337 pSMB->SearchAttributes =
1338 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1339 ATTR_DIRECTORY);
1340
1341 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1342 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001343 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001344 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 name_len++; /* trailing null */
1346 name_len *= 2;
1347 pSMB->OldFileName[name_len] = 0x04; /* pad */
1348 /* protocol requires ASCII signature byte on Unicode string */
1349 pSMB->OldFileName[name_len + 1] = 0x00;
1350 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001351 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001352 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1354 name_len2 *= 2; /* convert to bytes */
1355 } else { /* BB improve the check for buffer overruns BB */
1356 name_len = strnlen(fromName, PATH_MAX);
1357 name_len++; /* trailing null */
1358 strncpy(pSMB->OldFileName, fromName, name_len);
1359 name_len2 = strnlen(toName, PATH_MAX);
1360 name_len2++; /* trailing null */
1361 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1362 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1363 name_len2++; /* trailing null */
1364 name_len2++; /* signature byte */
1365 }
1366
1367 count = 1 /* 1st signature byte */ + name_len + name_len2;
1368 pSMB->hdr.smb_buf_length += count;
1369 pSMB->ByteCount = cpu_to_le16(count);
1370
1371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1372 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001373 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (rc) {
1375 cFYI(1, ("Send error in rename = %d", rc));
1376 }
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 cifs_buf_release(pSMB);
1379
1380 if (rc == -EAGAIN)
1381 goto renameRetry;
1382
1383 return rc;
1384}
1385
1386int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001387 int netfid, char * target_name,
1388 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389{
1390 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1391 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1392 struct set_file_rename * rename_info;
1393 char *data_offset;
1394 char dummy_string[30];
1395 int rc = 0;
1396 int bytes_returned = 0;
1397 int len_of_str;
1398 __u16 params, param_offset, offset, count, byte_count;
1399
1400 cFYI(1, ("Rename to File by handle"));
1401 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1402 (void **) &pSMBr);
1403 if (rc)
1404 return rc;
1405
1406 params = 6;
1407 pSMB->MaxSetupCount = 0;
1408 pSMB->Reserved = 0;
1409 pSMB->Flags = 0;
1410 pSMB->Timeout = 0;
1411 pSMB->Reserved2 = 0;
1412 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1413 offset = param_offset + params;
1414
1415 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1416 rename_info = (struct set_file_rename *) data_offset;
1417 pSMB->MaxParameterCount = cpu_to_le16(2);
1418 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1419 pSMB->SetupCount = 1;
1420 pSMB->Reserved3 = 0;
1421 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1422 byte_count = 3 /* pad */ + params;
1423 pSMB->ParameterCount = cpu_to_le16(params);
1424 pSMB->TotalParameterCount = pSMB->ParameterCount;
1425 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1426 pSMB->DataOffset = cpu_to_le16(offset);
1427 /* construct random name ".cifs_tmp<inodenum><mid>" */
1428 rename_info->overwrite = cpu_to_le32(1);
1429 rename_info->root_fid = 0;
1430 /* unicode only call */
1431 if(target_name == NULL) {
1432 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001433 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001434 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001436 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001437 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 }
1439 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1440 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1441 byte_count += count;
1442 pSMB->DataCount = cpu_to_le16(count);
1443 pSMB->TotalDataCount = pSMB->DataCount;
1444 pSMB->Fid = netfid;
1445 pSMB->InformationLevel =
1446 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1447 pSMB->Reserved4 = 0;
1448 pSMB->hdr.smb_buf_length += byte_count;
1449 pSMB->ByteCount = cpu_to_le16(byte_count);
1450 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1451 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001452 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (rc) {
1454 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1455 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001456
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 cifs_buf_release(pSMB);
1458
1459 /* Note: On -EAGAIN error only caller can retry on handle based calls
1460 since file handle passed in no longer valid */
1461
1462 return rc;
1463}
1464
1465int
1466CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1467 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001468 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469{
1470 int rc = 0;
1471 COPY_REQ *pSMB = NULL;
1472 COPY_RSP *pSMBr = NULL;
1473 int bytes_returned;
1474 int name_len, name_len2;
1475 __u16 count;
1476
1477 cFYI(1, ("In CIFSSMBCopy"));
1478copyRetry:
1479 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1480 (void **) &pSMBr);
1481 if (rc)
1482 return rc;
1483
1484 pSMB->BufferFormat = 0x04;
1485 pSMB->Tid2 = target_tid;
1486
1487 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1488
1489 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001490 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001491 fromName, PATH_MAX, nls_codepage,
1492 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 name_len++; /* trailing null */
1494 name_len *= 2;
1495 pSMB->OldFileName[name_len] = 0x04; /* pad */
1496 /* protocol requires ASCII signature byte on Unicode string */
1497 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001498 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001499 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1501 name_len2 *= 2; /* convert to bytes */
1502 } else { /* BB improve the check for buffer overruns BB */
1503 name_len = strnlen(fromName, PATH_MAX);
1504 name_len++; /* trailing null */
1505 strncpy(pSMB->OldFileName, fromName, name_len);
1506 name_len2 = strnlen(toName, PATH_MAX);
1507 name_len2++; /* trailing null */
1508 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1509 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1510 name_len2++; /* trailing null */
1511 name_len2++; /* signature byte */
1512 }
1513
1514 count = 1 /* 1st signature byte */ + name_len + name_len2;
1515 pSMB->hdr.smb_buf_length += count;
1516 pSMB->ByteCount = cpu_to_le16(count);
1517
1518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1519 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1520 if (rc) {
1521 cFYI(1, ("Send error in copy = %d with %d files copied",
1522 rc, le16_to_cpu(pSMBr->CopyCount)));
1523 }
1524 if (pSMB)
1525 cifs_buf_release(pSMB);
1526
1527 if (rc == -EAGAIN)
1528 goto copyRetry;
1529
1530 return rc;
1531}
1532
1533int
1534CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1535 const char *fromName, const char *toName,
1536 const struct nls_table *nls_codepage)
1537{
1538 TRANSACTION2_SPI_REQ *pSMB = NULL;
1539 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1540 char *data_offset;
1541 int name_len;
1542 int name_len_target;
1543 int rc = 0;
1544 int bytes_returned = 0;
1545 __u16 params, param_offset, offset, byte_count;
1546
1547 cFYI(1, ("In Symlink Unix style"));
1548createSymLinkRetry:
1549 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1550 (void **) &pSMBr);
1551 if (rc)
1552 return rc;
1553
1554 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1555 name_len =
1556 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1557 /* find define for this maxpathcomponent */
1558 , nls_codepage);
1559 name_len++; /* trailing null */
1560 name_len *= 2;
1561
1562 } else { /* BB improve the check for buffer overruns BB */
1563 name_len = strnlen(fromName, PATH_MAX);
1564 name_len++; /* trailing null */
1565 strncpy(pSMB->FileName, fromName, name_len);
1566 }
1567 params = 6 + name_len;
1568 pSMB->MaxSetupCount = 0;
1569 pSMB->Reserved = 0;
1570 pSMB->Flags = 0;
1571 pSMB->Timeout = 0;
1572 pSMB->Reserved2 = 0;
1573 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1574 InformationLevel) - 4;
1575 offset = param_offset + params;
1576
1577 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1578 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1579 name_len_target =
1580 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1581 /* find define for this maxpathcomponent */
1582 , nls_codepage);
1583 name_len_target++; /* trailing null */
1584 name_len_target *= 2;
1585 } else { /* BB improve the check for buffer overruns BB */
1586 name_len_target = strnlen(toName, PATH_MAX);
1587 name_len_target++; /* trailing null */
1588 strncpy(data_offset, toName, name_len_target);
1589 }
1590
1591 pSMB->MaxParameterCount = cpu_to_le16(2);
1592 /* BB find exact max on data count below from sess */
1593 pSMB->MaxDataCount = cpu_to_le16(1000);
1594 pSMB->SetupCount = 1;
1595 pSMB->Reserved3 = 0;
1596 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1597 byte_count = 3 /* pad */ + params + name_len_target;
1598 pSMB->DataCount = cpu_to_le16(name_len_target);
1599 pSMB->ParameterCount = cpu_to_le16(params);
1600 pSMB->TotalDataCount = pSMB->DataCount;
1601 pSMB->TotalParameterCount = pSMB->ParameterCount;
1602 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1603 pSMB->DataOffset = cpu_to_le16(offset);
1604 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1605 pSMB->Reserved4 = 0;
1606 pSMB->hdr.smb_buf_length += byte_count;
1607 pSMB->ByteCount = cpu_to_le16(byte_count);
1608 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1609 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001610 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 if (rc) {
1612 cFYI(1,
1613 ("Send error in SetPathInfo (create symlink) = %d",
1614 rc));
1615 }
1616
1617 if (pSMB)
1618 cifs_buf_release(pSMB);
1619
1620 if (rc == -EAGAIN)
1621 goto createSymLinkRetry;
1622
1623 return rc;
1624}
1625
1626int
1627CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1628 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001629 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630{
1631 TRANSACTION2_SPI_REQ *pSMB = NULL;
1632 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1633 char *data_offset;
1634 int name_len;
1635 int name_len_target;
1636 int rc = 0;
1637 int bytes_returned = 0;
1638 __u16 params, param_offset, offset, byte_count;
1639
1640 cFYI(1, ("In Create Hard link Unix style"));
1641createHardLinkRetry:
1642 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1643 (void **) &pSMBr);
1644 if (rc)
1645 return rc;
1646
1647 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001648 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001649 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 name_len++; /* trailing null */
1651 name_len *= 2;
1652
1653 } else { /* BB improve the check for buffer overruns BB */
1654 name_len = strnlen(toName, PATH_MAX);
1655 name_len++; /* trailing null */
1656 strncpy(pSMB->FileName, toName, name_len);
1657 }
1658 params = 6 + name_len;
1659 pSMB->MaxSetupCount = 0;
1660 pSMB->Reserved = 0;
1661 pSMB->Flags = 0;
1662 pSMB->Timeout = 0;
1663 pSMB->Reserved2 = 0;
1664 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1665 InformationLevel) - 4;
1666 offset = param_offset + params;
1667
1668 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1669 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1670 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001671 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001672 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 name_len_target++; /* trailing null */
1674 name_len_target *= 2;
1675 } else { /* BB improve the check for buffer overruns BB */
1676 name_len_target = strnlen(fromName, PATH_MAX);
1677 name_len_target++; /* trailing null */
1678 strncpy(data_offset, fromName, name_len_target);
1679 }
1680
1681 pSMB->MaxParameterCount = cpu_to_le16(2);
1682 /* BB find exact max on data count below from sess*/
1683 pSMB->MaxDataCount = cpu_to_le16(1000);
1684 pSMB->SetupCount = 1;
1685 pSMB->Reserved3 = 0;
1686 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1687 byte_count = 3 /* pad */ + params + name_len_target;
1688 pSMB->ParameterCount = cpu_to_le16(params);
1689 pSMB->TotalParameterCount = pSMB->ParameterCount;
1690 pSMB->DataCount = cpu_to_le16(name_len_target);
1691 pSMB->TotalDataCount = pSMB->DataCount;
1692 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1693 pSMB->DataOffset = cpu_to_le16(offset);
1694 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1695 pSMB->Reserved4 = 0;
1696 pSMB->hdr.smb_buf_length += byte_count;
1697 pSMB->ByteCount = cpu_to_le16(byte_count);
1698 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1699 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001700 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (rc) {
1702 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1703 }
1704
1705 cifs_buf_release(pSMB);
1706 if (rc == -EAGAIN)
1707 goto createHardLinkRetry;
1708
1709 return rc;
1710}
1711
1712int
1713CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1714 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001715 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716{
1717 int rc = 0;
1718 NT_RENAME_REQ *pSMB = NULL;
1719 RENAME_RSP *pSMBr = NULL;
1720 int bytes_returned;
1721 int name_len, name_len2;
1722 __u16 count;
1723
1724 cFYI(1, ("In CIFSCreateHardLink"));
1725winCreateHardLinkRetry:
1726
1727 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1728 (void **) &pSMBr);
1729 if (rc)
1730 return rc;
1731
1732 pSMB->SearchAttributes =
1733 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1734 ATTR_DIRECTORY);
1735 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1736 pSMB->ClusterCount = 0;
1737
1738 pSMB->BufferFormat = 0x04;
1739
1740 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1741 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001742 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001743 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 name_len++; /* trailing null */
1745 name_len *= 2;
1746 pSMB->OldFileName[name_len] = 0; /* pad */
1747 pSMB->OldFileName[name_len + 1] = 0x04;
1748 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001749 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001750 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1752 name_len2 *= 2; /* convert to bytes */
1753 } else { /* BB improve the check for buffer overruns BB */
1754 name_len = strnlen(fromName, PATH_MAX);
1755 name_len++; /* trailing null */
1756 strncpy(pSMB->OldFileName, fromName, name_len);
1757 name_len2 = strnlen(toName, PATH_MAX);
1758 name_len2++; /* trailing null */
1759 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1760 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1761 name_len2++; /* trailing null */
1762 name_len2++; /* signature byte */
1763 }
1764
1765 count = 1 /* string type byte */ + name_len + name_len2;
1766 pSMB->hdr.smb_buf_length += count;
1767 pSMB->ByteCount = cpu_to_le16(count);
1768
1769 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1770 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001771 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 if (rc) {
1773 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1774 }
1775 cifs_buf_release(pSMB);
1776 if (rc == -EAGAIN)
1777 goto winCreateHardLinkRetry;
1778
1779 return rc;
1780}
1781
1782int
1783CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1784 const unsigned char *searchName,
1785 char *symlinkinfo, const int buflen,
1786 const struct nls_table *nls_codepage)
1787{
1788/* SMB_QUERY_FILE_UNIX_LINK */
1789 TRANSACTION2_QPI_REQ *pSMB = NULL;
1790 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1791 int rc = 0;
1792 int bytes_returned;
1793 int name_len;
1794 __u16 params, byte_count;
1795
1796 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1797
1798querySymLinkRetry:
1799 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1800 (void **) &pSMBr);
1801 if (rc)
1802 return rc;
1803
1804 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1805 name_len =
1806 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1807 /* find define for this maxpathcomponent */
1808 , nls_codepage);
1809 name_len++; /* trailing null */
1810 name_len *= 2;
1811 } else { /* BB improve the check for buffer overruns BB */
1812 name_len = strnlen(searchName, PATH_MAX);
1813 name_len++; /* trailing null */
1814 strncpy(pSMB->FileName, searchName, name_len);
1815 }
1816
1817 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1818 pSMB->TotalDataCount = 0;
1819 pSMB->MaxParameterCount = cpu_to_le16(2);
1820 /* BB find exact max data count below from sess structure BB */
1821 pSMB->MaxDataCount = cpu_to_le16(4000);
1822 pSMB->MaxSetupCount = 0;
1823 pSMB->Reserved = 0;
1824 pSMB->Flags = 0;
1825 pSMB->Timeout = 0;
1826 pSMB->Reserved2 = 0;
1827 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1828 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1829 pSMB->DataCount = 0;
1830 pSMB->DataOffset = 0;
1831 pSMB->SetupCount = 1;
1832 pSMB->Reserved3 = 0;
1833 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1834 byte_count = params + 1 /* pad */ ;
1835 pSMB->TotalParameterCount = cpu_to_le16(params);
1836 pSMB->ParameterCount = pSMB->TotalParameterCount;
1837 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1838 pSMB->Reserved4 = 0;
1839 pSMB->hdr.smb_buf_length += byte_count;
1840 pSMB->ByteCount = cpu_to_le16(byte_count);
1841
1842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1844 if (rc) {
1845 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1846 } else {
1847 /* decode response */
1848
1849 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1850 if (rc || (pSMBr->ByteCount < 2))
1851 /* BB also check enough total bytes returned */
1852 rc = -EIO; /* bad smb */
1853 else {
1854 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1855 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1856
1857 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1858 name_len = UniStrnlen((wchar_t *) ((char *)
1859 &pSMBr->hdr.Protocol +data_offset),
1860 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001861 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 cifs_strfromUCS_le(symlinkinfo,
1863 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1864 data_offset),
1865 name_len, nls_codepage);
1866 } else {
1867 strncpy(symlinkinfo,
1868 (char *) &pSMBr->hdr.Protocol +
1869 data_offset,
1870 min_t(const int, buflen, count));
1871 }
1872 symlinkinfo[buflen] = 0;
1873 /* just in case so calling code does not go off the end of buffer */
1874 }
1875 }
1876 cifs_buf_release(pSMB);
1877 if (rc == -EAGAIN)
1878 goto querySymLinkRetry;
1879 return rc;
1880}
1881
1882int
1883CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1884 const unsigned char *searchName,
1885 char *symlinkinfo, const int buflen,__u16 fid,
1886 const struct nls_table *nls_codepage)
1887{
1888 int rc = 0;
1889 int bytes_returned;
1890 int name_len;
1891 struct smb_com_transaction_ioctl_req * pSMB;
1892 struct smb_com_transaction_ioctl_rsp * pSMBr;
1893
1894 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1895 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1896 (void **) &pSMBr);
1897 if (rc)
1898 return rc;
1899
1900 pSMB->TotalParameterCount = 0 ;
1901 pSMB->TotalDataCount = 0;
1902 pSMB->MaxParameterCount = cpu_to_le32(2);
1903 /* BB find exact data count max from sess structure BB */
1904 pSMB->MaxDataCount = cpu_to_le32(4000);
1905 pSMB->MaxSetupCount = 4;
1906 pSMB->Reserved = 0;
1907 pSMB->ParameterOffset = 0;
1908 pSMB->DataCount = 0;
1909 pSMB->DataOffset = 0;
1910 pSMB->SetupCount = 4;
1911 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1912 pSMB->ParameterCount = pSMB->TotalParameterCount;
1913 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1914 pSMB->IsFsctl = 1; /* FSCTL */
1915 pSMB->IsRootFlag = 0;
1916 pSMB->Fid = fid; /* file handle always le */
1917 pSMB->ByteCount = 0;
1918
1919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1921 if (rc) {
1922 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1923 } else { /* decode response */
1924 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1925 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1926 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1927 /* BB also check enough total bytes returned */
1928 rc = -EIO; /* bad smb */
1929 else {
1930 if(data_count && (data_count < 2048)) {
1931 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1932
1933 struct reparse_data * reparse_buf = (struct reparse_data *)
1934 ((char *)&pSMBr->hdr.Protocol + data_offset);
1935 if((char*)reparse_buf >= end_of_smb) {
1936 rc = -EIO;
1937 goto qreparse_out;
1938 }
1939 if((reparse_buf->LinkNamesBuf +
1940 reparse_buf->TargetNameOffset +
1941 reparse_buf->TargetNameLen) >
1942 end_of_smb) {
1943 cFYI(1,("reparse buf extended beyond SMB"));
1944 rc = -EIO;
1945 goto qreparse_out;
1946 }
1947
1948 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1949 name_len = UniStrnlen((wchar_t *)
1950 (reparse_buf->LinkNamesBuf +
1951 reparse_buf->TargetNameOffset),
1952 min(buflen/2, reparse_buf->TargetNameLen / 2));
1953 cifs_strfromUCS_le(symlinkinfo,
1954 (wchar_t *) (reparse_buf->LinkNamesBuf +
1955 reparse_buf->TargetNameOffset),
1956 name_len, nls_codepage);
1957 } else { /* ASCII names */
1958 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1959 reparse_buf->TargetNameOffset,
1960 min_t(const int, buflen, reparse_buf->TargetNameLen));
1961 }
1962 } else {
1963 rc = -EIO;
1964 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1965 }
1966 symlinkinfo[buflen] = 0; /* just in case so the caller
1967 does not go off the end of the buffer */
1968 cFYI(1,("readlink result - %s ",symlinkinfo));
1969 }
1970 }
1971qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001972 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
1974 /* Note: On -EAGAIN error only caller can retry on handle based calls
1975 since file handle passed in no longer valid */
1976
1977 return rc;
1978}
1979
1980#ifdef CONFIG_CIFS_POSIX
1981
1982/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1983static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1984{
1985 /* u8 cifs fields do not need le conversion */
1986 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1987 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1988 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1989 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1990
1991 return;
1992}
1993
1994/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07001995static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1996 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997{
1998 int size = 0;
1999 int i;
2000 __u16 count;
2001 struct cifs_posix_ace * pACE;
2002 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2003 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2004
2005 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2006 return -EOPNOTSUPP;
2007
2008 if(acl_type & ACL_TYPE_ACCESS) {
2009 count = le16_to_cpu(cifs_acl->access_entry_count);
2010 pACE = &cifs_acl->ace_array[0];
2011 size = sizeof(struct cifs_posix_acl);
2012 size += sizeof(struct cifs_posix_ace) * count;
2013 /* check if we would go beyond end of SMB */
2014 if(size_of_data_area < size) {
2015 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2016 return -EINVAL;
2017 }
2018 } else if(acl_type & ACL_TYPE_DEFAULT) {
2019 count = le16_to_cpu(cifs_acl->access_entry_count);
2020 size = sizeof(struct cifs_posix_acl);
2021 size += sizeof(struct cifs_posix_ace) * count;
2022/* skip past access ACEs to get to default ACEs */
2023 pACE = &cifs_acl->ace_array[count];
2024 count = le16_to_cpu(cifs_acl->default_entry_count);
2025 size += sizeof(struct cifs_posix_ace) * count;
2026 /* check if we would go beyond end of SMB */
2027 if(size_of_data_area < size)
2028 return -EINVAL;
2029 } else {
2030 /* illegal type */
2031 return -EINVAL;
2032 }
2033
2034 size = posix_acl_xattr_size(count);
2035 if((buflen == 0) || (local_acl == NULL)) {
2036 /* used to query ACL EA size */
2037 } else if(size > buflen) {
2038 return -ERANGE;
2039 } else /* buffer big enough */ {
2040 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
2041 for(i = 0;i < count ;i++) {
2042 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2043 pACE ++;
2044 }
2045 }
2046 return size;
2047}
2048
2049static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2050 const posix_acl_xattr_entry * local_ace)
2051{
2052 __u16 rc = 0; /* 0 = ACL converted ok */
2053
2054 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
2055 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
2056 /* BB is there a better way to handle the large uid? */
2057 if(local_ace->e_id == -1) {
2058 /* Probably no need to le convert -1 on any arch but can not hurt */
2059 cifs_ace->cifs_uid = cpu_to_le64(-1);
2060 } else
2061 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
2062 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2063 return rc;
2064}
2065
2066/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2067static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2068 const int acl_type)
2069{
2070 __u16 rc = 0;
2071 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2072 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2073 int count;
2074 int i;
2075
2076 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2077 return 0;
2078
2079 count = posix_acl_xattr_count((size_t)buflen);
2080 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2081 count,buflen,local_acl->a_version));
2082 if(local_acl->a_version != 2) {
2083 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
2084 return 0;
2085 }
2086 cifs_acl->version = cpu_to_le16(1);
2087 if(acl_type == ACL_TYPE_ACCESS)
2088 cifs_acl->access_entry_count = count;
2089 else if(acl_type == ACL_TYPE_DEFAULT)
2090 cifs_acl->default_entry_count = count;
2091 else {
2092 cFYI(1,("unknown ACL type %d",acl_type));
2093 return 0;
2094 }
2095 for(i=0;i<count;i++) {
2096 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2097 &local_acl->a_entries[i]);
2098 if(rc != 0) {
2099 /* ACE not converted */
2100 break;
2101 }
2102 }
2103 if(rc == 0) {
2104 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2105 rc += sizeof(struct cifs_posix_acl);
2106 /* BB add check to make sure ACL does not overflow SMB */
2107 }
2108 return rc;
2109}
2110
2111int
2112CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2113 const unsigned char *searchName,
2114 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002115 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116{
2117/* SMB_QUERY_POSIX_ACL */
2118 TRANSACTION2_QPI_REQ *pSMB = NULL;
2119 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2120 int rc = 0;
2121 int bytes_returned;
2122 int name_len;
2123 __u16 params, byte_count;
2124
2125 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2126
2127queryAclRetry:
2128 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2129 (void **) &pSMBr);
2130 if (rc)
2131 return rc;
2132
2133 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2134 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002135 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002136 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 name_len++; /* trailing null */
2138 name_len *= 2;
2139 pSMB->FileName[name_len] = 0;
2140 pSMB->FileName[name_len+1] = 0;
2141 } else { /* BB improve the check for buffer overruns BB */
2142 name_len = strnlen(searchName, PATH_MAX);
2143 name_len++; /* trailing null */
2144 strncpy(pSMB->FileName, searchName, name_len);
2145 }
2146
2147 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2148 pSMB->TotalDataCount = 0;
2149 pSMB->MaxParameterCount = cpu_to_le16(2);
2150 /* BB find exact max data count below from sess structure BB */
2151 pSMB->MaxDataCount = cpu_to_le16(4000);
2152 pSMB->MaxSetupCount = 0;
2153 pSMB->Reserved = 0;
2154 pSMB->Flags = 0;
2155 pSMB->Timeout = 0;
2156 pSMB->Reserved2 = 0;
2157 pSMB->ParameterOffset = cpu_to_le16(
2158 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2159 pSMB->DataCount = 0;
2160 pSMB->DataOffset = 0;
2161 pSMB->SetupCount = 1;
2162 pSMB->Reserved3 = 0;
2163 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2164 byte_count = params + 1 /* pad */ ;
2165 pSMB->TotalParameterCount = cpu_to_le16(params);
2166 pSMB->ParameterCount = pSMB->TotalParameterCount;
2167 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2168 pSMB->Reserved4 = 0;
2169 pSMB->hdr.smb_buf_length += byte_count;
2170 pSMB->ByteCount = cpu_to_le16(byte_count);
2171
2172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2174 if (rc) {
2175 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2176 } else {
2177 /* decode response */
2178
2179 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2180 if (rc || (pSMBr->ByteCount < 2))
2181 /* BB also check enough total bytes returned */
2182 rc = -EIO; /* bad smb */
2183 else {
2184 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2185 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2186 rc = cifs_copy_posix_acl(acl_inf,
2187 (char *)&pSMBr->hdr.Protocol+data_offset,
2188 buflen,acl_type,count);
2189 }
2190 }
2191 cifs_buf_release(pSMB);
2192 if (rc == -EAGAIN)
2193 goto queryAclRetry;
2194 return rc;
2195}
2196
2197int
2198CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2199 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002200 const char *local_acl, const int buflen,
2201 const int acl_type,
2202 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203{
2204 struct smb_com_transaction2_spi_req *pSMB = NULL;
2205 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2206 char *parm_data;
2207 int name_len;
2208 int rc = 0;
2209 int bytes_returned = 0;
2210 __u16 params, byte_count, data_count, param_offset, offset;
2211
2212 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2213setAclRetry:
2214 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2215 (void **) &pSMBr);
2216 if (rc)
2217 return rc;
2218 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2219 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002220 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002221 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 name_len++; /* trailing null */
2223 name_len *= 2;
2224 } else { /* BB improve the check for buffer overruns BB */
2225 name_len = strnlen(fileName, PATH_MAX);
2226 name_len++; /* trailing null */
2227 strncpy(pSMB->FileName, fileName, name_len);
2228 }
2229 params = 6 + name_len;
2230 pSMB->MaxParameterCount = cpu_to_le16(2);
2231 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2232 pSMB->MaxSetupCount = 0;
2233 pSMB->Reserved = 0;
2234 pSMB->Flags = 0;
2235 pSMB->Timeout = 0;
2236 pSMB->Reserved2 = 0;
2237 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2238 InformationLevel) - 4;
2239 offset = param_offset + params;
2240 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2241 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2242
2243 /* convert to on the wire format for POSIX ACL */
2244 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2245
2246 if(data_count == 0) {
2247 rc = -EOPNOTSUPP;
2248 goto setACLerrorExit;
2249 }
2250 pSMB->DataOffset = cpu_to_le16(offset);
2251 pSMB->SetupCount = 1;
2252 pSMB->Reserved3 = 0;
2253 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2254 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2255 byte_count = 3 /* pad */ + params + data_count;
2256 pSMB->DataCount = cpu_to_le16(data_count);
2257 pSMB->TotalDataCount = pSMB->DataCount;
2258 pSMB->ParameterCount = cpu_to_le16(params);
2259 pSMB->TotalParameterCount = pSMB->ParameterCount;
2260 pSMB->Reserved4 = 0;
2261 pSMB->hdr.smb_buf_length += byte_count;
2262 pSMB->ByteCount = cpu_to_le16(byte_count);
2263 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2264 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2265 if (rc) {
2266 cFYI(1, ("Set POSIX ACL returned %d", rc));
2267 }
2268
2269setACLerrorExit:
2270 cifs_buf_release(pSMB);
2271 if (rc == -EAGAIN)
2272 goto setAclRetry;
2273 return rc;
2274}
2275
Steve Frenchf654bac2005-04-28 22:41:04 -07002276/* BB fix tabs in this function FIXME BB */
2277int
2278CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2279 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2280{
2281 int rc = 0;
2282 struct smb_t2_qfi_req *pSMB = NULL;
2283 struct smb_t2_qfi_rsp *pSMBr = NULL;
2284 int bytes_returned;
2285 __u16 params, byte_count;
2286
2287 cFYI(1,("In GetExtAttr"));
2288 if(tcon == NULL)
2289 return -ENODEV;
2290
2291GetExtAttrRetry:
2292 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2293 (void **) &pSMBr);
2294 if (rc)
2295 return rc;
2296
Steve Frenchc67593a2005-04-28 22:41:04 -07002297 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002298 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002299 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002300 /* BB find exact max data count below from sess structure BB */
2301 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2302 pSMB->t2.MaxSetupCount = 0;
2303 pSMB->t2.Reserved = 0;
2304 pSMB->t2.Flags = 0;
2305 pSMB->t2.Timeout = 0;
2306 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002307 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2308 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002309 pSMB->t2.DataCount = 0;
2310 pSMB->t2.DataOffset = 0;
2311 pSMB->t2.SetupCount = 1;
2312 pSMB->t2.Reserved3 = 0;
2313 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002314 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002315 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2316 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2317 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002318 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002319 pSMB->Fid = netfid;
2320 pSMB->hdr.smb_buf_length += byte_count;
2321 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2322
2323 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2324 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2325 if (rc) {
2326 cFYI(1, ("error %d in GetExtAttr", rc));
2327 } else {
2328 /* decode response */
2329 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2330 if (rc || (pSMBr->ByteCount < 2))
2331 /* BB also check enough total bytes returned */
2332 /* If rc should we check for EOPNOSUPP and
2333 disable the srvino flag? or in caller? */
2334 rc = -EIO; /* bad smb */
2335 else {
2336 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2337 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2338 struct file_chattr_info * pfinfo;
2339 /* BB Do we need a cast or hash here ? */
2340 if(count != 16) {
2341 cFYI(1, ("Illegal size ret in GetExtAttr"));
2342 rc = -EIO;
2343 goto GetExtAttrOut;
2344 }
2345 pfinfo = (struct file_chattr_info *)
2346 (data_offset + (char *) &pSMBr->hdr.Protocol);
2347 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2348 *pMask = le64_to_cpu(pfinfo->mask);
2349 }
2350 }
2351GetExtAttrOut:
2352 cifs_buf_release(pSMB);
2353 if (rc == -EAGAIN)
2354 goto GetExtAttrRetry;
2355 return rc;
2356}
2357
2358
2359#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Steve French6b8edfe2005-08-23 20:26:03 -07002361/* Legacy Query Path Information call for lookup to old servers such
2362 as Win9x/WinME */
2363int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2364 const unsigned char *searchName,
2365 FILE_ALL_INFO * pFinfo,
2366 const struct nls_table *nls_codepage, int remap)
2367{
2368 QUERY_INFORMATION_REQ * pSMB;
2369 QUERY_INFORMATION_RSP * pSMBr;
2370 int rc = 0;
2371 int bytes_returned;
2372 int name_len;
2373
2374 cFYI(1, ("In SMBQPath path %s", searchName));
2375QInfRetry:
2376 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2377 (void **) &pSMBr);
2378 if (rc)
2379 return rc;
2380
2381 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2382 name_len =
2383 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2384 PATH_MAX, nls_codepage, remap);
2385 name_len++; /* trailing null */
2386 name_len *= 2;
2387 } else {
2388 name_len = strnlen(searchName, PATH_MAX);
2389 name_len++; /* trailing null */
2390 strncpy(pSMB->FileName, searchName, name_len);
2391 }
2392 pSMB->BufferFormat = 0x04;
2393 name_len++; /* account for buffer type byte */
2394 pSMB->hdr.smb_buf_length += (__u16) name_len;
2395 pSMB->ByteCount = cpu_to_le16(name_len);
2396
2397 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2398 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2399 if (rc) {
2400 cFYI(1, ("Send error in QueryInfo = %d", rc));
2401 } else if (pFinfo) { /* decode response */
2402 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002403 pFinfo->AllocationSize =
2404 cpu_to_le64(le32_to_cpu(pSMBr->size));
2405 pFinfo->EndOfFile = pFinfo->AllocationSize;
2406 pFinfo->Attributes =
2407 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002408 } else
2409 rc = -EIO; /* bad buffer passed in */
2410
2411 cifs_buf_release(pSMB);
2412
2413 if (rc == -EAGAIN)
2414 goto QInfRetry;
2415
2416 return rc;
2417}
2418
2419
2420
2421
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422int
2423CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2424 const unsigned char *searchName,
2425 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002426 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427{
2428/* level 263 SMB_QUERY_FILE_ALL_INFO */
2429 TRANSACTION2_QPI_REQ *pSMB = NULL;
2430 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2431 int rc = 0;
2432 int bytes_returned;
2433 int name_len;
2434 __u16 params, byte_count;
2435
2436/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2437QPathInfoRetry:
2438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2439 (void **) &pSMBr);
2440 if (rc)
2441 return rc;
2442
2443 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2444 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002445 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002446 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 name_len++; /* trailing null */
2448 name_len *= 2;
2449 } else { /* BB improve the check for buffer overruns BB */
2450 name_len = strnlen(searchName, PATH_MAX);
2451 name_len++; /* trailing null */
2452 strncpy(pSMB->FileName, searchName, name_len);
2453 }
2454
2455 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2456 pSMB->TotalDataCount = 0;
2457 pSMB->MaxParameterCount = cpu_to_le16(2);
2458 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2459 pSMB->MaxSetupCount = 0;
2460 pSMB->Reserved = 0;
2461 pSMB->Flags = 0;
2462 pSMB->Timeout = 0;
2463 pSMB->Reserved2 = 0;
2464 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2465 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2466 pSMB->DataCount = 0;
2467 pSMB->DataOffset = 0;
2468 pSMB->SetupCount = 1;
2469 pSMB->Reserved3 = 0;
2470 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2471 byte_count = params + 1 /* pad */ ;
2472 pSMB->TotalParameterCount = cpu_to_le16(params);
2473 pSMB->ParameterCount = pSMB->TotalParameterCount;
2474 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2475 pSMB->Reserved4 = 0;
2476 pSMB->hdr.smb_buf_length += byte_count;
2477 pSMB->ByteCount = cpu_to_le16(byte_count);
2478
2479 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2480 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2481 if (rc) {
2482 cFYI(1, ("Send error in QPathInfo = %d", rc));
2483 } else { /* decode response */
2484 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2485
2486 if (rc || (pSMBr->ByteCount < 40))
2487 rc = -EIO; /* bad smb */
2488 else if (pFindData){
2489 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2490 memcpy((char *) pFindData,
2491 (char *) &pSMBr->hdr.Protocol +
2492 data_offset, sizeof (FILE_ALL_INFO));
2493 } else
2494 rc = -ENOMEM;
2495 }
2496 cifs_buf_release(pSMB);
2497 if (rc == -EAGAIN)
2498 goto QPathInfoRetry;
2499
2500 return rc;
2501}
2502
2503int
2504CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2505 const unsigned char *searchName,
2506 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002507 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508{
2509/* SMB_QUERY_FILE_UNIX_BASIC */
2510 TRANSACTION2_QPI_REQ *pSMB = NULL;
2511 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2512 int rc = 0;
2513 int bytes_returned = 0;
2514 int name_len;
2515 __u16 params, byte_count;
2516
2517 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2518UnixQPathInfoRetry:
2519 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2520 (void **) &pSMBr);
2521 if (rc)
2522 return rc;
2523
2524 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2525 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002526 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002527 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 name_len++; /* trailing null */
2529 name_len *= 2;
2530 } else { /* BB improve the check for buffer overruns BB */
2531 name_len = strnlen(searchName, PATH_MAX);
2532 name_len++; /* trailing null */
2533 strncpy(pSMB->FileName, searchName, name_len);
2534 }
2535
2536 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2537 pSMB->TotalDataCount = 0;
2538 pSMB->MaxParameterCount = cpu_to_le16(2);
2539 /* BB find exact max SMB PDU from sess structure BB */
2540 pSMB->MaxDataCount = cpu_to_le16(4000);
2541 pSMB->MaxSetupCount = 0;
2542 pSMB->Reserved = 0;
2543 pSMB->Flags = 0;
2544 pSMB->Timeout = 0;
2545 pSMB->Reserved2 = 0;
2546 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2547 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2548 pSMB->DataCount = 0;
2549 pSMB->DataOffset = 0;
2550 pSMB->SetupCount = 1;
2551 pSMB->Reserved3 = 0;
2552 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2553 byte_count = params + 1 /* pad */ ;
2554 pSMB->TotalParameterCount = cpu_to_le16(params);
2555 pSMB->ParameterCount = pSMB->TotalParameterCount;
2556 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2557 pSMB->Reserved4 = 0;
2558 pSMB->hdr.smb_buf_length += byte_count;
2559 pSMB->ByteCount = cpu_to_le16(byte_count);
2560
2561 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2562 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2563 if (rc) {
2564 cFYI(1, ("Send error in QPathInfo = %d", rc));
2565 } else { /* decode response */
2566 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2567
2568 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2569 rc = -EIO; /* bad smb */
2570 } else {
2571 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2572 memcpy((char *) pFindData,
2573 (char *) &pSMBr->hdr.Protocol +
2574 data_offset,
2575 sizeof (FILE_UNIX_BASIC_INFO));
2576 }
2577 }
2578 cifs_buf_release(pSMB);
2579 if (rc == -EAGAIN)
2580 goto UnixQPathInfoRetry;
2581
2582 return rc;
2583}
2584
2585#if 0 /* function unused at present */
2586int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2587 const char *searchName, FILE_ALL_INFO * findData,
2588 const struct nls_table *nls_codepage)
2589{
2590/* level 257 SMB_ */
2591 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2592 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2593 int rc = 0;
2594 int bytes_returned;
2595 int name_len;
2596 __u16 params, byte_count;
2597
2598 cFYI(1, ("In FindUnique"));
2599findUniqueRetry:
2600 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2601 (void **) &pSMBr);
2602 if (rc)
2603 return rc;
2604
2605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2606 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002607 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 /* find define for this maxpathcomponent */
2609 , nls_codepage);
2610 name_len++; /* trailing null */
2611 name_len *= 2;
2612 } else { /* BB improve the check for buffer overruns BB */
2613 name_len = strnlen(searchName, PATH_MAX);
2614 name_len++; /* trailing null */
2615 strncpy(pSMB->FileName, searchName, name_len);
2616 }
2617
2618 params = 12 + name_len /* includes null */ ;
2619 pSMB->TotalDataCount = 0; /* no EAs */
2620 pSMB->MaxParameterCount = cpu_to_le16(2);
2621 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2622 pSMB->MaxSetupCount = 0;
2623 pSMB->Reserved = 0;
2624 pSMB->Flags = 0;
2625 pSMB->Timeout = 0;
2626 pSMB->Reserved2 = 0;
2627 pSMB->ParameterOffset = cpu_to_le16(
2628 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2629 pSMB->DataCount = 0;
2630 pSMB->DataOffset = 0;
2631 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2632 pSMB->Reserved3 = 0;
2633 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2634 byte_count = params + 1 /* pad */ ;
2635 pSMB->TotalParameterCount = cpu_to_le16(params);
2636 pSMB->ParameterCount = pSMB->TotalParameterCount;
2637 pSMB->SearchAttributes =
2638 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2639 ATTR_DIRECTORY);
2640 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2641 pSMB->SearchFlags = cpu_to_le16(1);
2642 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2643 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2644 pSMB->hdr.smb_buf_length += byte_count;
2645 pSMB->ByteCount = cpu_to_le16(byte_count);
2646
2647 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2648 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2649
2650 if (rc) {
2651 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2652 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07002653 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 /* BB fill in */
2655 }
2656
2657 cifs_buf_release(pSMB);
2658 if (rc == -EAGAIN)
2659 goto findUniqueRetry;
2660
2661 return rc;
2662}
2663#endif /* end unused (temporarily) function */
2664
2665/* xid, tcon, searchName and codepage are input parms, rest are returned */
2666int
2667CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2668 const char *searchName,
2669 const struct nls_table *nls_codepage,
2670 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002671 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672{
2673/* level 257 SMB_ */
2674 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2675 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2676 T2_FFIRST_RSP_PARMS * parms;
2677 int rc = 0;
2678 int bytes_returned = 0;
2679 int name_len;
2680 __u16 params, byte_count;
2681
Steve French737b7582005-04-28 22:41:06 -07002682 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
2684findFirstRetry:
2685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2686 (void **) &pSMBr);
2687 if (rc)
2688 return rc;
2689
2690 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2691 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002692 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002693 PATH_MAX, nls_codepage, remap);
2694 /* We can not add the asterik earlier in case
2695 it got remapped to 0xF03A as if it were part of the
2696 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002698 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002699 pSMB->FileName[name_len+1] = 0;
2700 pSMB->FileName[name_len+2] = '*';
2701 pSMB->FileName[name_len+3] = 0;
2702 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2704 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002705 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 } else { /* BB add check for overrun of SMB buf BB */
2707 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708/* BB fix here and in unicode clause above ie
2709 if(name_len > buffersize-header)
2710 free buffer exit; BB */
2711 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002712 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002713 pSMB->FileName[name_len+1] = '*';
2714 pSMB->FileName[name_len+2] = 0;
2715 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 }
2717
2718 params = 12 + name_len /* includes null */ ;
2719 pSMB->TotalDataCount = 0; /* no EAs */
2720 pSMB->MaxParameterCount = cpu_to_le16(10);
2721 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2722 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2723 pSMB->MaxSetupCount = 0;
2724 pSMB->Reserved = 0;
2725 pSMB->Flags = 0;
2726 pSMB->Timeout = 0;
2727 pSMB->Reserved2 = 0;
2728 byte_count = params + 1 /* pad */ ;
2729 pSMB->TotalParameterCount = cpu_to_le16(params);
2730 pSMB->ParameterCount = pSMB->TotalParameterCount;
2731 pSMB->ParameterOffset = cpu_to_le16(
2732 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2733 pSMB->DataCount = 0;
2734 pSMB->DataOffset = 0;
2735 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2736 pSMB->Reserved3 = 0;
2737 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2738 pSMB->SearchAttributes =
2739 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2740 ATTR_DIRECTORY);
2741 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2742 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2743 CIFS_SEARCH_RETURN_RESUME);
2744 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2745
2746 /* BB what should we set StorageType to? Does it matter? BB */
2747 pSMB->SearchStorageType = 0;
2748 pSMB->hdr.smb_buf_length += byte_count;
2749 pSMB->ByteCount = cpu_to_le16(byte_count);
2750
2751 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2752 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002753 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
Steve French1982c342005-08-17 12:38:22 -07002755 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 /* BB Add code to handle unsupported level rc */
2757 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002758
2759 if (pSMB)
2760 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761
2762 /* BB eventually could optimize out free and realloc of buf */
2763 /* for this case */
2764 if (rc == -EAGAIN)
2765 goto findFirstRetry;
2766 } else { /* decode response */
2767 /* BB remember to free buffer if error BB */
2768 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2769 if(rc == 0) {
2770 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2771 psrch_inf->unicode = TRUE;
2772 else
2773 psrch_inf->unicode = FALSE;
2774
2775 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2776 psrch_inf->srch_entries_start =
2777 (char *) &pSMBr->hdr.Protocol +
2778 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2780 le16_to_cpu(pSMBr->t2.ParameterOffset));
2781
2782 if(parms->EndofSearch)
2783 psrch_inf->endOfSearch = TRUE;
2784 else
2785 psrch_inf->endOfSearch = FALSE;
2786
2787 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2788 psrch_inf->index_of_last_entry =
2789 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 *pnetfid = parms->SearchHandle;
2791 } else {
2792 cifs_buf_release(pSMB);
2793 }
2794 }
2795
2796 return rc;
2797}
2798
2799int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2800 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2801{
2802 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2803 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2804 T2_FNEXT_RSP_PARMS * parms;
2805 char *response_data;
2806 int rc = 0;
2807 int bytes_returned, name_len;
2808 __u16 params, byte_count;
2809
2810 cFYI(1, ("In FindNext"));
2811
2812 if(psrch_inf->endOfSearch == TRUE)
2813 return -ENOENT;
2814
2815 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2816 (void **) &pSMBr);
2817 if (rc)
2818 return rc;
2819
2820 params = 14; /* includes 2 bytes of null string, converted to LE below */
2821 byte_count = 0;
2822 pSMB->TotalDataCount = 0; /* no EAs */
2823 pSMB->MaxParameterCount = cpu_to_le16(8);
2824 pSMB->MaxDataCount =
2825 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2826 pSMB->MaxSetupCount = 0;
2827 pSMB->Reserved = 0;
2828 pSMB->Flags = 0;
2829 pSMB->Timeout = 0;
2830 pSMB->Reserved2 = 0;
2831 pSMB->ParameterOffset = cpu_to_le16(
2832 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2833 pSMB->DataCount = 0;
2834 pSMB->DataOffset = 0;
2835 pSMB->SetupCount = 1;
2836 pSMB->Reserved3 = 0;
2837 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2838 pSMB->SearchHandle = searchHandle; /* always kept as le */
2839 pSMB->SearchCount =
2840 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2841 /* test for Unix extensions */
2842/* if (tcon->ses->capabilities & CAP_UNIX) {
2843 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2844 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2845 } else {
2846 pSMB->InformationLevel =
2847 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2848 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2849 } */
2850 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2851 pSMB->ResumeKey = psrch_inf->resume_key;
2852 pSMB->SearchFlags =
2853 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2854
2855 name_len = psrch_inf->resume_name_len;
2856 params += name_len;
2857 if(name_len < PATH_MAX) {
2858 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2859 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002860 /* 14 byte parm len above enough for 2 byte null terminator */
2861 pSMB->ResumeFileName[name_len] = 0;
2862 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 } else {
2864 rc = -EINVAL;
2865 goto FNext2_err_exit;
2866 }
2867 byte_count = params + 1 /* pad */ ;
2868 pSMB->TotalParameterCount = cpu_to_le16(params);
2869 pSMB->ParameterCount = pSMB->TotalParameterCount;
2870 pSMB->hdr.smb_buf_length += byte_count;
2871 pSMB->ByteCount = cpu_to_le16(byte_count);
2872
2873 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2874 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002875 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 if (rc) {
2877 if (rc == -EBADF) {
2878 psrch_inf->endOfSearch = TRUE;
2879 rc = 0; /* search probably was closed at end of search above */
2880 } else
2881 cFYI(1, ("FindNext returned = %d", rc));
2882 } else { /* decode response */
2883 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2884
2885 if(rc == 0) {
2886 /* BB fixme add lock for file (srch_info) struct here */
2887 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2888 psrch_inf->unicode = TRUE;
2889 else
2890 psrch_inf->unicode = FALSE;
2891 response_data = (char *) &pSMBr->hdr.Protocol +
2892 le16_to_cpu(pSMBr->t2.ParameterOffset);
2893 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2894 response_data = (char *)&pSMBr->hdr.Protocol +
2895 le16_to_cpu(pSMBr->t2.DataOffset);
2896 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2897 psrch_inf->srch_entries_start = response_data;
2898 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2899 if(parms->EndofSearch)
2900 psrch_inf->endOfSearch = TRUE;
2901 else
2902 psrch_inf->endOfSearch = FALSE;
2903
2904 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2905 psrch_inf->index_of_last_entry +=
2906 psrch_inf->entries_in_buffer;
2907/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2908
2909 /* BB fixme add unlock here */
2910 }
2911
2912 }
2913
2914 /* BB On error, should we leave previous search buf (and count and
2915 last entry fields) intact or free the previous one? */
2916
2917 /* Note: On -EAGAIN error only caller can retry on handle based calls
2918 since file handle passed in no longer valid */
2919FNext2_err_exit:
2920 if (rc != 0)
2921 cifs_buf_release(pSMB);
2922
2923 return rc;
2924}
2925
2926int
2927CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2928{
2929 int rc = 0;
2930 FINDCLOSE_REQ *pSMB = NULL;
2931 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2932 int bytes_returned;
2933
2934 cFYI(1, ("In CIFSSMBFindClose"));
2935 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2936
2937 /* no sense returning error if session restarted
2938 as file handle has been closed */
2939 if(rc == -EAGAIN)
2940 return 0;
2941 if (rc)
2942 return rc;
2943
2944 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2945 pSMB->FileID = searchHandle;
2946 pSMB->ByteCount = 0;
2947 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2948 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2949 if (rc) {
2950 cERROR(1, ("Send error in FindClose = %d", rc));
2951 }
Steve Frencha4544342005-08-24 13:59:35 -07002952 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 cifs_small_buf_release(pSMB);
2954
2955 /* Since session is dead, search handle closed on server already */
2956 if (rc == -EAGAIN)
2957 rc = 0;
2958
2959 return rc;
2960}
2961
2962#ifdef CONFIG_CIFS_EXPERIMENTAL
2963int
2964CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2965 const unsigned char *searchName,
2966 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002967 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968{
2969 int rc = 0;
2970 TRANSACTION2_QPI_REQ *pSMB = NULL;
2971 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2972 int name_len, bytes_returned;
2973 __u16 params, byte_count;
2974
2975 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2976 if(tcon == NULL)
2977 return -ENODEV;
2978
2979GetInodeNumberRetry:
2980 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2981 (void **) &pSMBr);
2982 if (rc)
2983 return rc;
2984
2985
2986 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2987 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002988 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002989 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 name_len++; /* trailing null */
2991 name_len *= 2;
2992 } else { /* BB improve the check for buffer overruns BB */
2993 name_len = strnlen(searchName, PATH_MAX);
2994 name_len++; /* trailing null */
2995 strncpy(pSMB->FileName, searchName, name_len);
2996 }
2997
2998 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2999 pSMB->TotalDataCount = 0;
3000 pSMB->MaxParameterCount = cpu_to_le16(2);
3001 /* BB find exact max data count below from sess structure BB */
3002 pSMB->MaxDataCount = cpu_to_le16(4000);
3003 pSMB->MaxSetupCount = 0;
3004 pSMB->Reserved = 0;
3005 pSMB->Flags = 0;
3006 pSMB->Timeout = 0;
3007 pSMB->Reserved2 = 0;
3008 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3009 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3010 pSMB->DataCount = 0;
3011 pSMB->DataOffset = 0;
3012 pSMB->SetupCount = 1;
3013 pSMB->Reserved3 = 0;
3014 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3015 byte_count = params + 1 /* pad */ ;
3016 pSMB->TotalParameterCount = cpu_to_le16(params);
3017 pSMB->ParameterCount = pSMB->TotalParameterCount;
3018 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3019 pSMB->Reserved4 = 0;
3020 pSMB->hdr.smb_buf_length += byte_count;
3021 pSMB->ByteCount = cpu_to_le16(byte_count);
3022
3023 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3024 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3025 if (rc) {
3026 cFYI(1, ("error %d in QueryInternalInfo", rc));
3027 } else {
3028 /* decode response */
3029 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3030 if (rc || (pSMBr->ByteCount < 2))
3031 /* BB also check enough total bytes returned */
3032 /* If rc should we check for EOPNOSUPP and
3033 disable the srvino flag? or in caller? */
3034 rc = -EIO; /* bad smb */
3035 else {
3036 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3037 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3038 struct file_internal_info * pfinfo;
3039 /* BB Do we need a cast or hash here ? */
3040 if(count < 8) {
3041 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3042 rc = -EIO;
3043 goto GetInodeNumOut;
3044 }
3045 pfinfo = (struct file_internal_info *)
3046 (data_offset + (char *) &pSMBr->hdr.Protocol);
3047 *inode_number = pfinfo->UniqueId;
3048 }
3049 }
3050GetInodeNumOut:
3051 cifs_buf_release(pSMB);
3052 if (rc == -EAGAIN)
3053 goto GetInodeNumberRetry;
3054 return rc;
3055}
3056#endif /* CIFS_EXPERIMENTAL */
3057
3058int
3059CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3060 const unsigned char *searchName,
3061 unsigned char **targetUNCs,
3062 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003063 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064{
3065/* TRANS2_GET_DFS_REFERRAL */
3066 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3067 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3068 struct dfs_referral_level_3 * referrals = NULL;
3069 int rc = 0;
3070 int bytes_returned;
3071 int name_len;
3072 unsigned int i;
3073 char * temp;
3074 __u16 params, byte_count;
3075 *number_of_UNC_in_array = 0;
3076 *targetUNCs = NULL;
3077
3078 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3079 if (ses == NULL)
3080 return -ENODEV;
3081getDFSRetry:
3082 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3083 (void **) &pSMBr);
3084 if (rc)
3085 return rc;
Steve French1982c342005-08-17 12:38:22 -07003086
3087 /* server pointer checked in called function,
3088 but should never be null here anyway */
3089 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 pSMB->hdr.Tid = ses->ipc_tid;
3091 pSMB->hdr.Uid = ses->Suid;
3092 if (ses->capabilities & CAP_STATUS32) {
3093 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3094 }
3095 if (ses->capabilities & CAP_DFS) {
3096 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3097 }
3098
3099 if (ses->capabilities & CAP_UNICODE) {
3100 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3101 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003102 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003103 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 name_len++; /* trailing null */
3105 name_len *= 2;
3106 } else { /* BB improve the check for buffer overruns BB */
3107 name_len = strnlen(searchName, PATH_MAX);
3108 name_len++; /* trailing null */
3109 strncpy(pSMB->RequestFileName, searchName, name_len);
3110 }
3111
3112 params = 2 /* level */ + name_len /*includes null */ ;
3113 pSMB->TotalDataCount = 0;
3114 pSMB->DataCount = 0;
3115 pSMB->DataOffset = 0;
3116 pSMB->MaxParameterCount = 0;
3117 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3118 pSMB->MaxSetupCount = 0;
3119 pSMB->Reserved = 0;
3120 pSMB->Flags = 0;
3121 pSMB->Timeout = 0;
3122 pSMB->Reserved2 = 0;
3123 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3124 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3125 pSMB->SetupCount = 1;
3126 pSMB->Reserved3 = 0;
3127 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3128 byte_count = params + 3 /* pad */ ;
3129 pSMB->ParameterCount = cpu_to_le16(params);
3130 pSMB->TotalParameterCount = pSMB->ParameterCount;
3131 pSMB->MaxReferralLevel = cpu_to_le16(3);
3132 pSMB->hdr.smb_buf_length += byte_count;
3133 pSMB->ByteCount = cpu_to_le16(byte_count);
3134
3135 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3136 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3137 if (rc) {
3138 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3139 } else { /* decode response */
3140/* BB Add logic to parse referrals here */
3141 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3142
3143 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3144 rc = -EIO; /* bad smb */
3145 else {
3146 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3147 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3148
3149 cFYI(1,
3150 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3151 pSMBr->ByteCount, data_offset));
3152 referrals =
3153 (struct dfs_referral_level_3 *)
3154 (8 /* sizeof start of data block */ +
3155 data_offset +
3156 (char *) &pSMBr->hdr.Protocol);
3157 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",
3158 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)));
3159 /* BB This field is actually two bytes in from start of
3160 data block so we could do safety check that DataBlock
3161 begins at address of pSMBr->NumberOfReferrals */
3162 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3163
3164 /* BB Fix below so can return more than one referral */
3165 if(*number_of_UNC_in_array > 1)
3166 *number_of_UNC_in_array = 1;
3167
3168 /* get the length of the strings describing refs */
3169 name_len = 0;
3170 for(i=0;i<*number_of_UNC_in_array;i++) {
3171 /* make sure that DfsPathOffset not past end */
3172 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3173 if (offset > data_count) {
3174 /* if invalid referral, stop here and do
3175 not try to copy any more */
3176 *number_of_UNC_in_array = i;
3177 break;
3178 }
3179 temp = ((char *)referrals) + offset;
3180
3181 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3182 name_len += UniStrnlen((wchar_t *)temp,data_count);
3183 } else {
3184 name_len += strnlen(temp,data_count);
3185 }
3186 referrals++;
3187 /* BB add check that referral pointer does not fall off end PDU */
3188
3189 }
3190 /* BB add check for name_len bigger than bcc */
3191 *targetUNCs =
3192 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3193 if(*targetUNCs == NULL) {
3194 rc = -ENOMEM;
3195 goto GetDFSRefExit;
3196 }
3197 /* copy the ref strings */
3198 referrals =
3199 (struct dfs_referral_level_3 *)
3200 (8 /* sizeof data hdr */ +
3201 data_offset +
3202 (char *) &pSMBr->hdr.Protocol);
3203
3204 for(i=0;i<*number_of_UNC_in_array;i++) {
3205 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3206 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3207 cifs_strfromUCS_le(*targetUNCs,
3208 (wchar_t *) temp, name_len, nls_codepage);
3209 } else {
3210 strncpy(*targetUNCs,temp,name_len);
3211 }
3212 /* BB update target_uncs pointers */
3213 referrals++;
3214 }
3215 temp = *targetUNCs;
3216 temp[name_len] = 0;
3217 }
3218
3219 }
3220GetDFSRefExit:
3221 if (pSMB)
3222 cifs_buf_release(pSMB);
3223
3224 if (rc == -EAGAIN)
3225 goto getDFSRetry;
3226
3227 return rc;
3228}
3229
Steve French20962432005-09-21 22:05:57 -07003230/* Query File System Info such as free space to old servers such as Win 9x */
3231int
3232SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3233{
3234/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3235 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3236 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3237 FILE_SYSTEM_ALLOC_INFO *response_data;
3238 int rc = 0;
3239 int bytes_returned = 0;
3240 __u16 params, byte_count;
3241
3242 cFYI(1, ("OldQFSInfo"));
3243oldQFSInfoRetry:
3244 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3245 (void **) &pSMBr);
3246 if (rc)
3247 return rc;
3248 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3249 (void **) &pSMBr);
3250 if (rc)
3251 return rc;
3252
3253 params = 2; /* level */
3254 pSMB->TotalDataCount = 0;
3255 pSMB->MaxParameterCount = cpu_to_le16(2);
3256 pSMB->MaxDataCount = cpu_to_le16(1000);
3257 pSMB->MaxSetupCount = 0;
3258 pSMB->Reserved = 0;
3259 pSMB->Flags = 0;
3260 pSMB->Timeout = 0;
3261 pSMB->Reserved2 = 0;
3262 byte_count = params + 1 /* pad */ ;
3263 pSMB->TotalParameterCount = cpu_to_le16(params);
3264 pSMB->ParameterCount = pSMB->TotalParameterCount;
3265 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3266 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3267 pSMB->DataCount = 0;
3268 pSMB->DataOffset = 0;
3269 pSMB->SetupCount = 1;
3270 pSMB->Reserved3 = 0;
3271 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3272 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3273 pSMB->hdr.smb_buf_length += byte_count;
3274 pSMB->ByteCount = cpu_to_le16(byte_count);
3275
3276 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3277 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3278 if (rc) {
3279 cFYI(1, ("Send error in QFSInfo = %d", rc));
3280 } else { /* decode response */
3281 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3282
3283 if (rc || (pSMBr->ByteCount < 18))
3284 rc = -EIO; /* bad smb */
3285 else {
3286 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3287 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3288 pSMBr->ByteCount, data_offset));
3289
3290 response_data =
3291 (FILE_SYSTEM_ALLOC_INFO *)
3292 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3293 FSData->f_bsize =
3294 le16_to_cpu(response_data->BytesPerSector) *
3295 le32_to_cpu(response_data->
3296 SectorsPerAllocationUnit);
3297 FSData->f_blocks =
3298 le32_to_cpu(response_data->TotalAllocationUnits);
3299 FSData->f_bfree = FSData->f_bavail =
3300 le32_to_cpu(response_data->FreeAllocationUnits);
3301 cFYI(1,
3302 ("Blocks: %lld Free: %lld Block size %ld",
3303 (unsigned long long)FSData->f_blocks,
3304 (unsigned long long)FSData->f_bfree,
3305 FSData->f_bsize));
3306 }
3307 }
3308 cifs_buf_release(pSMB);
3309
3310 if (rc == -EAGAIN)
3311 goto oldQFSInfoRetry;
3312
3313 return rc;
3314}
3315
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316int
Steve French737b7582005-04-28 22:41:06 -07003317CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318{
3319/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3320 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3321 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3322 FILE_SYSTEM_INFO *response_data;
3323 int rc = 0;
3324 int bytes_returned = 0;
3325 __u16 params, byte_count;
3326
3327 cFYI(1, ("In QFSInfo"));
3328QFSInfoRetry:
3329 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3330 (void **) &pSMBr);
3331 if (rc)
3332 return rc;
3333
3334 params = 2; /* level */
3335 pSMB->TotalDataCount = 0;
3336 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003337 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 pSMB->MaxSetupCount = 0;
3339 pSMB->Reserved = 0;
3340 pSMB->Flags = 0;
3341 pSMB->Timeout = 0;
3342 pSMB->Reserved2 = 0;
3343 byte_count = params + 1 /* pad */ ;
3344 pSMB->TotalParameterCount = cpu_to_le16(params);
3345 pSMB->ParameterCount = pSMB->TotalParameterCount;
3346 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3347 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3348 pSMB->DataCount = 0;
3349 pSMB->DataOffset = 0;
3350 pSMB->SetupCount = 1;
3351 pSMB->Reserved3 = 0;
3352 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3353 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3354 pSMB->hdr.smb_buf_length += byte_count;
3355 pSMB->ByteCount = cpu_to_le16(byte_count);
3356
3357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3359 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003360 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 } else { /* decode response */
3362 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3363
Steve French20962432005-09-21 22:05:57 -07003364 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 rc = -EIO; /* bad smb */
3366 else {
3367 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368
3369 response_data =
3370 (FILE_SYSTEM_INFO
3371 *) (((char *) &pSMBr->hdr.Protocol) +
3372 data_offset);
3373 FSData->f_bsize =
3374 le32_to_cpu(response_data->BytesPerSector) *
3375 le32_to_cpu(response_data->
3376 SectorsPerAllocationUnit);
3377 FSData->f_blocks =
3378 le64_to_cpu(response_data->TotalAllocationUnits);
3379 FSData->f_bfree = FSData->f_bavail =
3380 le64_to_cpu(response_data->FreeAllocationUnits);
3381 cFYI(1,
3382 ("Blocks: %lld Free: %lld Block size %ld",
3383 (unsigned long long)FSData->f_blocks,
3384 (unsigned long long)FSData->f_bfree,
3385 FSData->f_bsize));
3386 }
3387 }
3388 cifs_buf_release(pSMB);
3389
3390 if (rc == -EAGAIN)
3391 goto QFSInfoRetry;
3392
3393 return rc;
3394}
3395
3396int
Steve French737b7582005-04-28 22:41:06 -07003397CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398{
3399/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3400 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3401 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3402 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3403 int rc = 0;
3404 int bytes_returned = 0;
3405 __u16 params, byte_count;
3406
3407 cFYI(1, ("In QFSAttributeInfo"));
3408QFSAttributeRetry:
3409 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3410 (void **) &pSMBr);
3411 if (rc)
3412 return rc;
3413
3414 params = 2; /* level */
3415 pSMB->TotalDataCount = 0;
3416 pSMB->MaxParameterCount = cpu_to_le16(2);
3417 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3418 pSMB->MaxSetupCount = 0;
3419 pSMB->Reserved = 0;
3420 pSMB->Flags = 0;
3421 pSMB->Timeout = 0;
3422 pSMB->Reserved2 = 0;
3423 byte_count = params + 1 /* pad */ ;
3424 pSMB->TotalParameterCount = cpu_to_le16(params);
3425 pSMB->ParameterCount = pSMB->TotalParameterCount;
3426 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3427 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3428 pSMB->DataCount = 0;
3429 pSMB->DataOffset = 0;
3430 pSMB->SetupCount = 1;
3431 pSMB->Reserved3 = 0;
3432 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3433 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3434 pSMB->hdr.smb_buf_length += byte_count;
3435 pSMB->ByteCount = cpu_to_le16(byte_count);
3436
3437 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3439 if (rc) {
3440 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3441 } else { /* decode response */
3442 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3443
3444 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3445 rc = -EIO; /* bad smb */
3446 } else {
3447 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3448 response_data =
3449 (FILE_SYSTEM_ATTRIBUTE_INFO
3450 *) (((char *) &pSMBr->hdr.Protocol) +
3451 data_offset);
3452 memcpy(&tcon->fsAttrInfo, response_data,
3453 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3454 }
3455 }
3456 cifs_buf_release(pSMB);
3457
3458 if (rc == -EAGAIN)
3459 goto QFSAttributeRetry;
3460
3461 return rc;
3462}
3463
3464int
Steve French737b7582005-04-28 22:41:06 -07003465CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466{
3467/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3468 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3469 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3470 FILE_SYSTEM_DEVICE_INFO *response_data;
3471 int rc = 0;
3472 int bytes_returned = 0;
3473 __u16 params, byte_count;
3474
3475 cFYI(1, ("In QFSDeviceInfo"));
3476QFSDeviceRetry:
3477 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3478 (void **) &pSMBr);
3479 if (rc)
3480 return rc;
3481
3482 params = 2; /* level */
3483 pSMB->TotalDataCount = 0;
3484 pSMB->MaxParameterCount = cpu_to_le16(2);
3485 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3486 pSMB->MaxSetupCount = 0;
3487 pSMB->Reserved = 0;
3488 pSMB->Flags = 0;
3489 pSMB->Timeout = 0;
3490 pSMB->Reserved2 = 0;
3491 byte_count = params + 1 /* pad */ ;
3492 pSMB->TotalParameterCount = cpu_to_le16(params);
3493 pSMB->ParameterCount = pSMB->TotalParameterCount;
3494 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3495 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3496
3497 pSMB->DataCount = 0;
3498 pSMB->DataOffset = 0;
3499 pSMB->SetupCount = 1;
3500 pSMB->Reserved3 = 0;
3501 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3502 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3503 pSMB->hdr.smb_buf_length += byte_count;
3504 pSMB->ByteCount = cpu_to_le16(byte_count);
3505
3506 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3507 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3508 if (rc) {
3509 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3510 } else { /* decode response */
3511 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3512
3513 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3514 rc = -EIO; /* bad smb */
3515 else {
3516 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3517 response_data =
Steve French737b7582005-04-28 22:41:06 -07003518 (FILE_SYSTEM_DEVICE_INFO *)
3519 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 data_offset);
3521 memcpy(&tcon->fsDevInfo, response_data,
3522 sizeof (FILE_SYSTEM_DEVICE_INFO));
3523 }
3524 }
3525 cifs_buf_release(pSMB);
3526
3527 if (rc == -EAGAIN)
3528 goto QFSDeviceRetry;
3529
3530 return rc;
3531}
3532
3533int
Steve French737b7582005-04-28 22:41:06 -07003534CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535{
3536/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3537 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3538 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3539 FILE_SYSTEM_UNIX_INFO *response_data;
3540 int rc = 0;
3541 int bytes_returned = 0;
3542 __u16 params, byte_count;
3543
3544 cFYI(1, ("In QFSUnixInfo"));
3545QFSUnixRetry:
3546 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3547 (void **) &pSMBr);
3548 if (rc)
3549 return rc;
3550
3551 params = 2; /* level */
3552 pSMB->TotalDataCount = 0;
3553 pSMB->DataCount = 0;
3554 pSMB->DataOffset = 0;
3555 pSMB->MaxParameterCount = cpu_to_le16(2);
3556 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3557 pSMB->MaxSetupCount = 0;
3558 pSMB->Reserved = 0;
3559 pSMB->Flags = 0;
3560 pSMB->Timeout = 0;
3561 pSMB->Reserved2 = 0;
3562 byte_count = params + 1 /* pad */ ;
3563 pSMB->ParameterCount = cpu_to_le16(params);
3564 pSMB->TotalParameterCount = pSMB->ParameterCount;
3565 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3566 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3567 pSMB->SetupCount = 1;
3568 pSMB->Reserved3 = 0;
3569 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3570 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3571 pSMB->hdr.smb_buf_length += byte_count;
3572 pSMB->ByteCount = cpu_to_le16(byte_count);
3573
3574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3576 if (rc) {
3577 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3578 } else { /* decode response */
3579 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3580
3581 if (rc || (pSMBr->ByteCount < 13)) {
3582 rc = -EIO; /* bad smb */
3583 } else {
3584 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3585 response_data =
3586 (FILE_SYSTEM_UNIX_INFO
3587 *) (((char *) &pSMBr->hdr.Protocol) +
3588 data_offset);
3589 memcpy(&tcon->fsUnixInfo, response_data,
3590 sizeof (FILE_SYSTEM_UNIX_INFO));
3591 }
3592 }
3593 cifs_buf_release(pSMB);
3594
3595 if (rc == -EAGAIN)
3596 goto QFSUnixRetry;
3597
3598
3599 return rc;
3600}
3601
Jeremy Allisonac670552005-06-22 17:26:35 -07003602int
Steve French45abc6e2005-06-23 13:42:03 -05003603CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003604{
3605/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3606 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3607 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3608 int rc = 0;
3609 int bytes_returned = 0;
3610 __u16 params, param_offset, offset, byte_count;
3611
3612 cFYI(1, ("In SETFSUnixInfo"));
3613SETFSUnixRetry:
3614 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3615 (void **) &pSMBr);
3616 if (rc)
3617 return rc;
3618
3619 params = 4; /* 2 bytes zero followed by info level. */
3620 pSMB->MaxSetupCount = 0;
3621 pSMB->Reserved = 0;
3622 pSMB->Flags = 0;
3623 pSMB->Timeout = 0;
3624 pSMB->Reserved2 = 0;
3625 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3626 offset = param_offset + params;
3627
3628 pSMB->MaxParameterCount = cpu_to_le16(4);
3629 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3630 pSMB->SetupCount = 1;
3631 pSMB->Reserved3 = 0;
3632 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3633 byte_count = 1 /* pad */ + params + 12;
3634
3635 pSMB->DataCount = cpu_to_le16(12);
3636 pSMB->ParameterCount = cpu_to_le16(params);
3637 pSMB->TotalDataCount = pSMB->DataCount;
3638 pSMB->TotalParameterCount = pSMB->ParameterCount;
3639 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3640 pSMB->DataOffset = cpu_to_le16(offset);
3641
3642 /* Params. */
3643 pSMB->FileNum = 0;
3644 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3645
3646 /* Data. */
3647 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3648 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3649 pSMB->ClientUnixCap = cpu_to_le64(cap);
3650
3651 pSMB->hdr.smb_buf_length += byte_count;
3652 pSMB->ByteCount = cpu_to_le16(byte_count);
3653
3654 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3655 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3656 if (rc) {
3657 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3658 } else { /* decode response */
3659 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3660 if (rc) {
3661 rc = -EIO; /* bad smb */
3662 }
3663 }
3664 cifs_buf_release(pSMB);
3665
3666 if (rc == -EAGAIN)
3667 goto SETFSUnixRetry;
3668
3669 return rc;
3670}
3671
3672
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673
3674int
3675CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003676 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677{
3678/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3679 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3680 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3681 FILE_SYSTEM_POSIX_INFO *response_data;
3682 int rc = 0;
3683 int bytes_returned = 0;
3684 __u16 params, byte_count;
3685
3686 cFYI(1, ("In QFSPosixInfo"));
3687QFSPosixRetry:
3688 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3689 (void **) &pSMBr);
3690 if (rc)
3691 return rc;
3692
3693 params = 2; /* level */
3694 pSMB->TotalDataCount = 0;
3695 pSMB->DataCount = 0;
3696 pSMB->DataOffset = 0;
3697 pSMB->MaxParameterCount = cpu_to_le16(2);
3698 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3699 pSMB->MaxSetupCount = 0;
3700 pSMB->Reserved = 0;
3701 pSMB->Flags = 0;
3702 pSMB->Timeout = 0;
3703 pSMB->Reserved2 = 0;
3704 byte_count = params + 1 /* pad */ ;
3705 pSMB->ParameterCount = cpu_to_le16(params);
3706 pSMB->TotalParameterCount = pSMB->ParameterCount;
3707 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3708 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3709 pSMB->SetupCount = 1;
3710 pSMB->Reserved3 = 0;
3711 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3712 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3713 pSMB->hdr.smb_buf_length += byte_count;
3714 pSMB->ByteCount = cpu_to_le16(byte_count);
3715
3716 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3717 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3718 if (rc) {
3719 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3720 } else { /* decode response */
3721 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3722
3723 if (rc || (pSMBr->ByteCount < 13)) {
3724 rc = -EIO; /* bad smb */
3725 } else {
3726 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3727 response_data =
3728 (FILE_SYSTEM_POSIX_INFO
3729 *) (((char *) &pSMBr->hdr.Protocol) +
3730 data_offset);
3731 FSData->f_bsize =
3732 le32_to_cpu(response_data->BlockSize);
3733 FSData->f_blocks =
3734 le64_to_cpu(response_data->TotalBlocks);
3735 FSData->f_bfree =
3736 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003737 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 FSData->f_bavail = FSData->f_bfree;
3739 } else {
3740 FSData->f_bavail =
3741 le64_to_cpu(response_data->UserBlocksAvail);
3742 }
Steve French70ca7342005-09-22 16:32:06 -07003743 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 FSData->f_files =
3745 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003746 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 FSData->f_ffree =
3748 le64_to_cpu(response_data->FreeFileNodes);
3749 }
3750 }
3751 cifs_buf_release(pSMB);
3752
3753 if (rc == -EAGAIN)
3754 goto QFSPosixRetry;
3755
3756 return rc;
3757}
3758
3759
3760/* We can not use write of zero bytes trick to
3761 set file size due to need for large file support. Also note that
3762 this SetPathInfo is preferred to SetFileInfo based method in next
3763 routine which is only needed to work around a sharing violation bug
3764 in Samba which this routine can run into */
3765
3766int
3767CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003768 __u64 size, int SetAllocation,
3769 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770{
3771 struct smb_com_transaction2_spi_req *pSMB = NULL;
3772 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3773 struct file_end_of_file_info *parm_data;
3774 int name_len;
3775 int rc = 0;
3776 int bytes_returned = 0;
3777 __u16 params, byte_count, data_count, param_offset, offset;
3778
3779 cFYI(1, ("In SetEOF"));
3780SetEOFRetry:
3781 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3782 (void **) &pSMBr);
3783 if (rc)
3784 return rc;
3785
3786 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3787 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003788 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003789 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 name_len++; /* trailing null */
3791 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07003792 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 name_len = strnlen(fileName, PATH_MAX);
3794 name_len++; /* trailing null */
3795 strncpy(pSMB->FileName, fileName, name_len);
3796 }
3797 params = 6 + name_len;
3798 data_count = sizeof (struct file_end_of_file_info);
3799 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07003800 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 pSMB->MaxSetupCount = 0;
3802 pSMB->Reserved = 0;
3803 pSMB->Flags = 0;
3804 pSMB->Timeout = 0;
3805 pSMB->Reserved2 = 0;
3806 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3807 InformationLevel) - 4;
3808 offset = param_offset + params;
3809 if(SetAllocation) {
3810 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3811 pSMB->InformationLevel =
3812 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3813 else
3814 pSMB->InformationLevel =
3815 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3816 } else /* Set File Size */ {
3817 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3818 pSMB->InformationLevel =
3819 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3820 else
3821 pSMB->InformationLevel =
3822 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3823 }
3824
3825 parm_data =
3826 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3827 offset);
3828 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3829 pSMB->DataOffset = cpu_to_le16(offset);
3830 pSMB->SetupCount = 1;
3831 pSMB->Reserved3 = 0;
3832 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3833 byte_count = 3 /* pad */ + params + data_count;
3834 pSMB->DataCount = cpu_to_le16(data_count);
3835 pSMB->TotalDataCount = pSMB->DataCount;
3836 pSMB->ParameterCount = cpu_to_le16(params);
3837 pSMB->TotalParameterCount = pSMB->ParameterCount;
3838 pSMB->Reserved4 = 0;
3839 pSMB->hdr.smb_buf_length += byte_count;
3840 parm_data->FileSize = cpu_to_le64(size);
3841 pSMB->ByteCount = cpu_to_le16(byte_count);
3842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3844 if (rc) {
3845 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3846 }
3847
3848 cifs_buf_release(pSMB);
3849
3850 if (rc == -EAGAIN)
3851 goto SetEOFRetry;
3852
3853 return rc;
3854}
3855
3856int
3857CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3858 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3859{
3860 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3861 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3862 char *data_offset;
3863 struct file_end_of_file_info *parm_data;
3864 int rc = 0;
3865 int bytes_returned = 0;
3866 __u16 params, param_offset, offset, byte_count, count;
3867
3868 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3869 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003870 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3871
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 if (rc)
3873 return rc;
3874
Steve Frenchcd634992005-04-28 22:41:10 -07003875 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3876
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3878 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3879
3880 params = 6;
3881 pSMB->MaxSetupCount = 0;
3882 pSMB->Reserved = 0;
3883 pSMB->Flags = 0;
3884 pSMB->Timeout = 0;
3885 pSMB->Reserved2 = 0;
3886 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3887 offset = param_offset + params;
3888
3889 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3890
3891 count = sizeof(struct file_end_of_file_info);
3892 pSMB->MaxParameterCount = cpu_to_le16(2);
3893 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3894 pSMB->SetupCount = 1;
3895 pSMB->Reserved3 = 0;
3896 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3897 byte_count = 3 /* pad */ + params + count;
3898 pSMB->DataCount = cpu_to_le16(count);
3899 pSMB->ParameterCount = cpu_to_le16(params);
3900 pSMB->TotalDataCount = pSMB->DataCount;
3901 pSMB->TotalParameterCount = pSMB->ParameterCount;
3902 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3903 parm_data =
3904 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3905 offset);
3906 pSMB->DataOffset = cpu_to_le16(offset);
3907 parm_data->FileSize = cpu_to_le64(size);
3908 pSMB->Fid = fid;
3909 if(SetAllocation) {
3910 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3911 pSMB->InformationLevel =
3912 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3913 else
3914 pSMB->InformationLevel =
3915 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3916 } else /* Set File Size */ {
3917 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3918 pSMB->InformationLevel =
3919 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3920 else
3921 pSMB->InformationLevel =
3922 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3923 }
3924 pSMB->Reserved4 = 0;
3925 pSMB->hdr.smb_buf_length += byte_count;
3926 pSMB->ByteCount = cpu_to_le16(byte_count);
3927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3929 if (rc) {
3930 cFYI(1,
3931 ("Send error in SetFileInfo (SetFileSize) = %d",
3932 rc));
3933 }
3934
3935 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003936 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937
3938 /* Note: On -EAGAIN error only caller can retry on handle based calls
3939 since file handle passed in no longer valid */
3940
3941 return rc;
3942}
3943
3944/* Some legacy servers such as NT4 require that the file times be set on
3945 an open handle, rather than by pathname - this is awkward due to
3946 potential access conflicts on the open, but it is unavoidable for these
3947 old servers since the only other choice is to go from 100 nanosecond DCE
3948 time and resort to the original setpathinfo level which takes the ancient
3949 DOS time format with 2 second granularity */
3950int
3951CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3952 __u16 fid)
3953{
3954 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3955 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3956 char *data_offset;
3957 int rc = 0;
3958 int bytes_returned = 0;
3959 __u16 params, param_offset, offset, byte_count, count;
3960
3961 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003962 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3963
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 if (rc)
3965 return rc;
3966
Steve Frenchcd634992005-04-28 22:41:10 -07003967 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3968
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 /* At this point there is no need to override the current pid
3970 with the pid of the opener, but that could change if we someday
3971 use an existing handle (rather than opening one on the fly) */
3972 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3973 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3974
3975 params = 6;
3976 pSMB->MaxSetupCount = 0;
3977 pSMB->Reserved = 0;
3978 pSMB->Flags = 0;
3979 pSMB->Timeout = 0;
3980 pSMB->Reserved2 = 0;
3981 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3982 offset = param_offset + params;
3983
3984 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3985
3986 count = sizeof (FILE_BASIC_INFO);
3987 pSMB->MaxParameterCount = cpu_to_le16(2);
3988 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3989 pSMB->SetupCount = 1;
3990 pSMB->Reserved3 = 0;
3991 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3992 byte_count = 3 /* pad */ + params + count;
3993 pSMB->DataCount = cpu_to_le16(count);
3994 pSMB->ParameterCount = cpu_to_le16(params);
3995 pSMB->TotalDataCount = pSMB->DataCount;
3996 pSMB->TotalParameterCount = pSMB->ParameterCount;
3997 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3998 pSMB->DataOffset = cpu_to_le16(offset);
3999 pSMB->Fid = fid;
4000 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4001 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4002 else
4003 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4004 pSMB->Reserved4 = 0;
4005 pSMB->hdr.smb_buf_length += byte_count;
4006 pSMB->ByteCount = cpu_to_le16(byte_count);
4007 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4010 if (rc) {
4011 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4012 }
4013
Steve Frenchcd634992005-04-28 22:41:10 -07004014 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015
4016 /* Note: On -EAGAIN error only caller can retry on handle based calls
4017 since file handle passed in no longer valid */
4018
4019 return rc;
4020}
4021
4022
4023int
4024CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4025 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004026 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027{
4028 TRANSACTION2_SPI_REQ *pSMB = NULL;
4029 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4030 int name_len;
4031 int rc = 0;
4032 int bytes_returned = 0;
4033 char *data_offset;
4034 __u16 params, param_offset, offset, byte_count, count;
4035
4036 cFYI(1, ("In SetTimes"));
4037
4038SetTimesRetry:
4039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4040 (void **) &pSMBr);
4041 if (rc)
4042 return rc;
4043
4044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4045 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004046 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004047 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 name_len++; /* trailing null */
4049 name_len *= 2;
4050 } else { /* BB improve the check for buffer overruns BB */
4051 name_len = strnlen(fileName, PATH_MAX);
4052 name_len++; /* trailing null */
4053 strncpy(pSMB->FileName, fileName, name_len);
4054 }
4055
4056 params = 6 + name_len;
4057 count = sizeof (FILE_BASIC_INFO);
4058 pSMB->MaxParameterCount = cpu_to_le16(2);
4059 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4060 pSMB->MaxSetupCount = 0;
4061 pSMB->Reserved = 0;
4062 pSMB->Flags = 0;
4063 pSMB->Timeout = 0;
4064 pSMB->Reserved2 = 0;
4065 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4066 InformationLevel) - 4;
4067 offset = param_offset + params;
4068 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4069 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4070 pSMB->DataOffset = cpu_to_le16(offset);
4071 pSMB->SetupCount = 1;
4072 pSMB->Reserved3 = 0;
4073 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4074 byte_count = 3 /* pad */ + params + count;
4075
4076 pSMB->DataCount = cpu_to_le16(count);
4077 pSMB->ParameterCount = cpu_to_le16(params);
4078 pSMB->TotalDataCount = pSMB->DataCount;
4079 pSMB->TotalParameterCount = pSMB->ParameterCount;
4080 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4081 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4082 else
4083 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4084 pSMB->Reserved4 = 0;
4085 pSMB->hdr.smb_buf_length += byte_count;
4086 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4087 pSMB->ByteCount = cpu_to_le16(byte_count);
4088 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4089 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4090 if (rc) {
4091 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4092 }
4093
4094 cifs_buf_release(pSMB);
4095
4096 if (rc == -EAGAIN)
4097 goto SetTimesRetry;
4098
4099 return rc;
4100}
4101
4102/* Can not be used to set time stamps yet (due to old DOS time format) */
4103/* Can be used to set attributes */
4104#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4105 handling it anyway and NT4 was what we thought it would be needed for
4106 Do not delete it until we prove whether needed for Win9x though */
4107int
4108CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4109 __u16 dos_attrs, const struct nls_table *nls_codepage)
4110{
4111 SETATTR_REQ *pSMB = NULL;
4112 SETATTR_RSP *pSMBr = NULL;
4113 int rc = 0;
4114 int bytes_returned;
4115 int name_len;
4116
4117 cFYI(1, ("In SetAttrLegacy"));
4118
4119SetAttrLgcyRetry:
4120 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4121 (void **) &pSMBr);
4122 if (rc)
4123 return rc;
4124
4125 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4126 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004127 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 PATH_MAX, nls_codepage);
4129 name_len++; /* trailing null */
4130 name_len *= 2;
4131 } else { /* BB improve the check for buffer overruns BB */
4132 name_len = strnlen(fileName, PATH_MAX);
4133 name_len++; /* trailing null */
4134 strncpy(pSMB->fileName, fileName, name_len);
4135 }
4136 pSMB->attr = cpu_to_le16(dos_attrs);
4137 pSMB->BufferFormat = 0x04;
4138 pSMB->hdr.smb_buf_length += name_len + 1;
4139 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4141 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4142 if (rc) {
4143 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4144 }
4145
4146 cifs_buf_release(pSMB);
4147
4148 if (rc == -EAGAIN)
4149 goto SetAttrLgcyRetry;
4150
4151 return rc;
4152}
4153#endif /* temporarily unneeded SetAttr legacy function */
4154
4155int
4156CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004157 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4158 dev_t device, const struct nls_table *nls_codepage,
4159 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160{
4161 TRANSACTION2_SPI_REQ *pSMB = NULL;
4162 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4163 int name_len;
4164 int rc = 0;
4165 int bytes_returned = 0;
4166 FILE_UNIX_BASIC_INFO *data_offset;
4167 __u16 params, param_offset, offset, count, byte_count;
4168
4169 cFYI(1, ("In SetUID/GID/Mode"));
4170setPermsRetry:
4171 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4172 (void **) &pSMBr);
4173 if (rc)
4174 return rc;
4175
4176 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4177 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004178 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004179 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 name_len++; /* trailing null */
4181 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004182 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 name_len = strnlen(fileName, PATH_MAX);
4184 name_len++; /* trailing null */
4185 strncpy(pSMB->FileName, fileName, name_len);
4186 }
4187
4188 params = 6 + name_len;
4189 count = sizeof (FILE_UNIX_BASIC_INFO);
4190 pSMB->MaxParameterCount = cpu_to_le16(2);
4191 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4192 pSMB->MaxSetupCount = 0;
4193 pSMB->Reserved = 0;
4194 pSMB->Flags = 0;
4195 pSMB->Timeout = 0;
4196 pSMB->Reserved2 = 0;
4197 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4198 InformationLevel) - 4;
4199 offset = param_offset + params;
4200 data_offset =
4201 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4202 offset);
4203 memset(data_offset, 0, count);
4204 pSMB->DataOffset = cpu_to_le16(offset);
4205 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4206 pSMB->SetupCount = 1;
4207 pSMB->Reserved3 = 0;
4208 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4209 byte_count = 3 /* pad */ + params + count;
4210 pSMB->ParameterCount = cpu_to_le16(params);
4211 pSMB->DataCount = cpu_to_le16(count);
4212 pSMB->TotalParameterCount = pSMB->ParameterCount;
4213 pSMB->TotalDataCount = pSMB->DataCount;
4214 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4215 pSMB->Reserved4 = 0;
4216 pSMB->hdr.smb_buf_length += byte_count;
4217 data_offset->Uid = cpu_to_le64(uid);
4218 data_offset->Gid = cpu_to_le64(gid);
4219 /* better to leave device as zero when it is */
4220 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4221 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4222 data_offset->Permissions = cpu_to_le64(mode);
4223
4224 if(S_ISREG(mode))
4225 data_offset->Type = cpu_to_le32(UNIX_FILE);
4226 else if(S_ISDIR(mode))
4227 data_offset->Type = cpu_to_le32(UNIX_DIR);
4228 else if(S_ISLNK(mode))
4229 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4230 else if(S_ISCHR(mode))
4231 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4232 else if(S_ISBLK(mode))
4233 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4234 else if(S_ISFIFO(mode))
4235 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4236 else if(S_ISSOCK(mode))
4237 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4238
4239
4240 pSMB->ByteCount = cpu_to_le16(byte_count);
4241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4242 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4243 if (rc) {
4244 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4245 }
4246
4247 if (pSMB)
4248 cifs_buf_release(pSMB);
4249 if (rc == -EAGAIN)
4250 goto setPermsRetry;
4251 return rc;
4252}
4253
4254int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004255 const int notify_subdirs, const __u16 netfid,
4256 __u32 filter, struct file * pfile, int multishot,
4257 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258{
4259 int rc = 0;
4260 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4261 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004262 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 int bytes_returned;
4264
4265 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4266 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4267 (void **) &pSMBr);
4268 if (rc)
4269 return rc;
4270
4271 pSMB->TotalParameterCount = 0 ;
4272 pSMB->TotalDataCount = 0;
4273 pSMB->MaxParameterCount = cpu_to_le32(2);
4274 /* BB find exact data count max from sess structure BB */
4275 pSMB->MaxDataCount = 0; /* same in little endian or be */
4276 pSMB->MaxSetupCount = 4;
4277 pSMB->Reserved = 0;
4278 pSMB->ParameterOffset = 0;
4279 pSMB->DataCount = 0;
4280 pSMB->DataOffset = 0;
4281 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4282 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4283 pSMB->ParameterCount = pSMB->TotalParameterCount;
4284 if(notify_subdirs)
4285 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4286 pSMB->Reserved2 = 0;
4287 pSMB->CompletionFilter = cpu_to_le32(filter);
4288 pSMB->Fid = netfid; /* file handle always le */
4289 pSMB->ByteCount = 0;
4290
4291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4292 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4293 if (rc) {
4294 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004295 } else {
4296 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004297 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004298 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004299 sizeof(struct dir_notify_req),
4300 GFP_KERNEL);
4301 if(dnotify_req) {
4302 dnotify_req->Pid = pSMB->hdr.Pid;
4303 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4304 dnotify_req->Mid = pSMB->hdr.Mid;
4305 dnotify_req->Tid = pSMB->hdr.Tid;
4306 dnotify_req->Uid = pSMB->hdr.Uid;
4307 dnotify_req->netfid = netfid;
4308 dnotify_req->pfile = pfile;
4309 dnotify_req->filter = filter;
4310 dnotify_req->multishot = multishot;
4311 spin_lock(&GlobalMid_Lock);
4312 list_add_tail(&dnotify_req->lhead,
4313 &GlobalDnotifyReqList);
4314 spin_unlock(&GlobalMid_Lock);
4315 } else
4316 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 }
4318 cifs_buf_release(pSMB);
4319 return rc;
4320}
4321#ifdef CONFIG_CIFS_XATTR
4322ssize_t
4323CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4324 const unsigned char *searchName,
4325 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004326 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327{
4328 /* BB assumes one setup word */
4329 TRANSACTION2_QPI_REQ *pSMB = NULL;
4330 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4331 int rc = 0;
4332 int bytes_returned;
4333 int name_len;
4334 struct fea * temp_fea;
4335 char * temp_ptr;
4336 __u16 params, byte_count;
4337
4338 cFYI(1, ("In Query All EAs path %s", searchName));
4339QAllEAsRetry:
4340 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4341 (void **) &pSMBr);
4342 if (rc)
4343 return rc;
4344
4345 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4346 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004347 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004348 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 name_len++; /* trailing null */
4350 name_len *= 2;
4351 } else { /* BB improve the check for buffer overruns BB */
4352 name_len = strnlen(searchName, PATH_MAX);
4353 name_len++; /* trailing null */
4354 strncpy(pSMB->FileName, searchName, name_len);
4355 }
4356
4357 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4358 pSMB->TotalDataCount = 0;
4359 pSMB->MaxParameterCount = cpu_to_le16(2);
4360 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4361 pSMB->MaxSetupCount = 0;
4362 pSMB->Reserved = 0;
4363 pSMB->Flags = 0;
4364 pSMB->Timeout = 0;
4365 pSMB->Reserved2 = 0;
4366 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4367 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4368 pSMB->DataCount = 0;
4369 pSMB->DataOffset = 0;
4370 pSMB->SetupCount = 1;
4371 pSMB->Reserved3 = 0;
4372 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4373 byte_count = params + 1 /* pad */ ;
4374 pSMB->TotalParameterCount = cpu_to_le16(params);
4375 pSMB->ParameterCount = pSMB->TotalParameterCount;
4376 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4377 pSMB->Reserved4 = 0;
4378 pSMB->hdr.smb_buf_length += byte_count;
4379 pSMB->ByteCount = cpu_to_le16(byte_count);
4380
4381 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4382 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4383 if (rc) {
4384 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4385 } else { /* decode response */
4386 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4387
4388 /* BB also check enough total bytes returned */
4389 /* BB we need to improve the validity checking
4390 of these trans2 responses */
4391 if (rc || (pSMBr->ByteCount < 4))
4392 rc = -EIO; /* bad smb */
4393 /* else if (pFindData){
4394 memcpy((char *) pFindData,
4395 (char *) &pSMBr->hdr.Protocol +
4396 data_offset, kl);
4397 }*/ else {
4398 /* check that length of list is not more than bcc */
4399 /* check that each entry does not go beyond length
4400 of list */
4401 /* check that each element of each entry does not
4402 go beyond end of list */
4403 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4404 struct fealist * ea_response_data;
4405 rc = 0;
4406 /* validate_trans2_offsets() */
4407 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4408 ea_response_data = (struct fealist *)
4409 (((char *) &pSMBr->hdr.Protocol) +
4410 data_offset);
4411 name_len = le32_to_cpu(ea_response_data->list_len);
4412 cFYI(1,("ea length %d", name_len));
4413 if(name_len <= 8) {
4414 /* returned EA size zeroed at top of function */
4415 cFYI(1,("empty EA list returned from server"));
4416 } else {
4417 /* account for ea list len */
4418 name_len -= 4;
4419 temp_fea = ea_response_data->list;
4420 temp_ptr = (char *)temp_fea;
4421 while(name_len > 0) {
4422 __u16 value_len;
4423 name_len -= 4;
4424 temp_ptr += 4;
4425 rc += temp_fea->name_len;
4426 /* account for prefix user. and trailing null */
4427 rc = rc + 5 + 1;
4428 if(rc<(int)buf_size) {
4429 memcpy(EAData,"user.",5);
4430 EAData+=5;
4431 memcpy(EAData,temp_ptr,temp_fea->name_len);
4432 EAData+=temp_fea->name_len;
4433 /* null terminate name */
4434 *EAData = 0;
4435 EAData = EAData + 1;
4436 } else if(buf_size == 0) {
4437 /* skip copy - calc size only */
4438 } else {
4439 /* stop before overrun buffer */
4440 rc = -ERANGE;
4441 break;
4442 }
4443 name_len -= temp_fea->name_len;
4444 temp_ptr += temp_fea->name_len;
4445 /* account for trailing null */
4446 name_len--;
4447 temp_ptr++;
4448 value_len = le16_to_cpu(temp_fea->value_len);
4449 name_len -= value_len;
4450 temp_ptr += value_len;
4451 /* BB check that temp_ptr is still within smb BB*/
4452 /* no trailing null to account for in value len */
4453 /* go on to next EA */
4454 temp_fea = (struct fea *)temp_ptr;
4455 }
4456 }
4457 }
4458 }
4459 if (pSMB)
4460 cifs_buf_release(pSMB);
4461 if (rc == -EAGAIN)
4462 goto QAllEAsRetry;
4463
4464 return (ssize_t)rc;
4465}
4466
4467ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4468 const unsigned char * searchName,const unsigned char * ea_name,
4469 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004470 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471{
4472 TRANSACTION2_QPI_REQ *pSMB = NULL;
4473 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4474 int rc = 0;
4475 int bytes_returned;
4476 int name_len;
4477 struct fea * temp_fea;
4478 char * temp_ptr;
4479 __u16 params, byte_count;
4480
4481 cFYI(1, ("In Query EA path %s", searchName));
4482QEARetry:
4483 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4484 (void **) &pSMBr);
4485 if (rc)
4486 return rc;
4487
4488 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4489 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004490 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004491 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 name_len++; /* trailing null */
4493 name_len *= 2;
4494 } else { /* BB improve the check for buffer overruns BB */
4495 name_len = strnlen(searchName, PATH_MAX);
4496 name_len++; /* trailing null */
4497 strncpy(pSMB->FileName, searchName, name_len);
4498 }
4499
4500 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4501 pSMB->TotalDataCount = 0;
4502 pSMB->MaxParameterCount = cpu_to_le16(2);
4503 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4504 pSMB->MaxSetupCount = 0;
4505 pSMB->Reserved = 0;
4506 pSMB->Flags = 0;
4507 pSMB->Timeout = 0;
4508 pSMB->Reserved2 = 0;
4509 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4510 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4511 pSMB->DataCount = 0;
4512 pSMB->DataOffset = 0;
4513 pSMB->SetupCount = 1;
4514 pSMB->Reserved3 = 0;
4515 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4516 byte_count = params + 1 /* pad */ ;
4517 pSMB->TotalParameterCount = cpu_to_le16(params);
4518 pSMB->ParameterCount = pSMB->TotalParameterCount;
4519 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4520 pSMB->Reserved4 = 0;
4521 pSMB->hdr.smb_buf_length += byte_count;
4522 pSMB->ByteCount = cpu_to_le16(byte_count);
4523
4524 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4525 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4526 if (rc) {
4527 cFYI(1, ("Send error in Query EA = %d", rc));
4528 } else { /* decode response */
4529 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4530
4531 /* BB also check enough total bytes returned */
4532 /* BB we need to improve the validity checking
4533 of these trans2 responses */
4534 if (rc || (pSMBr->ByteCount < 4))
4535 rc = -EIO; /* bad smb */
4536 /* else if (pFindData){
4537 memcpy((char *) pFindData,
4538 (char *) &pSMBr->hdr.Protocol +
4539 data_offset, kl);
4540 }*/ else {
4541 /* check that length of list is not more than bcc */
4542 /* check that each entry does not go beyond length
4543 of list */
4544 /* check that each element of each entry does not
4545 go beyond end of list */
4546 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4547 struct fealist * ea_response_data;
4548 rc = -ENODATA;
4549 /* validate_trans2_offsets() */
4550 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4551 ea_response_data = (struct fealist *)
4552 (((char *) &pSMBr->hdr.Protocol) +
4553 data_offset);
4554 name_len = le32_to_cpu(ea_response_data->list_len);
4555 cFYI(1,("ea length %d", name_len));
4556 if(name_len <= 8) {
4557 /* returned EA size zeroed at top of function */
4558 cFYI(1,("empty EA list returned from server"));
4559 } else {
4560 /* account for ea list len */
4561 name_len -= 4;
4562 temp_fea = ea_response_data->list;
4563 temp_ptr = (char *)temp_fea;
4564 /* loop through checking if we have a matching
4565 name and then return the associated value */
4566 while(name_len > 0) {
4567 __u16 value_len;
4568 name_len -= 4;
4569 temp_ptr += 4;
4570 value_len = le16_to_cpu(temp_fea->value_len);
4571 /* BB validate that value_len falls within SMB,
4572 even though maximum for name_len is 255 */
4573 if(memcmp(temp_fea->name,ea_name,
4574 temp_fea->name_len) == 0) {
4575 /* found a match */
4576 rc = value_len;
4577 /* account for prefix user. and trailing null */
4578 if(rc<=(int)buf_size) {
4579 memcpy(ea_value,
4580 temp_fea->name+temp_fea->name_len+1,
4581 rc);
4582 /* ea values, unlike ea names,
4583 are not null terminated */
4584 } else if(buf_size == 0) {
4585 /* skip copy - calc size only */
4586 } else {
4587 /* stop before overrun buffer */
4588 rc = -ERANGE;
4589 }
4590 break;
4591 }
4592 name_len -= temp_fea->name_len;
4593 temp_ptr += temp_fea->name_len;
4594 /* account for trailing null */
4595 name_len--;
4596 temp_ptr++;
4597 name_len -= value_len;
4598 temp_ptr += value_len;
4599 /* no trailing null to account for in value len */
4600 /* go on to next EA */
4601 temp_fea = (struct fea *)temp_ptr;
4602 }
4603 }
4604 }
4605 }
4606 if (pSMB)
4607 cifs_buf_release(pSMB);
4608 if (rc == -EAGAIN)
4609 goto QEARetry;
4610
4611 return (ssize_t)rc;
4612}
4613
4614int
4615CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4616 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004617 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4618 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619{
4620 struct smb_com_transaction2_spi_req *pSMB = NULL;
4621 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4622 struct fealist *parm_data;
4623 int name_len;
4624 int rc = 0;
4625 int bytes_returned = 0;
4626 __u16 params, param_offset, byte_count, offset, count;
4627
4628 cFYI(1, ("In SetEA"));
4629SetEARetry:
4630 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4631 (void **) &pSMBr);
4632 if (rc)
4633 return rc;
4634
4635 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4636 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004637 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004638 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 name_len++; /* trailing null */
4640 name_len *= 2;
4641 } else { /* BB improve the check for buffer overruns BB */
4642 name_len = strnlen(fileName, PATH_MAX);
4643 name_len++; /* trailing null */
4644 strncpy(pSMB->FileName, fileName, name_len);
4645 }
4646
4647 params = 6 + name_len;
4648
4649 /* done calculating parms using name_len of file name,
4650 now use name_len to calculate length of ea name
4651 we are going to create in the inode xattrs */
4652 if(ea_name == NULL)
4653 name_len = 0;
4654 else
4655 name_len = strnlen(ea_name,255);
4656
4657 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4658 pSMB->MaxParameterCount = cpu_to_le16(2);
4659 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4660 pSMB->MaxSetupCount = 0;
4661 pSMB->Reserved = 0;
4662 pSMB->Flags = 0;
4663 pSMB->Timeout = 0;
4664 pSMB->Reserved2 = 0;
4665 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4666 InformationLevel) - 4;
4667 offset = param_offset + params;
4668 pSMB->InformationLevel =
4669 cpu_to_le16(SMB_SET_FILE_EA);
4670
4671 parm_data =
4672 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4673 offset);
4674 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4675 pSMB->DataOffset = cpu_to_le16(offset);
4676 pSMB->SetupCount = 1;
4677 pSMB->Reserved3 = 0;
4678 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4679 byte_count = 3 /* pad */ + params + count;
4680 pSMB->DataCount = cpu_to_le16(count);
4681 parm_data->list_len = cpu_to_le32(count);
4682 parm_data->list[0].EA_flags = 0;
4683 /* we checked above that name len is less than 255 */
4684 parm_data->list[0].name_len = (__u8)name_len;;
4685 /* EA names are always ASCII */
4686 if(ea_name)
4687 strncpy(parm_data->list[0].name,ea_name,name_len);
4688 parm_data->list[0].name[name_len] = 0;
4689 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4690 /* caller ensures that ea_value_len is less than 64K but
4691 we need to ensure that it fits within the smb */
4692
4693 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4694 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4695 if(ea_value_len)
4696 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4697
4698 pSMB->TotalDataCount = pSMB->DataCount;
4699 pSMB->ParameterCount = cpu_to_le16(params);
4700 pSMB->TotalParameterCount = pSMB->ParameterCount;
4701 pSMB->Reserved4 = 0;
4702 pSMB->hdr.smb_buf_length += byte_count;
4703 pSMB->ByteCount = cpu_to_le16(byte_count);
4704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4706 if (rc) {
4707 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4708 }
4709
4710 cifs_buf_release(pSMB);
4711
4712 if (rc == -EAGAIN)
4713 goto SetEARetry;
4714
4715 return rc;
4716}
4717
4718#endif