blob: 925881e00ff210e08822cc456337be1734f801d8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French12b3b8f2006-02-09 21:12:47 +00004 * Copyright (C) International Business Machines Corp., 2002,2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * 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"
Steve Frencheeac8042006-01-13 21:34:58 -080040#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
47 {CIFS_PROT, "\2NT LM 0.12"},
48 {CIFS_PROT, "\2POSIX 2"},
49 {BAD_PROT, "\2"}
50};
51#else
52static struct {
53 int index;
54 char *name;
55} protocols[] = {
56 {CIFS_PROT, "\2NT LM 0.12"},
57 {BAD_PROT, "\2"}
58};
59#endif
60
61
62/* Mark as invalid, all open files on tree connections since they
63 were closed when session to server was lost */
64static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
65{
66 struct cifsFileInfo *open_file = NULL;
67 struct list_head * tmp;
68 struct list_head * tmp1;
69
70/* list all files open on tree connection and mark them invalid */
71 write_lock(&GlobalSMBSeslock);
72 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
73 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
74 if(open_file) {
75 open_file->invalidHandle = TRUE;
76 }
77 }
78 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -070079 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
80 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081}
82
83/* If the return code is zero, this function must fill in request_buf pointer */
84static int
85small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
86 void **request_buf /* returned */)
87{
88 int rc = 0;
89
90 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
91 check for tcp and smb session status done differently
92 for those three - in the calling routine */
93 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -080094 if(tcon->tidStatus == CifsExiting) {
95 /* only tree disconnect, open, and write,
96 (and ulogoff which does not have tcon)
97 are allowed as we start force umount */
98 if((smb_command != SMB_COM_WRITE_ANDX) &&
99 (smb_command != SMB_COM_OPEN_ANDX) &&
100 (smb_command != SMB_COM_TREE_DISCONNECT)) {
101 cFYI(1,("can not send cmd %d while umounting",
102 smb_command));
103 return -ENODEV;
104 }
105 }
Steve French31ca3bc2005-04-28 22:41:11 -0700106 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
107 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 struct nls_table *nls_codepage;
109 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700110 reconnect, should be greater than cifs socket
111 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
113 wait_event_interruptible_timeout(tcon->ses->server->response_q,
114 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
115 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
116 /* on "soft" mounts we wait once */
117 if((tcon->retry == FALSE) ||
118 (tcon->ses->status == CifsExiting)) {
119 cFYI(1,("gave up waiting on reconnect in smb_init"));
120 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700121 } /* else "hard" mount - keep retrying
122 until process is killed or server
123 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 } else /* TCP session is reestablished now */
125 break;
126
127 }
128
129 nls_codepage = load_nls_default();
130 /* need to prevent multiple threads trying to
131 simultaneously reconnect the same SMB session */
132 down(&tcon->ses->sesSem);
133 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700134 rc = cifs_setup_session(0, tcon->ses,
135 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
137 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700138 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
139 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700141 /* BB FIXME add code to check if wsize needs
142 update due to negotiated smb buffer size
143 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 if(rc == 0)
145 atomic_inc(&tconInfoReconnectCount);
146
147 cFYI(1, ("reconnect tcon rc = %d", rc));
148 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700149 it is safer (and faster) to reopen files
150 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700153 know whether we can continue or not without
154 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 switch(smb_command) {
156 case SMB_COM_READ_ANDX:
157 case SMB_COM_WRITE_ANDX:
158 case SMB_COM_CLOSE:
159 case SMB_COM_FIND_CLOSE2:
160 case SMB_COM_LOCKING_ANDX: {
161 unload_nls(nls_codepage);
162 return -EAGAIN;
163 }
164 }
165 } else {
166 up(&tcon->ses->sesSem);
167 }
168 unload_nls(nls_codepage);
169
170 } else {
171 return -EIO;
172 }
173 }
174 if(rc)
175 return rc;
176
177 *request_buf = cifs_small_buf_get();
178 if (*request_buf == NULL) {
179 /* BB should we add a retry in here if not a writepage? */
180 return -ENOMEM;
181 }
182
183 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
184
Steve Frencha45443472005-08-24 13:59:35 -0700185 if(tcon != NULL)
186 cifs_stats_inc(&tcon->num_smbs_sent);
187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000189}
190
191#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French12b3b8f2006-02-09 21:12:47 +0000192int
Steve French5815449d2006-02-14 01:36:20 +0000193small_smb_init_no_tc(const int smb_command, const int wct,
194 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000195{
196 int rc;
197 struct smb_hdr * buffer;
198
Steve French5815449d2006-02-14 01:36:20 +0000199 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000200 if(rc)
201 return rc;
202
Steve French04fdabe2006-02-10 05:52:50 +0000203 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000204 buffer->Mid = GetNextMid(ses->server);
205 if (ses->capabilities & CAP_UNICODE)
206 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000207 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000208 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
209
210 /* uid, tid can stay at zero as set in header assemble */
211
212 /* BB add support for turning on the signing when
213 this function is used after 1st of session setup requests */
214
215 return rc;
216}
Steve French5815449d2006-02-14 01:36:20 +0000217#endif /* CONFIG_CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219/* If the return code is zero, this function must fill in request_buf pointer */
220static int
221smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
222 void **request_buf /* returned */ ,
223 void **response_buf /* returned */ )
224{
225 int rc = 0;
226
227 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
228 check for tcp and smb session status done differently
229 for those three - in the calling routine */
230 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800231 if(tcon->tidStatus == CifsExiting) {
232 /* only tree disconnect, open, and write,
233 (and ulogoff which does not have tcon)
234 are allowed as we start force umount */
235 if((smb_command != SMB_COM_WRITE_ANDX) &&
236 (smb_command != SMB_COM_OPEN_ANDX) &&
237 (smb_command != SMB_COM_TREE_DISCONNECT)) {
238 cFYI(1,("can not send cmd %d while umounting",
239 smb_command));
240 return -ENODEV;
241 }
242 }
243
Steve French31ca3bc2005-04-28 22:41:11 -0700244 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
245 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700247 /* Give Demultiplex thread up to 10 seconds to
248 reconnect, should be greater than cifs socket
249 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
251 wait_event_interruptible_timeout(tcon->ses->server->response_q,
252 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700253 if(tcon->ses->server->tcpStatus ==
254 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 /* on "soft" mounts we wait once */
256 if((tcon->retry == FALSE) ||
257 (tcon->ses->status == CifsExiting)) {
258 cFYI(1,("gave up waiting on reconnect in smb_init"));
259 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700260 } /* else "hard" mount - keep retrying
261 until process is killed or server
262 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 } else /* TCP session is reestablished now */
264 break;
265
266 }
267
268 nls_codepage = load_nls_default();
269 /* need to prevent multiple threads trying to
270 simultaneously reconnect the same SMB session */
271 down(&tcon->ses->sesSem);
272 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700273 rc = cifs_setup_session(0, tcon->ses,
274 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
276 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700277 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
278 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700280 /* BB FIXME add code to check if wsize needs
281 update due to negotiated smb buffer size
282 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 if(rc == 0)
284 atomic_inc(&tconInfoReconnectCount);
285
286 cFYI(1, ("reconnect tcon rc = %d", rc));
287 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700288 it is safer (and faster) to reopen files
289 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700292 know whether we can continue or not without
293 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 switch(smb_command) {
295 case SMB_COM_READ_ANDX:
296 case SMB_COM_WRITE_ANDX:
297 case SMB_COM_CLOSE:
298 case SMB_COM_FIND_CLOSE2:
299 case SMB_COM_LOCKING_ANDX: {
300 unload_nls(nls_codepage);
301 return -EAGAIN;
302 }
303 }
304 } else {
305 up(&tcon->ses->sesSem);
306 }
307 unload_nls(nls_codepage);
308
309 } else {
310 return -EIO;
311 }
312 }
313 if(rc)
314 return rc;
315
316 *request_buf = cifs_buf_get();
317 if (*request_buf == NULL) {
318 /* BB should we add a retry in here if not a writepage? */
319 return -ENOMEM;
320 }
321 /* Although the original thought was we needed the response buf for */
322 /* potential retries of smb operations it turns out we can determine */
323 /* from the mid flags when the request buffer can be resent without */
324 /* having to use a second distinct buffer for the response */
325 *response_buf = *request_buf;
326
327 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
328 wct /*wct */ );
329
Steve Frencha45443472005-08-24 13:59:35 -0700330 if(tcon != NULL)
331 cifs_stats_inc(&tcon->num_smbs_sent);
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 return rc;
334}
335
336static int validate_t2(struct smb_t2_rsp * pSMB)
337{
338 int rc = -EINVAL;
339 int total_size;
340 char * pBCC;
341
342 /* check for plausible wct, bcc and t2 data and parm sizes */
343 /* check for parm and data offset going beyond end of smb */
344 if(pSMB->hdr.WordCount >= 10) {
345 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
346 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
347 /* check that bcc is at least as big as parms + data */
348 /* check that bcc is less than negotiated smb buffer */
349 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
350 if(total_size < 512) {
351 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
352 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700353 pBCC = (pSMB->hdr.WordCount * 2) +
354 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 (char *)pSMB;
356 if((total_size <= (*(u16 *)pBCC)) &&
357 (total_size <
358 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
359 return 0;
360 }
361
362 }
363 }
364 }
365 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
366 sizeof(struct smb_t2_rsp) + 16);
367 return rc;
368}
369int
370CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
371{
372 NEGOTIATE_REQ *pSMB;
373 NEGOTIATE_RSP *pSMBr;
374 int rc = 0;
375 int bytes_returned;
376 struct TCP_Server_Info * server;
377 u16 count;
378
379 if(ses->server)
380 server = ses->server;
381 else {
382 rc = -EIO;
383 return rc;
384 }
385 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
386 (void **) &pSMB, (void **) &pSMBr);
387 if (rc)
388 return rc;
Steve French1982c342005-08-17 12:38:22 -0700389 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
391 if (extended_security)
392 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
393
394 count = strlen(protocols[0].name) + 1;
395 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
396 /* null guaranteed to be at end of source and target buffers anyway */
397
398 pSMB->hdr.smb_buf_length += count;
399 pSMB->ByteCount = cpu_to_le16(count);
400
401 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
402 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
403 if (rc == 0) {
Steve Frencheeac8042006-01-13 21:34:58 -0800404 server->secMode = pSMBr->SecurityMode;
405 if((server->secMode & SECMODE_USER) == 0)
406 cFYI(1,("share mode security"));
407 server->secType = NTLM; /* BB override default for
Steve French09d1db52005-04-28 22:41:08 -0700408 NTLMv2 or kerberos v5 */
409 /* one byte - no need to convert this or EncryptionKeyLen
410 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
412 /* probably no need to store and check maxvcs */
413 server->maxBuf =
414 min(le32_to_cpu(pSMBr->MaxBufferSize),
415 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
416 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve Frencheeac8042006-01-13 21:34:58 -0800417 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
419 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
420 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
421 /* BB with UTC do we ever need to be using srvr timezone? */
422 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
423 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
424 CIFS_CRYPTO_KEY_SIZE);
425 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
426 && (pSMBr->EncryptionKeyLength == 0)) {
427 /* decode security blob */
428 } else
429 rc = -EIO;
430
431 /* BB might be helpful to save off the domain of server here */
432
433 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
434 (server->capabilities & CAP_EXTENDED_SECURITY)) {
435 count = pSMBr->ByteCount;
436 if (count < 16)
437 rc = -EIO;
438 else if (count == 16) {
439 server->secType = RawNTLMSSP;
440 if (server->socketUseCount.counter > 1) {
441 if (memcmp
442 (server->server_GUID,
443 pSMBr->u.extended_response.
444 GUID, 16) != 0) {
Steve Frencheeac8042006-01-13 21:34:58 -0800445 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 memcpy(server->
447 server_GUID,
448 pSMBr->u.
449 extended_response.
450 GUID, 16);
451 }
452 } else
453 memcpy(server->server_GUID,
454 pSMBr->u.extended_response.
455 GUID, 16);
456 } else {
457 rc = decode_negTokenInit(pSMBr->u.
458 extended_response.
459 SecurityBlob,
460 count - 16,
461 &server->secType);
462 if(rc == 1) {
463 /* BB Need to fill struct for sessetup here */
464 rc = -EOPNOTSUPP;
465 } else {
466 rc = -EINVAL;
467 }
468 }
469 } else
470 server->capabilities &= ~CAP_EXTENDED_SECURITY;
471 if(sign_CIFS_PDUs == FALSE) {
472 if(server->secMode & SECMODE_SIGN_REQUIRED)
473 cERROR(1,
474 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700475 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 } else if(sign_CIFS_PDUs == 1) {
477 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700478 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 }
480
481 }
Steve French1982c342005-08-17 12:38:22 -0700482
Steve French4a6d87f2005-08-13 08:15:54 -0700483 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 return rc;
485}
486
487int
488CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
489{
490 struct smb_hdr *smb_buffer;
491 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
492 int rc = 0;
493 int length;
494
495 cFYI(1, ("In tree disconnect"));
496 /*
497 * If last user of the connection and
498 * connection alive - disconnect it
499 * If this is the last connection on the server session disconnect it
500 * (and inside session disconnect we should check if tcp socket needs
501 * to be freed and kernel thread woken up).
502 */
503 if (tcon)
504 down(&tcon->tconSem);
505 else
506 return -EIO;
507
508 atomic_dec(&tcon->useCount);
509 if (atomic_read(&tcon->useCount) > 0) {
510 up(&tcon->tconSem);
511 return -EBUSY;
512 }
513
514 /* No need to return error on this operation if tid invalidated and
515 closed on server already e.g. due to tcp session crashing */
516 if(tcon->tidStatus == CifsNeedReconnect) {
517 up(&tcon->tconSem);
518 return 0;
519 }
520
521 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
522 up(&tcon->tconSem);
523 return -EIO;
524 }
Steve French09d1db52005-04-28 22:41:08 -0700525 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
526 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 if (rc) {
528 up(&tcon->tconSem);
529 return rc;
530 } else {
531 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
534 &length, 0);
535 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700536 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538 if (smb_buffer)
539 cifs_small_buf_release(smb_buffer);
540 up(&tcon->tconSem);
541
542 /* No need to return error on this operation if tid invalidated and
543 closed on server already e.g. due to tcp session crashing */
544 if (rc == -EAGAIN)
545 rc = 0;
546
547 return rc;
548}
549
550int
551CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
552{
553 struct smb_hdr *smb_buffer_response;
554 LOGOFF_ANDX_REQ *pSMB;
555 int rc = 0;
556 int length;
557
558 cFYI(1, ("In SMBLogoff for session disconnect"));
559 if (ses)
560 down(&ses->sesSem);
561 else
562 return -EIO;
563
564 atomic_dec(&ses->inUse);
565 if (atomic_read(&ses->inUse) > 0) {
566 up(&ses->sesSem);
567 return -EBUSY;
568 }
569 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
570 if (rc) {
571 up(&ses->sesSem);
572 return rc;
573 }
574
575 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
576
577 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700578 pSMB->hdr.Mid = GetNextMid(ses->server);
579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 if(ses->server->secMode &
581 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
582 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
583 }
584
585 pSMB->hdr.Uid = ses->Suid;
586
587 pSMB->AndXCommand = 0xFF;
588 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
589 smb_buffer_response, &length, 0);
590 if (ses->server) {
591 atomic_dec(&ses->server->socketUseCount);
592 if (atomic_read(&ses->server->socketUseCount) == 0) {
593 spin_lock(&GlobalMid_Lock);
594 ses->server->tcpStatus = CifsExiting;
595 spin_unlock(&GlobalMid_Lock);
596 rc = -ESHUTDOWN;
597 }
598 }
Steve Frencha59c6582005-08-17 12:12:19 -0700599 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700600 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602 /* if session dead then we do not need to do ulogoff,
603 since server closed smb session, no sense reporting
604 error */
605 if (rc == -EAGAIN)
606 rc = 0;
607 return rc;
608}
609
610int
Steve French737b7582005-04-28 22:41:06 -0700611CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
612 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
614 DELETE_FILE_REQ *pSMB = NULL;
615 DELETE_FILE_RSP *pSMBr = NULL;
616 int rc = 0;
617 int bytes_returned;
618 int name_len;
619
620DelFileRetry:
621 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
622 (void **) &pSMBr);
623 if (rc)
624 return rc;
625
626 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
627 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500628 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700629 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 name_len++; /* trailing null */
631 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700632 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 name_len = strnlen(fileName, PATH_MAX);
634 name_len++; /* trailing null */
635 strncpy(pSMB->fileName, fileName, name_len);
636 }
637 pSMB->SearchAttributes =
638 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
639 pSMB->BufferFormat = 0x04;
640 pSMB->hdr.smb_buf_length += name_len + 1;
641 pSMB->ByteCount = cpu_to_le16(name_len + 1);
642 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
643 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700644 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (rc) {
646 cFYI(1, ("Error in RMFile = %d", rc));
647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 cifs_buf_release(pSMB);
650 if (rc == -EAGAIN)
651 goto DelFileRetry;
652
653 return rc;
654}
655
656int
Steve French737b7582005-04-28 22:41:06 -0700657CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
658 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659{
660 DELETE_DIRECTORY_REQ *pSMB = NULL;
661 DELETE_DIRECTORY_RSP *pSMBr = NULL;
662 int rc = 0;
663 int bytes_returned;
664 int name_len;
665
666 cFYI(1, ("In CIFSSMBRmDir"));
667RmDirRetry:
668 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
669 (void **) &pSMBr);
670 if (rc)
671 return rc;
672
673 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700674 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
675 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 name_len++; /* trailing null */
677 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700678 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 name_len = strnlen(dirName, PATH_MAX);
680 name_len++; /* trailing null */
681 strncpy(pSMB->DirName, dirName, name_len);
682 }
683
684 pSMB->BufferFormat = 0x04;
685 pSMB->hdr.smb_buf_length += name_len + 1;
686 pSMB->ByteCount = cpu_to_le16(name_len + 1);
687 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
688 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700689 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 if (rc) {
691 cFYI(1, ("Error in RMDir = %d", rc));
692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 cifs_buf_release(pSMB);
695 if (rc == -EAGAIN)
696 goto RmDirRetry;
697 return rc;
698}
699
700int
701CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700702 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 int rc = 0;
705 CREATE_DIRECTORY_REQ *pSMB = NULL;
706 CREATE_DIRECTORY_RSP *pSMBr = NULL;
707 int bytes_returned;
708 int name_len;
709
710 cFYI(1, ("In CIFSSMBMkDir"));
711MkDirRetry:
712 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
713 (void **) &pSMBr);
714 if (rc)
715 return rc;
716
717 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500718 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700719 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 name_len++; /* trailing null */
721 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700722 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 name_len = strnlen(name, PATH_MAX);
724 name_len++; /* trailing null */
725 strncpy(pSMB->DirName, name, name_len);
726 }
727
728 pSMB->BufferFormat = 0x04;
729 pSMB->hdr.smb_buf_length += name_len + 1;
730 pSMB->ByteCount = cpu_to_le16(name_len + 1);
731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
732 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700733 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 if (rc) {
735 cFYI(1, ("Error in Mkdir = %d", rc));
736 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 cifs_buf_release(pSMB);
739 if (rc == -EAGAIN)
740 goto MkDirRetry;
741 return rc;
742}
743
Steve Frencha9d02ad2005-08-24 23:06:05 -0700744static __u16 convert_disposition(int disposition)
745{
746 __u16 ofun = 0;
747
748 switch (disposition) {
749 case FILE_SUPERSEDE:
750 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
751 break;
752 case FILE_OPEN:
753 ofun = SMBOPEN_OAPPEND;
754 break;
755 case FILE_CREATE:
756 ofun = SMBOPEN_OCREATE;
757 break;
758 case FILE_OPEN_IF:
759 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
760 break;
761 case FILE_OVERWRITE:
762 ofun = SMBOPEN_OTRUNC;
763 break;
764 case FILE_OVERWRITE_IF:
765 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
766 break;
767 default:
768 cFYI(1,("unknown disposition %d",disposition));
769 ofun = SMBOPEN_OAPPEND; /* regular open */
770 }
771 return ofun;
772}
773
774int
775SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
776 const char *fileName, const int openDisposition,
777 const int access_flags, const int create_options, __u16 * netfid,
778 int *pOplock, FILE_ALL_INFO * pfile_info,
779 const struct nls_table *nls_codepage, int remap)
780{
781 int rc = -EACCES;
782 OPENX_REQ *pSMB = NULL;
783 OPENX_RSP *pSMBr = NULL;
784 int bytes_returned;
785 int name_len;
786 __u16 count;
787
788OldOpenRetry:
789 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
790 (void **) &pSMBr);
791 if (rc)
792 return rc;
793
794 pSMB->AndXCommand = 0xFF; /* none */
795
796 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
797 count = 1; /* account for one byte pad to word boundary */
798 name_len =
799 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
800 fileName, PATH_MAX, nls_codepage, remap);
801 name_len++; /* trailing null */
802 name_len *= 2;
803 } else { /* BB improve check for buffer overruns BB */
804 count = 0; /* no pad */
805 name_len = strnlen(fileName, PATH_MAX);
806 name_len++; /* trailing null */
807 strncpy(pSMB->fileName, fileName, name_len);
808 }
809 if (*pOplock & REQ_OPLOCK)
810 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
811 else if (*pOplock & REQ_BATCHOPLOCK) {
812 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
813 }
814 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
815 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
816 /* 0 = read
817 1 = write
818 2 = rw
819 3 = execute
820 */
821 pSMB->Mode = cpu_to_le16(2);
822 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
823 /* set file as system file if special file such
824 as fifo and server expecting SFU style and
825 no Unix extensions */
826
827 if(create_options & CREATE_OPTION_SPECIAL)
828 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
829 else
Steve French3e87d802005-09-18 20:49:21 -0700830 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700831
832 /* if ((omode & S_IWUGO) == 0)
833 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
834 /* Above line causes problems due to vfs splitting create into two
835 pieces - need to set mode after file created not while it is
836 being created */
837
838 /* BB FIXME BB */
839/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
840 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700841
842 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700843 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700844 count += name_len;
845 pSMB->hdr.smb_buf_length += count;
846
847 pSMB->ByteCount = cpu_to_le16(count);
848 /* long_op set to 1 to allow for oplock break timeouts */
849 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
850 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
851 cifs_stats_inc(&tcon->num_opens);
852 if (rc) {
853 cFYI(1, ("Error in Open = %d", rc));
854 } else {
855 /* BB verify if wct == 15 */
856
857/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
858
859 *netfid = pSMBr->Fid; /* cifs fid stays in le */
860 /* Let caller know file was created so we can set the mode. */
861 /* Do we care about the CreateAction in any other cases? */
862 /* BB FIXME BB */
863/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
864 *pOplock |= CIFS_CREATE_ACTION; */
865 /* BB FIXME END */
866
867 if(pfile_info) {
868 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
869 pfile_info->LastAccessTime = 0; /* BB fixme */
870 pfile_info->LastWriteTime = 0; /* BB fixme */
871 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700872 pfile_info->Attributes =
873 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700874 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700875 pfile_info->AllocationSize =
876 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
877 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700878 pfile_info->NumberOfLinks = cpu_to_le32(1);
879 }
880 }
881
882 cifs_buf_release(pSMB);
883 if (rc == -EAGAIN)
884 goto OldOpenRetry;
885 return rc;
886}
887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888int
889CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
890 const char *fileName, const int openDisposition,
891 const int access_flags, const int create_options, __u16 * netfid,
892 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700893 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
895 int rc = -EACCES;
896 OPEN_REQ *pSMB = NULL;
897 OPEN_RSP *pSMBr = NULL;
898 int bytes_returned;
899 int name_len;
900 __u16 count;
901
902openRetry:
903 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
904 (void **) &pSMBr);
905 if (rc)
906 return rc;
907
908 pSMB->AndXCommand = 0xFF; /* none */
909
910 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
911 count = 1; /* account for one byte pad to word boundary */
912 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500913 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700914 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 name_len++; /* trailing null */
916 name_len *= 2;
917 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700918 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 count = 0; /* no pad */
920 name_len = strnlen(fileName, PATH_MAX);
921 name_len++; /* trailing null */
922 pSMB->NameLength = cpu_to_le16(name_len);
923 strncpy(pSMB->fileName, fileName, name_len);
924 }
925 if (*pOplock & REQ_OPLOCK)
926 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
927 else if (*pOplock & REQ_BATCHOPLOCK) {
928 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
929 }
930 pSMB->DesiredAccess = cpu_to_le32(access_flags);
931 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700932 /* set file as system file if special file such
933 as fifo and server expecting SFU style and
934 no Unix extensions */
935 if(create_options & CREATE_OPTION_SPECIAL)
936 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
937 else
938 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 /* XP does not handle ATTR_POSIX_SEMANTICS */
940 /* but it helps speed up case sensitive checks for other
941 servers such as Samba */
942 if (tcon->ses->capabilities & CAP_UNIX)
943 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
944
945 /* if ((omode & S_IWUGO) == 0)
946 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
947 /* Above line causes problems due to vfs splitting create into two
948 pieces - need to set mode after file created not while it is
949 being created */
950 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
951 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700952 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700953 /* BB Expirement with various impersonation levels and verify */
954 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 pSMB->SecurityFlags =
956 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
957
958 count += name_len;
959 pSMB->hdr.smb_buf_length += count;
960
961 pSMB->ByteCount = cpu_to_le16(count);
962 /* long_op set to 1 to allow for oplock break timeouts */
963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
964 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha45443472005-08-24 13:59:35 -0700965 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 if (rc) {
967 cFYI(1, ("Error in Open = %d", rc));
968 } else {
Steve French09d1db52005-04-28 22:41:08 -0700969 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 *netfid = pSMBr->Fid; /* cifs fid stays in le */
971 /* Let caller know file was created so we can set the mode. */
972 /* Do we care about the CreateAction in any other cases? */
973 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
974 *pOplock |= CIFS_CREATE_ACTION;
975 if(pfile_info) {
976 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
977 36 /* CreationTime to Attributes */);
978 /* the file_info buf is endian converted by caller */
979 pfile_info->AllocationSize = pSMBr->AllocationSize;
980 pfile_info->EndOfFile = pSMBr->EndOfFile;
981 pfile_info->NumberOfLinks = cpu_to_le32(1);
982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 cifs_buf_release(pSMB);
986 if (rc == -EAGAIN)
987 goto openRetry;
988 return rc;
989}
990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991int
992CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -0800993 const int netfid, const unsigned int count,
994 const __u64 lseek, unsigned int *nbytes, char **buf,
995 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996{
997 int rc = -EACCES;
998 READ_REQ *pSMB = NULL;
999 READ_RSP *pSMBr = NULL;
1000 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001001 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001002 int resp_buf_type = 0;
1003 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001006 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1007 wct = 12;
1008 else
1009 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001012 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 if (rc)
1014 return rc;
1015
1016 /* tcon and ses pointer are checked in smb_init */
1017 if (tcon->ses->server == NULL)
1018 return -ECONNABORTED;
1019
Steve Frenchec637e32005-12-12 20:53:18 -08001020 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 pSMB->Fid = netfid;
1022 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001023 if(wct == 12)
1024 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001025 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1026 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 pSMB->Remaining = 0;
1029 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1030 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001031 if(wct == 12)
1032 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1033 else {
1034 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001035 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001036 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001037 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001038 }
Steve Frenchec637e32005-12-12 20:53:18 -08001039
1040 iov[0].iov_base = (char *)pSMB;
1041 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1042 rc = SendReceive2(xid, tcon->ses, iov,
1043 1 /* num iovecs */,
1044 &resp_buf_type, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001045 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001046 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 if (rc) {
1048 cERROR(1, ("Send error in read = %d", rc));
1049 } else {
1050 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1051 data_length = data_length << 16;
1052 data_length += le16_to_cpu(pSMBr->DataLength);
1053 *nbytes = data_length;
1054
1055 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001056 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 || (data_length > count)) {
1058 cFYI(1,("bad length %d for count %d",data_length,count));
1059 rc = -EIO;
1060 *nbytes = 0;
1061 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001062 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001064/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1065 cERROR(1,("Faulting on read rc = %d",rc));
1066 rc = -EFAULT;
1067 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001069 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
1071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Steve French4b8f9302006-02-26 16:41:18 +00001073/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001074 if(*buf) {
1075 if(resp_buf_type == CIFS_SMALL_BUFFER)
1076 cifs_small_buf_release(iov[0].iov_base);
1077 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1078 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001079 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1080 /* return buffer to caller to free */
1081 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001082 if(resp_buf_type == CIFS_SMALL_BUFFER)
1083 *pbuf_type = CIFS_SMALL_BUFFER;
1084 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1085 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001086 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001087
1088 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 since file handle passed in no longer valid */
1090 return rc;
1091}
1092
Steve Frenchec637e32005-12-12 20:53:18 -08001093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094int
1095CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1096 const int netfid, const unsigned int count,
1097 const __u64 offset, unsigned int *nbytes, const char *buf,
1098 const char __user * ubuf, const int long_op)
1099{
1100 int rc = -EACCES;
1101 WRITE_REQ *pSMB = NULL;
1102 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001103 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 __u32 bytes_sent;
1105 __u16 byte_count;
1106
1107 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001108 if(tcon->ses == NULL)
1109 return -ECONNABORTED;
1110
1111 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1112 wct = 14;
1113 else
1114 wct = 12;
1115
1116 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 (void **) &pSMBr);
1118 if (rc)
1119 return rc;
1120 /* tcon and ses pointer are checked in smb_init */
1121 if (tcon->ses->server == NULL)
1122 return -ECONNABORTED;
1123
1124 pSMB->AndXCommand = 0xFF; /* none */
1125 pSMB->Fid = netfid;
1126 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001127 if(wct == 14)
1128 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1129 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1130 return -EIO;
1131
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 pSMB->Reserved = 0xFFFFFFFF;
1133 pSMB->WriteMode = 0;
1134 pSMB->Remaining = 0;
1135
1136 /* Can increase buffer size if buffer is big enough in some cases - ie we
1137 can send more if LARGE_WRITE_X capability returned by the server and if
1138 our buffer is big enough or if we convert to iovecs on socket writes
1139 and eliminate the copy to the CIFS buffer */
1140 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1141 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1142 } else {
1143 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1144 & ~0xFF;
1145 }
1146
1147 if (bytes_sent > count)
1148 bytes_sent = count;
1149 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001150 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 if(buf)
1152 memcpy(pSMB->Data,buf,bytes_sent);
1153 else if(ubuf) {
1154 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1155 cifs_buf_release(pSMB);
1156 return -EFAULT;
1157 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001158 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 /* No buffer */
1160 cifs_buf_release(pSMB);
1161 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001162 } /* else setting file size with write of zero bytes */
1163 if(wct == 14)
1164 byte_count = bytes_sent + 1; /* pad */
1165 else /* wct == 12 */ {
1166 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1169 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001170 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001171
1172 if(wct == 14)
1173 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001174 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001175 struct smb_com_writex_req * pSMBW =
1176 (struct smb_com_writex_req *)pSMB;
1177 pSMBW->ByteCount = cpu_to_le16(byte_count);
1178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
1180 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1181 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001182 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 if (rc) {
1184 cFYI(1, ("Send error in write = %d", rc));
1185 *nbytes = 0;
1186 } else {
1187 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1188 *nbytes = (*nbytes) << 16;
1189 *nbytes += le16_to_cpu(pSMBr->Count);
1190 }
1191
1192 cifs_buf_release(pSMB);
1193
1194 /* Note: On -EAGAIN error only caller can retry on handle based calls
1195 since file handle passed in no longer valid */
1196
1197 return rc;
1198}
1199
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001200int
1201CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001203 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1204 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
1206 int rc = -EACCES;
1207 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001208 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001209 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001210 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
Steve Frenchff7feac2005-11-15 16:45:16 -08001212 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1213
Steve French8cc64c62005-10-03 13:49:43 -07001214 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1215 wct = 14;
1216 else
1217 wct = 12;
1218 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 if (rc)
1220 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 /* tcon and ses pointer are checked in smb_init */
1222 if (tcon->ses->server == NULL)
1223 return -ECONNABORTED;
1224
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001225 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 pSMB->Fid = netfid;
1227 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001228 if(wct == 14)
1229 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1230 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1231 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 pSMB->Reserved = 0xFFFFFFFF;
1233 pSMB->WriteMode = 0;
1234 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 pSMB->DataOffset =
1237 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1238
Steve French3e844692005-10-03 13:37:24 -07001239 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1240 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001241 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001242 if(wct == 14)
1243 pSMB->hdr.smb_buf_length += count+1;
1244 else /* wct == 12 */
1245 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1246 if(wct == 14)
1247 pSMB->ByteCount = cpu_to_le16(count + 1);
1248 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1249 struct smb_com_writex_req * pSMBW =
1250 (struct smb_com_writex_req *)pSMB;
1251 pSMBW->ByteCount = cpu_to_le16(count + 5);
1252 }
Steve French3e844692005-10-03 13:37:24 -07001253 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001254 if(wct == 14)
1255 iov[0].iov_len = smb_hdr_len + 4;
1256 else /* wct == 12 pad bigger by four bytes */
1257 iov[0].iov_len = smb_hdr_len + 8;
1258
Steve French3e844692005-10-03 13:37:24 -07001259
Steve Frenchec637e32005-12-12 20:53:18 -08001260 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001261 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001262 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001264 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001266 } else if(resp_buf_type == 0) {
1267 /* presumably this can not happen, but best to be safe */
1268 rc = -EIO;
1269 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001270 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001271 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001272 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1273 *nbytes = (*nbytes) << 16;
1274 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
Steve French4b8f9302006-02-26 16:41:18 +00001277/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001278 if(resp_buf_type == CIFS_SMALL_BUFFER)
1279 cifs_small_buf_release(iov[0].iov_base);
1280 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1281 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
1283 /* Note: On -EAGAIN error only caller can retry on handle based calls
1284 since file handle passed in no longer valid */
1285
1286 return rc;
1287}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001288
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290int
1291CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1292 const __u16 smb_file_id, const __u64 len,
1293 const __u64 offset, const __u32 numUnlock,
1294 const __u32 numLock, const __u8 lockType, const int waitFlag)
1295{
1296 int rc = 0;
1297 LOCK_REQ *pSMB = NULL;
1298 LOCK_RSP *pSMBr = NULL;
1299 int bytes_returned;
1300 int timeout = 0;
1301 __u16 count;
1302
1303 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001304 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1305
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 if (rc)
1307 return rc;
1308
Steve French46810cb2005-04-28 22:41:09 -07001309 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1312 timeout = -1; /* no response expected */
1313 pSMB->Timeout = 0;
1314 } else if (waitFlag == TRUE) {
1315 timeout = 3; /* blocking operation, no timeout */
1316 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1317 } else {
1318 pSMB->Timeout = 0;
1319 }
1320
1321 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1322 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1323 pSMB->LockType = lockType;
1324 pSMB->AndXCommand = 0xFF; /* none */
1325 pSMB->Fid = smb_file_id; /* netfid stays le */
1326
1327 if((numLock != 0) || (numUnlock != 0)) {
1328 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1329 /* BB where to store pid high? */
1330 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1331 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1332 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1333 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1334 count = sizeof(LOCKING_ANDX_RANGE);
1335 } else {
1336 /* oplock break */
1337 count = 0;
1338 }
1339 pSMB->hdr.smb_buf_length += count;
1340 pSMB->ByteCount = cpu_to_le16(count);
1341
1342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha45443472005-08-24 13:59:35 -07001344 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 if (rc) {
1346 cFYI(1, ("Send error in Lock = %d", rc));
1347 }
Steve French46810cb2005-04-28 22:41:09 -07001348 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350 /* Note: On -EAGAIN error only caller can retry on handle based calls
1351 since file handle passed in no longer valid */
1352 return rc;
1353}
1354
1355int
Steve French08547b02006-02-28 22:39:25 +00001356CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1357 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001358 struct file_lock *pLockData, const __u16 lock_type,
1359 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001360{
1361 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1362 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1363 char *data_offset;
1364 struct cifs_posix_lock *parm_data;
1365 int rc = 0;
1366 int bytes_returned = 0;
1367 __u16 params, param_offset, offset, byte_count, count;
1368
1369 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001370
1371 if(pLockData == NULL)
1372 return EINVAL;
1373
Steve French08547b02006-02-28 22:39:25 +00001374 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1375
1376 if (rc)
1377 return rc;
1378
1379 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1380
1381 params = 6;
1382 pSMB->MaxSetupCount = 0;
1383 pSMB->Reserved = 0;
1384 pSMB->Flags = 0;
1385 pSMB->Timeout = 0;
1386 pSMB->Reserved2 = 0;
1387 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1388 offset = param_offset + params;
1389
1390 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1391
1392 count = sizeof(struct cifs_posix_lock);
1393 pSMB->MaxParameterCount = cpu_to_le16(2);
1394 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1395 pSMB->SetupCount = 1;
1396 pSMB->Reserved3 = 0;
1397 if(get_flag)
1398 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1399 else
1400 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1401 byte_count = 3 /* pad */ + params + count;
1402 pSMB->DataCount = cpu_to_le16(count);
1403 pSMB->ParameterCount = cpu_to_le16(params);
1404 pSMB->TotalDataCount = pSMB->DataCount;
1405 pSMB->TotalParameterCount = pSMB->ParameterCount;
1406 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1407 parm_data = (struct cifs_posix_lock *)
1408 (((char *) &pSMB->hdr.Protocol) + offset);
1409
1410 parm_data->lock_type = cpu_to_le16(lock_type);
1411 if(waitFlag)
Steve Frenchcec6815a2006-05-30 18:07:17 +00001412 parm_data->lock_flags = cpu_to_le16(1);
Steve French08547b02006-02-28 22:39:25 +00001413 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001414 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001415 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001416
1417 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001418 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001419 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1420 pSMB->Reserved4 = 0;
1421 pSMB->hdr.smb_buf_length += byte_count;
1422 pSMB->ByteCount = cpu_to_le16(byte_count);
1423 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1425 if (rc) {
1426 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001427 } else if (get_flag) {
1428 /* lock structure can be returned on get */
1429 __u16 data_offset;
1430 __u16 data_count;
1431 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001432
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001433 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1434 rc = -EIO; /* bad smb */
1435 goto plk_err_exit;
1436 }
1437 if(pLockData == NULL) {
1438 rc = -EINVAL;
1439 goto plk_err_exit;
1440 }
1441 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1442 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1443 if(data_count < sizeof(struct cifs_posix_lock)) {
1444 rc = -EIO;
1445 goto plk_err_exit;
1446 }
1447 parm_data = (struct cifs_posix_lock *)
1448 ((char *)&pSMBr->hdr.Protocol + data_offset);
1449 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1450 pLockData->fl_type = F_UNLCK;
1451 }
1452
1453plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001454 if (pSMB)
1455 cifs_small_buf_release(pSMB);
1456
1457 /* Note: On -EAGAIN error only caller can retry on handle based calls
1458 since file handle passed in no longer valid */
1459
1460 return rc;
1461}
1462
1463
1464int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1466{
1467 int rc = 0;
1468 CLOSE_REQ *pSMB = NULL;
1469 CLOSE_RSP *pSMBr = NULL;
1470 int bytes_returned;
1471 cFYI(1, ("In CIFSSMBClose"));
1472
1473/* do not retry on dead session on close */
1474 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1475 if(rc == -EAGAIN)
1476 return 0;
1477 if (rc)
1478 return rc;
1479
1480 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1481
1482 pSMB->FileID = (__u16) smb_file_id;
1483 pSMB->LastWriteTime = 0;
1484 pSMB->ByteCount = 0;
1485 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1486 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001487 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 if (rc) {
1489 if(rc!=-EINTR) {
1490 /* EINTR is expected when user ctl-c to kill app */
1491 cERROR(1, ("Send error in Close = %d", rc));
1492 }
1493 }
1494
1495 cifs_small_buf_release(pSMB);
1496
1497 /* Since session is dead, file will be closed on server already */
1498 if(rc == -EAGAIN)
1499 rc = 0;
1500
1501 return rc;
1502}
1503
1504int
1505CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1506 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001507 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508{
1509 int rc = 0;
1510 RENAME_REQ *pSMB = NULL;
1511 RENAME_RSP *pSMBr = NULL;
1512 int bytes_returned;
1513 int name_len, name_len2;
1514 __u16 count;
1515
1516 cFYI(1, ("In CIFSSMBRename"));
1517renameRetry:
1518 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1519 (void **) &pSMBr);
1520 if (rc)
1521 return rc;
1522
1523 pSMB->BufferFormat = 0x04;
1524 pSMB->SearchAttributes =
1525 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1526 ATTR_DIRECTORY);
1527
1528 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1529 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001530 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001531 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 name_len++; /* trailing null */
1533 name_len *= 2;
1534 pSMB->OldFileName[name_len] = 0x04; /* pad */
1535 /* protocol requires ASCII signature byte on Unicode string */
1536 pSMB->OldFileName[name_len + 1] = 0x00;
1537 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001538 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001539 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1541 name_len2 *= 2; /* convert to bytes */
1542 } else { /* BB improve the check for buffer overruns BB */
1543 name_len = strnlen(fromName, PATH_MAX);
1544 name_len++; /* trailing null */
1545 strncpy(pSMB->OldFileName, fromName, name_len);
1546 name_len2 = strnlen(toName, PATH_MAX);
1547 name_len2++; /* trailing null */
1548 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1549 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1550 name_len2++; /* trailing null */
1551 name_len2++; /* signature byte */
1552 }
1553
1554 count = 1 /* 1st signature byte */ + name_len + name_len2;
1555 pSMB->hdr.smb_buf_length += count;
1556 pSMB->ByteCount = cpu_to_le16(count);
1557
1558 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1559 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001560 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 if (rc) {
1562 cFYI(1, ("Send error in rename = %d", rc));
1563 }
1564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 cifs_buf_release(pSMB);
1566
1567 if (rc == -EAGAIN)
1568 goto renameRetry;
1569
1570 return rc;
1571}
1572
1573int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001574 int netfid, char * target_name,
1575 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576{
1577 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1578 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1579 struct set_file_rename * rename_info;
1580 char *data_offset;
1581 char dummy_string[30];
1582 int rc = 0;
1583 int bytes_returned = 0;
1584 int len_of_str;
1585 __u16 params, param_offset, offset, count, byte_count;
1586
1587 cFYI(1, ("Rename to File by handle"));
1588 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1589 (void **) &pSMBr);
1590 if (rc)
1591 return rc;
1592
1593 params = 6;
1594 pSMB->MaxSetupCount = 0;
1595 pSMB->Reserved = 0;
1596 pSMB->Flags = 0;
1597 pSMB->Timeout = 0;
1598 pSMB->Reserved2 = 0;
1599 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1600 offset = param_offset + params;
1601
1602 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1603 rename_info = (struct set_file_rename *) data_offset;
1604 pSMB->MaxParameterCount = cpu_to_le16(2);
1605 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1606 pSMB->SetupCount = 1;
1607 pSMB->Reserved3 = 0;
1608 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1609 byte_count = 3 /* pad */ + params;
1610 pSMB->ParameterCount = cpu_to_le16(params);
1611 pSMB->TotalParameterCount = pSMB->ParameterCount;
1612 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1613 pSMB->DataOffset = cpu_to_le16(offset);
1614 /* construct random name ".cifs_tmp<inodenum><mid>" */
1615 rename_info->overwrite = cpu_to_le32(1);
1616 rename_info->root_fid = 0;
1617 /* unicode only call */
1618 if(target_name == NULL) {
1619 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001620 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001621 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001623 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001624 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 }
1626 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1627 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1628 byte_count += count;
1629 pSMB->DataCount = cpu_to_le16(count);
1630 pSMB->TotalDataCount = pSMB->DataCount;
1631 pSMB->Fid = netfid;
1632 pSMB->InformationLevel =
1633 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1634 pSMB->Reserved4 = 0;
1635 pSMB->hdr.smb_buf_length += byte_count;
1636 pSMB->ByteCount = cpu_to_le16(byte_count);
1637 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1638 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001639 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (rc) {
1641 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1642 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 cifs_buf_release(pSMB);
1645
1646 /* Note: On -EAGAIN error only caller can retry on handle based calls
1647 since file handle passed in no longer valid */
1648
1649 return rc;
1650}
1651
1652int
1653CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1654 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001655 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656{
1657 int rc = 0;
1658 COPY_REQ *pSMB = NULL;
1659 COPY_RSP *pSMBr = NULL;
1660 int bytes_returned;
1661 int name_len, name_len2;
1662 __u16 count;
1663
1664 cFYI(1, ("In CIFSSMBCopy"));
1665copyRetry:
1666 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1667 (void **) &pSMBr);
1668 if (rc)
1669 return rc;
1670
1671 pSMB->BufferFormat = 0x04;
1672 pSMB->Tid2 = target_tid;
1673
1674 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1675
1676 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001677 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001678 fromName, PATH_MAX, nls_codepage,
1679 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 name_len++; /* trailing null */
1681 name_len *= 2;
1682 pSMB->OldFileName[name_len] = 0x04; /* pad */
1683 /* protocol requires ASCII signature byte on Unicode string */
1684 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001685 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001686 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1688 name_len2 *= 2; /* convert to bytes */
1689 } else { /* BB improve the check for buffer overruns BB */
1690 name_len = strnlen(fromName, PATH_MAX);
1691 name_len++; /* trailing null */
1692 strncpy(pSMB->OldFileName, fromName, name_len);
1693 name_len2 = strnlen(toName, PATH_MAX);
1694 name_len2++; /* trailing null */
1695 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1696 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1697 name_len2++; /* trailing null */
1698 name_len2++; /* signature byte */
1699 }
1700
1701 count = 1 /* 1st signature byte */ + name_len + name_len2;
1702 pSMB->hdr.smb_buf_length += count;
1703 pSMB->ByteCount = cpu_to_le16(count);
1704
1705 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1706 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1707 if (rc) {
1708 cFYI(1, ("Send error in copy = %d with %d files copied",
1709 rc, le16_to_cpu(pSMBr->CopyCount)));
1710 }
1711 if (pSMB)
1712 cifs_buf_release(pSMB);
1713
1714 if (rc == -EAGAIN)
1715 goto copyRetry;
1716
1717 return rc;
1718}
1719
1720int
1721CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1722 const char *fromName, const char *toName,
1723 const struct nls_table *nls_codepage)
1724{
1725 TRANSACTION2_SPI_REQ *pSMB = NULL;
1726 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1727 char *data_offset;
1728 int name_len;
1729 int name_len_target;
1730 int rc = 0;
1731 int bytes_returned = 0;
1732 __u16 params, param_offset, offset, byte_count;
1733
1734 cFYI(1, ("In Symlink Unix style"));
1735createSymLinkRetry:
1736 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1737 (void **) &pSMBr);
1738 if (rc)
1739 return rc;
1740
1741 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1742 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001743 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 /* find define for this maxpathcomponent */
1745 , nls_codepage);
1746 name_len++; /* trailing null */
1747 name_len *= 2;
1748
1749 } else { /* BB improve the check for buffer overruns BB */
1750 name_len = strnlen(fromName, PATH_MAX);
1751 name_len++; /* trailing null */
1752 strncpy(pSMB->FileName, fromName, name_len);
1753 }
1754 params = 6 + name_len;
1755 pSMB->MaxSetupCount = 0;
1756 pSMB->Reserved = 0;
1757 pSMB->Flags = 0;
1758 pSMB->Timeout = 0;
1759 pSMB->Reserved2 = 0;
1760 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1761 InformationLevel) - 4;
1762 offset = param_offset + params;
1763
1764 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1765 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1766 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001767 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 /* find define for this maxpathcomponent */
1769 , nls_codepage);
1770 name_len_target++; /* trailing null */
1771 name_len_target *= 2;
1772 } else { /* BB improve the check for buffer overruns BB */
1773 name_len_target = strnlen(toName, PATH_MAX);
1774 name_len_target++; /* trailing null */
1775 strncpy(data_offset, toName, name_len_target);
1776 }
1777
1778 pSMB->MaxParameterCount = cpu_to_le16(2);
1779 /* BB find exact max on data count below from sess */
1780 pSMB->MaxDataCount = cpu_to_le16(1000);
1781 pSMB->SetupCount = 1;
1782 pSMB->Reserved3 = 0;
1783 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1784 byte_count = 3 /* pad */ + params + name_len_target;
1785 pSMB->DataCount = cpu_to_le16(name_len_target);
1786 pSMB->ParameterCount = cpu_to_le16(params);
1787 pSMB->TotalDataCount = pSMB->DataCount;
1788 pSMB->TotalParameterCount = pSMB->ParameterCount;
1789 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1790 pSMB->DataOffset = cpu_to_le16(offset);
1791 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1792 pSMB->Reserved4 = 0;
1793 pSMB->hdr.smb_buf_length += byte_count;
1794 pSMB->ByteCount = cpu_to_le16(byte_count);
1795 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1796 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001797 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 if (rc) {
1799 cFYI(1,
1800 ("Send error in SetPathInfo (create symlink) = %d",
1801 rc));
1802 }
1803
1804 if (pSMB)
1805 cifs_buf_release(pSMB);
1806
1807 if (rc == -EAGAIN)
1808 goto createSymLinkRetry;
1809
1810 return rc;
1811}
1812
1813int
1814CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1815 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001816 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817{
1818 TRANSACTION2_SPI_REQ *pSMB = NULL;
1819 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1820 char *data_offset;
1821 int name_len;
1822 int name_len_target;
1823 int rc = 0;
1824 int bytes_returned = 0;
1825 __u16 params, param_offset, offset, byte_count;
1826
1827 cFYI(1, ("In Create Hard link Unix style"));
1828createHardLinkRetry:
1829 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1830 (void **) &pSMBr);
1831 if (rc)
1832 return rc;
1833
1834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001835 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001836 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 name_len++; /* trailing null */
1838 name_len *= 2;
1839
1840 } else { /* BB improve the check for buffer overruns BB */
1841 name_len = strnlen(toName, PATH_MAX);
1842 name_len++; /* trailing null */
1843 strncpy(pSMB->FileName, toName, name_len);
1844 }
1845 params = 6 + name_len;
1846 pSMB->MaxSetupCount = 0;
1847 pSMB->Reserved = 0;
1848 pSMB->Flags = 0;
1849 pSMB->Timeout = 0;
1850 pSMB->Reserved2 = 0;
1851 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1852 InformationLevel) - 4;
1853 offset = param_offset + params;
1854
1855 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1857 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001858 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001859 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 name_len_target++; /* trailing null */
1861 name_len_target *= 2;
1862 } else { /* BB improve the check for buffer overruns BB */
1863 name_len_target = strnlen(fromName, PATH_MAX);
1864 name_len_target++; /* trailing null */
1865 strncpy(data_offset, fromName, name_len_target);
1866 }
1867
1868 pSMB->MaxParameterCount = cpu_to_le16(2);
1869 /* BB find exact max on data count below from sess*/
1870 pSMB->MaxDataCount = cpu_to_le16(1000);
1871 pSMB->SetupCount = 1;
1872 pSMB->Reserved3 = 0;
1873 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1874 byte_count = 3 /* pad */ + params + name_len_target;
1875 pSMB->ParameterCount = cpu_to_le16(params);
1876 pSMB->TotalParameterCount = pSMB->ParameterCount;
1877 pSMB->DataCount = cpu_to_le16(name_len_target);
1878 pSMB->TotalDataCount = pSMB->DataCount;
1879 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1880 pSMB->DataOffset = cpu_to_le16(offset);
1881 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1882 pSMB->Reserved4 = 0;
1883 pSMB->hdr.smb_buf_length += byte_count;
1884 pSMB->ByteCount = cpu_to_le16(byte_count);
1885 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1886 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001887 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (rc) {
1889 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1890 }
1891
1892 cifs_buf_release(pSMB);
1893 if (rc == -EAGAIN)
1894 goto createHardLinkRetry;
1895
1896 return rc;
1897}
1898
1899int
1900CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1901 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001902 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903{
1904 int rc = 0;
1905 NT_RENAME_REQ *pSMB = NULL;
1906 RENAME_RSP *pSMBr = NULL;
1907 int bytes_returned;
1908 int name_len, name_len2;
1909 __u16 count;
1910
1911 cFYI(1, ("In CIFSCreateHardLink"));
1912winCreateHardLinkRetry:
1913
1914 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1915 (void **) &pSMBr);
1916 if (rc)
1917 return rc;
1918
1919 pSMB->SearchAttributes =
1920 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1921 ATTR_DIRECTORY);
1922 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1923 pSMB->ClusterCount = 0;
1924
1925 pSMB->BufferFormat = 0x04;
1926
1927 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1928 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001929 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001930 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 name_len++; /* trailing null */
1932 name_len *= 2;
1933 pSMB->OldFileName[name_len] = 0; /* pad */
1934 pSMB->OldFileName[name_len + 1] = 0x04;
1935 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001936 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001937 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1939 name_len2 *= 2; /* convert to bytes */
1940 } else { /* BB improve the check for buffer overruns BB */
1941 name_len = strnlen(fromName, PATH_MAX);
1942 name_len++; /* trailing null */
1943 strncpy(pSMB->OldFileName, fromName, name_len);
1944 name_len2 = strnlen(toName, PATH_MAX);
1945 name_len2++; /* trailing null */
1946 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1947 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1948 name_len2++; /* trailing null */
1949 name_len2++; /* signature byte */
1950 }
1951
1952 count = 1 /* string type byte */ + name_len + name_len2;
1953 pSMB->hdr.smb_buf_length += count;
1954 pSMB->ByteCount = cpu_to_le16(count);
1955
1956 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1957 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001958 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 if (rc) {
1960 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1961 }
1962 cifs_buf_release(pSMB);
1963 if (rc == -EAGAIN)
1964 goto winCreateHardLinkRetry;
1965
1966 return rc;
1967}
1968
1969int
1970CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1971 const unsigned char *searchName,
1972 char *symlinkinfo, const int buflen,
1973 const struct nls_table *nls_codepage)
1974{
1975/* SMB_QUERY_FILE_UNIX_LINK */
1976 TRANSACTION2_QPI_REQ *pSMB = NULL;
1977 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1978 int rc = 0;
1979 int bytes_returned;
1980 int name_len;
1981 __u16 params, byte_count;
1982
1983 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1984
1985querySymLinkRetry:
1986 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1987 (void **) &pSMBr);
1988 if (rc)
1989 return rc;
1990
1991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1992 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001993 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 /* find define for this maxpathcomponent */
1995 , nls_codepage);
1996 name_len++; /* trailing null */
1997 name_len *= 2;
1998 } else { /* BB improve the check for buffer overruns BB */
1999 name_len = strnlen(searchName, PATH_MAX);
2000 name_len++; /* trailing null */
2001 strncpy(pSMB->FileName, searchName, name_len);
2002 }
2003
2004 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2005 pSMB->TotalDataCount = 0;
2006 pSMB->MaxParameterCount = cpu_to_le16(2);
2007 /* BB find exact max data count below from sess structure BB */
2008 pSMB->MaxDataCount = cpu_to_le16(4000);
2009 pSMB->MaxSetupCount = 0;
2010 pSMB->Reserved = 0;
2011 pSMB->Flags = 0;
2012 pSMB->Timeout = 0;
2013 pSMB->Reserved2 = 0;
2014 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2015 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2016 pSMB->DataCount = 0;
2017 pSMB->DataOffset = 0;
2018 pSMB->SetupCount = 1;
2019 pSMB->Reserved3 = 0;
2020 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2021 byte_count = params + 1 /* pad */ ;
2022 pSMB->TotalParameterCount = cpu_to_le16(params);
2023 pSMB->ParameterCount = pSMB->TotalParameterCount;
2024 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2025 pSMB->Reserved4 = 0;
2026 pSMB->hdr.smb_buf_length += byte_count;
2027 pSMB->ByteCount = cpu_to_le16(byte_count);
2028
2029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2031 if (rc) {
2032 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2033 } else {
2034 /* decode response */
2035
2036 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2037 if (rc || (pSMBr->ByteCount < 2))
2038 /* BB also check enough total bytes returned */
2039 rc = -EIO; /* bad smb */
2040 else {
2041 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2042 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2043
2044 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2045 name_len = UniStrnlen((wchar_t *) ((char *)
2046 &pSMBr->hdr.Protocol +data_offset),
2047 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002048 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002050 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 data_offset),
2052 name_len, nls_codepage);
2053 } else {
2054 strncpy(symlinkinfo,
2055 (char *) &pSMBr->hdr.Protocol +
2056 data_offset,
2057 min_t(const int, buflen, count));
2058 }
2059 symlinkinfo[buflen] = 0;
2060 /* just in case so calling code does not go off the end of buffer */
2061 }
2062 }
2063 cifs_buf_release(pSMB);
2064 if (rc == -EAGAIN)
2065 goto querySymLinkRetry;
2066 return rc;
2067}
2068
Steve French0a4b92c2006-01-12 15:44:21 -08002069/* Initialize NT TRANSACT SMB into small smb request buffer.
2070 This assumes that all NT TRANSACTS that we init here have
2071 total parm and data under about 400 bytes (to fit in small cifs
2072 buffer size), which is the case so far, it easily fits. NB:
2073 Setup words themselves and ByteCount
2074 MaxSetupCount (size of returned setup area) and
2075 MaxParameterCount (returned parms size) must be set by caller */
2076static int
2077smb_init_ntransact(const __u16 sub_command, const int setup_count,
2078 const int parm_len, struct cifsTconInfo *tcon,
2079 void ** ret_buf)
2080{
2081 int rc;
2082 __u32 temp_offset;
2083 struct smb_com_ntransact_req * pSMB;
2084
2085 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2086 (void **)&pSMB);
2087 if (rc)
2088 return rc;
2089 *ret_buf = (void *)pSMB;
2090 pSMB->Reserved = 0;
2091 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2092 pSMB->TotalDataCount = 0;
2093 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2094 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2095 pSMB->ParameterCount = pSMB->TotalParameterCount;
2096 pSMB->DataCount = pSMB->TotalDataCount;
2097 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2098 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2099 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2100 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2101 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2102 pSMB->SubCommand = cpu_to_le16(sub_command);
2103 return 0;
2104}
2105
2106static int
2107validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2108 int * pdatalen, int * pparmlen)
2109{
2110 char * end_of_smb;
2111 __u32 data_count, data_offset, parm_count, parm_offset;
2112 struct smb_com_ntransact_rsp * pSMBr;
2113
2114 if(buf == NULL)
2115 return -EINVAL;
2116
2117 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2118
2119 /* ByteCount was converted from little endian in SendReceive */
2120 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2121 (char *)&pSMBr->ByteCount;
2122
2123
2124 data_offset = le32_to_cpu(pSMBr->DataOffset);
2125 data_count = le32_to_cpu(pSMBr->DataCount);
2126 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2127 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2128
2129 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2130 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2131
2132 /* should we also check that parm and data areas do not overlap? */
2133 if(*ppparm > end_of_smb) {
2134 cFYI(1,("parms start after end of smb"));
2135 return -EINVAL;
2136 } else if(parm_count + *ppparm > end_of_smb) {
2137 cFYI(1,("parm end after end of smb"));
2138 return -EINVAL;
2139 } else if(*ppdata > end_of_smb) {
2140 cFYI(1,("data starts after end of smb"));
2141 return -EINVAL;
2142 } else if(data_count + *ppdata > end_of_smb) {
2143 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2144 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2145 return -EINVAL;
2146 } else if(parm_count + data_count > pSMBr->ByteCount) {
2147 cFYI(1,("parm count and data count larger than SMB"));
2148 return -EINVAL;
2149 }
2150 return 0;
2151}
2152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153int
2154CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2155 const unsigned char *searchName,
2156 char *symlinkinfo, const int buflen,__u16 fid,
2157 const struct nls_table *nls_codepage)
2158{
2159 int rc = 0;
2160 int bytes_returned;
2161 int name_len;
2162 struct smb_com_transaction_ioctl_req * pSMB;
2163 struct smb_com_transaction_ioctl_rsp * pSMBr;
2164
2165 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2166 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2167 (void **) &pSMBr);
2168 if (rc)
2169 return rc;
2170
2171 pSMB->TotalParameterCount = 0 ;
2172 pSMB->TotalDataCount = 0;
2173 pSMB->MaxParameterCount = cpu_to_le32(2);
2174 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002175 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2176 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 pSMB->MaxSetupCount = 4;
2178 pSMB->Reserved = 0;
2179 pSMB->ParameterOffset = 0;
2180 pSMB->DataCount = 0;
2181 pSMB->DataOffset = 0;
2182 pSMB->SetupCount = 4;
2183 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2184 pSMB->ParameterCount = pSMB->TotalParameterCount;
2185 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2186 pSMB->IsFsctl = 1; /* FSCTL */
2187 pSMB->IsRootFlag = 0;
2188 pSMB->Fid = fid; /* file handle always le */
2189 pSMB->ByteCount = 0;
2190
2191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2193 if (rc) {
2194 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2195 } else { /* decode response */
2196 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2197 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2198 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2199 /* BB also check enough total bytes returned */
2200 rc = -EIO; /* bad smb */
2201 else {
2202 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002203 char * end_of_smb = 2 /* sizeof byte count */ +
2204 pSMBr->ByteCount +
2205 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
2207 struct reparse_data * reparse_buf = (struct reparse_data *)
2208 ((char *)&pSMBr->hdr.Protocol + data_offset);
2209 if((char*)reparse_buf >= end_of_smb) {
2210 rc = -EIO;
2211 goto qreparse_out;
2212 }
2213 if((reparse_buf->LinkNamesBuf +
2214 reparse_buf->TargetNameOffset +
2215 reparse_buf->TargetNameLen) >
2216 end_of_smb) {
2217 cFYI(1,("reparse buf extended beyond SMB"));
2218 rc = -EIO;
2219 goto qreparse_out;
2220 }
2221
2222 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2223 name_len = UniStrnlen((wchar_t *)
2224 (reparse_buf->LinkNamesBuf +
2225 reparse_buf->TargetNameOffset),
2226 min(buflen/2, reparse_buf->TargetNameLen / 2));
2227 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002228 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 reparse_buf->TargetNameOffset),
2230 name_len, nls_codepage);
2231 } else { /* ASCII names */
2232 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2233 reparse_buf->TargetNameOffset,
2234 min_t(const int, buflen, reparse_buf->TargetNameLen));
2235 }
2236 } else {
2237 rc = -EIO;
2238 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2239 }
2240 symlinkinfo[buflen] = 0; /* just in case so the caller
2241 does not go off the end of the buffer */
2242 cFYI(1,("readlink result - %s ",symlinkinfo));
2243 }
2244 }
2245qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002246 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
2248 /* Note: On -EAGAIN error only caller can retry on handle based calls
2249 since file handle passed in no longer valid */
2250
2251 return rc;
2252}
2253
2254#ifdef CONFIG_CIFS_POSIX
2255
2256/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2257static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2258{
2259 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002260 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2261 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2262 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2264
2265 return;
2266}
2267
2268/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002269static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2270 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271{
2272 int size = 0;
2273 int i;
2274 __u16 count;
2275 struct cifs_posix_ace * pACE;
2276 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2277 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2278
2279 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2280 return -EOPNOTSUPP;
2281
2282 if(acl_type & ACL_TYPE_ACCESS) {
2283 count = le16_to_cpu(cifs_acl->access_entry_count);
2284 pACE = &cifs_acl->ace_array[0];
2285 size = sizeof(struct cifs_posix_acl);
2286 size += sizeof(struct cifs_posix_ace) * count;
2287 /* check if we would go beyond end of SMB */
2288 if(size_of_data_area < size) {
2289 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2290 return -EINVAL;
2291 }
2292 } else if(acl_type & ACL_TYPE_DEFAULT) {
2293 count = le16_to_cpu(cifs_acl->access_entry_count);
2294 size = sizeof(struct cifs_posix_acl);
2295 size += sizeof(struct cifs_posix_ace) * count;
2296/* skip past access ACEs to get to default ACEs */
2297 pACE = &cifs_acl->ace_array[count];
2298 count = le16_to_cpu(cifs_acl->default_entry_count);
2299 size += sizeof(struct cifs_posix_ace) * count;
2300 /* check if we would go beyond end of SMB */
2301 if(size_of_data_area < size)
2302 return -EINVAL;
2303 } else {
2304 /* illegal type */
2305 return -EINVAL;
2306 }
2307
2308 size = posix_acl_xattr_size(count);
2309 if((buflen == 0) || (local_acl == NULL)) {
2310 /* used to query ACL EA size */
2311 } else if(size > buflen) {
2312 return -ERANGE;
2313 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002314 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 for(i = 0;i < count ;i++) {
2316 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2317 pACE ++;
2318 }
2319 }
2320 return size;
2321}
2322
2323static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2324 const posix_acl_xattr_entry * local_ace)
2325{
2326 __u16 rc = 0; /* 0 = ACL converted ok */
2327
Steve Frenchff7feac2005-11-15 16:45:16 -08002328 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2329 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002331 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 /* Probably no need to le convert -1 on any arch but can not hurt */
2333 cifs_ace->cifs_uid = cpu_to_le64(-1);
2334 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002335 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2337 return rc;
2338}
2339
2340/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2341static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2342 const int acl_type)
2343{
2344 __u16 rc = 0;
2345 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2346 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2347 int count;
2348 int i;
2349
2350 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2351 return 0;
2352
2353 count = posix_acl_xattr_count((size_t)buflen);
2354 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002355 count, buflen, le32_to_cpu(local_acl->a_version)));
2356 if(le32_to_cpu(local_acl->a_version) != 2) {
2357 cFYI(1,("unknown POSIX ACL version %d",
2358 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 return 0;
2360 }
2361 cifs_acl->version = cpu_to_le16(1);
2362 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002363 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002365 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 else {
2367 cFYI(1,("unknown ACL type %d",acl_type));
2368 return 0;
2369 }
2370 for(i=0;i<count;i++) {
2371 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2372 &local_acl->a_entries[i]);
2373 if(rc != 0) {
2374 /* ACE not converted */
2375 break;
2376 }
2377 }
2378 if(rc == 0) {
2379 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2380 rc += sizeof(struct cifs_posix_acl);
2381 /* BB add check to make sure ACL does not overflow SMB */
2382 }
2383 return rc;
2384}
2385
2386int
2387CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2388 const unsigned char *searchName,
2389 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002390 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391{
2392/* SMB_QUERY_POSIX_ACL */
2393 TRANSACTION2_QPI_REQ *pSMB = NULL;
2394 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2395 int rc = 0;
2396 int bytes_returned;
2397 int name_len;
2398 __u16 params, byte_count;
2399
2400 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2401
2402queryAclRetry:
2403 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2404 (void **) &pSMBr);
2405 if (rc)
2406 return rc;
2407
2408 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2409 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002410 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002411 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 name_len++; /* trailing null */
2413 name_len *= 2;
2414 pSMB->FileName[name_len] = 0;
2415 pSMB->FileName[name_len+1] = 0;
2416 } else { /* BB improve the check for buffer overruns BB */
2417 name_len = strnlen(searchName, PATH_MAX);
2418 name_len++; /* trailing null */
2419 strncpy(pSMB->FileName, searchName, name_len);
2420 }
2421
2422 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2423 pSMB->TotalDataCount = 0;
2424 pSMB->MaxParameterCount = cpu_to_le16(2);
2425 /* BB find exact max data count below from sess structure BB */
2426 pSMB->MaxDataCount = cpu_to_le16(4000);
2427 pSMB->MaxSetupCount = 0;
2428 pSMB->Reserved = 0;
2429 pSMB->Flags = 0;
2430 pSMB->Timeout = 0;
2431 pSMB->Reserved2 = 0;
2432 pSMB->ParameterOffset = cpu_to_le16(
2433 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2434 pSMB->DataCount = 0;
2435 pSMB->DataOffset = 0;
2436 pSMB->SetupCount = 1;
2437 pSMB->Reserved3 = 0;
2438 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2439 byte_count = params + 1 /* pad */ ;
2440 pSMB->TotalParameterCount = cpu_to_le16(params);
2441 pSMB->ParameterCount = pSMB->TotalParameterCount;
2442 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2443 pSMB->Reserved4 = 0;
2444 pSMB->hdr.smb_buf_length += byte_count;
2445 pSMB->ByteCount = cpu_to_le16(byte_count);
2446
2447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002449 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 if (rc) {
2451 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2452 } else {
2453 /* decode response */
2454
2455 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2456 if (rc || (pSMBr->ByteCount < 2))
2457 /* BB also check enough total bytes returned */
2458 rc = -EIO; /* bad smb */
2459 else {
2460 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2461 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2462 rc = cifs_copy_posix_acl(acl_inf,
2463 (char *)&pSMBr->hdr.Protocol+data_offset,
2464 buflen,acl_type,count);
2465 }
2466 }
2467 cifs_buf_release(pSMB);
2468 if (rc == -EAGAIN)
2469 goto queryAclRetry;
2470 return rc;
2471}
2472
2473int
2474CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2475 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002476 const char *local_acl, const int buflen,
2477 const int acl_type,
2478 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479{
2480 struct smb_com_transaction2_spi_req *pSMB = NULL;
2481 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2482 char *parm_data;
2483 int name_len;
2484 int rc = 0;
2485 int bytes_returned = 0;
2486 __u16 params, byte_count, data_count, param_offset, offset;
2487
2488 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2489setAclRetry:
2490 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2491 (void **) &pSMBr);
2492 if (rc)
2493 return rc;
2494 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2495 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002496 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002497 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 name_len++; /* trailing null */
2499 name_len *= 2;
2500 } else { /* BB improve the check for buffer overruns BB */
2501 name_len = strnlen(fileName, PATH_MAX);
2502 name_len++; /* trailing null */
2503 strncpy(pSMB->FileName, fileName, name_len);
2504 }
2505 params = 6 + name_len;
2506 pSMB->MaxParameterCount = cpu_to_le16(2);
2507 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2508 pSMB->MaxSetupCount = 0;
2509 pSMB->Reserved = 0;
2510 pSMB->Flags = 0;
2511 pSMB->Timeout = 0;
2512 pSMB->Reserved2 = 0;
2513 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2514 InformationLevel) - 4;
2515 offset = param_offset + params;
2516 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2517 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2518
2519 /* convert to on the wire format for POSIX ACL */
2520 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2521
2522 if(data_count == 0) {
2523 rc = -EOPNOTSUPP;
2524 goto setACLerrorExit;
2525 }
2526 pSMB->DataOffset = cpu_to_le16(offset);
2527 pSMB->SetupCount = 1;
2528 pSMB->Reserved3 = 0;
2529 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2530 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2531 byte_count = 3 /* pad */ + params + data_count;
2532 pSMB->DataCount = cpu_to_le16(data_count);
2533 pSMB->TotalDataCount = pSMB->DataCount;
2534 pSMB->ParameterCount = cpu_to_le16(params);
2535 pSMB->TotalParameterCount = pSMB->ParameterCount;
2536 pSMB->Reserved4 = 0;
2537 pSMB->hdr.smb_buf_length += byte_count;
2538 pSMB->ByteCount = cpu_to_le16(byte_count);
2539 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2540 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2541 if (rc) {
2542 cFYI(1, ("Set POSIX ACL returned %d", rc));
2543 }
2544
2545setACLerrorExit:
2546 cifs_buf_release(pSMB);
2547 if (rc == -EAGAIN)
2548 goto setAclRetry;
2549 return rc;
2550}
2551
Steve Frenchf654bac2005-04-28 22:41:04 -07002552/* BB fix tabs in this function FIXME BB */
2553int
2554CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2555 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2556{
2557 int rc = 0;
2558 struct smb_t2_qfi_req *pSMB = NULL;
2559 struct smb_t2_qfi_rsp *pSMBr = NULL;
2560 int bytes_returned;
2561 __u16 params, byte_count;
2562
2563 cFYI(1,("In GetExtAttr"));
2564 if(tcon == NULL)
2565 return -ENODEV;
2566
2567GetExtAttrRetry:
2568 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2569 (void **) &pSMBr);
2570 if (rc)
2571 return rc;
2572
Steve Frenchc67593a2005-04-28 22:41:04 -07002573 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002574 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002575 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002576 /* BB find exact max data count below from sess structure BB */
2577 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2578 pSMB->t2.MaxSetupCount = 0;
2579 pSMB->t2.Reserved = 0;
2580 pSMB->t2.Flags = 0;
2581 pSMB->t2.Timeout = 0;
2582 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002583 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2584 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002585 pSMB->t2.DataCount = 0;
2586 pSMB->t2.DataOffset = 0;
2587 pSMB->t2.SetupCount = 1;
2588 pSMB->t2.Reserved3 = 0;
2589 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002590 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002591 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2592 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2593 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002594 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002595 pSMB->Fid = netfid;
2596 pSMB->hdr.smb_buf_length += byte_count;
2597 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2598
2599 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2600 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2601 if (rc) {
2602 cFYI(1, ("error %d in GetExtAttr", rc));
2603 } else {
2604 /* decode response */
2605 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2606 if (rc || (pSMBr->ByteCount < 2))
2607 /* BB also check enough total bytes returned */
2608 /* If rc should we check for EOPNOSUPP and
2609 disable the srvino flag? or in caller? */
2610 rc = -EIO; /* bad smb */
2611 else {
2612 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2613 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2614 struct file_chattr_info * pfinfo;
2615 /* BB Do we need a cast or hash here ? */
2616 if(count != 16) {
2617 cFYI(1, ("Illegal size ret in GetExtAttr"));
2618 rc = -EIO;
2619 goto GetExtAttrOut;
2620 }
2621 pfinfo = (struct file_chattr_info *)
2622 (data_offset + (char *) &pSMBr->hdr.Protocol);
2623 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2624 *pMask = le64_to_cpu(pfinfo->mask);
2625 }
2626 }
2627GetExtAttrOut:
2628 cifs_buf_release(pSMB);
2629 if (rc == -EAGAIN)
2630 goto GetExtAttrRetry;
2631 return rc;
2632}
2633
2634
2635#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636
Steve Frencheeac8042006-01-13 21:34:58 -08002637
2638/* security id for everyone */
2639const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2640/* group users */
2641const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2642
Steve French0a4b92c2006-01-12 15:44:21 -08002643/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002644static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002645{
Steve French0a4b92c2006-01-12 15:44:21 -08002646 return 0;
2647}
2648
2649/* Get Security Descriptor (by handle) from remote server for a file or dir */
2650int
2651CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2652 /* BB fix up return info */ char *acl_inf, const int buflen,
2653 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2654{
2655 int rc = 0;
2656 int buf_type = 0;
2657 QUERY_SEC_DESC_REQ * pSMB;
2658 struct kvec iov[1];
2659
2660 cFYI(1, ("GetCifsACL"));
2661
2662 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2663 8 /* parm len */, tcon, (void **) &pSMB);
2664 if (rc)
2665 return rc;
2666
2667 pSMB->MaxParameterCount = cpu_to_le32(4);
2668 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2669 pSMB->MaxSetupCount = 0;
2670 pSMB->Fid = fid; /* file handle always le */
2671 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2672 CIFS_ACL_DACL);
2673 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2674 pSMB->hdr.smb_buf_length += 11;
2675 iov[0].iov_base = (char *)pSMB;
2676 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2677
2678 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2679 cifs_stats_inc(&tcon->num_acl_get);
2680 if (rc) {
2681 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2682 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002683 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002684 __le32 * parm;
2685 int parm_len;
2686 int data_len;
2687 int acl_len;
2688 struct smb_com_ntransact_rsp * pSMBr;
2689
2690/* validate_nttransact */
2691 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2692 (char **)&psec_desc,
2693 &parm_len, &data_len);
2694
2695 if(rc)
2696 goto qsec_out;
2697 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2698
2699 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2700
2701 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2702 rc = -EIO; /* bad smb */
2703 goto qsec_out;
2704 }
2705
2706/* BB check that data area is minimum length and as big as acl_len */
2707
2708 acl_len = le32_to_cpu(*(__le32 *)parm);
2709 /* BB check if(acl_len > bufsize) */
2710
2711 parse_sec_desc(psec_desc, acl_len);
2712 }
2713qsec_out:
2714 if(buf_type == CIFS_SMALL_BUFFER)
2715 cifs_small_buf_release(iov[0].iov_base);
2716 else if(buf_type == CIFS_LARGE_BUFFER)
2717 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002718/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002719 return rc;
2720}
2721
2722
Steve French6b8edfe2005-08-23 20:26:03 -07002723/* Legacy Query Path Information call for lookup to old servers such
2724 as Win9x/WinME */
2725int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2726 const unsigned char *searchName,
2727 FILE_ALL_INFO * pFinfo,
2728 const struct nls_table *nls_codepage, int remap)
2729{
2730 QUERY_INFORMATION_REQ * pSMB;
2731 QUERY_INFORMATION_RSP * pSMBr;
2732 int rc = 0;
2733 int bytes_returned;
2734 int name_len;
2735
2736 cFYI(1, ("In SMBQPath path %s", searchName));
2737QInfRetry:
2738 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2739 (void **) &pSMBr);
2740 if (rc)
2741 return rc;
2742
2743 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2744 name_len =
2745 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2746 PATH_MAX, nls_codepage, remap);
2747 name_len++; /* trailing null */
2748 name_len *= 2;
2749 } else {
2750 name_len = strnlen(searchName, PATH_MAX);
2751 name_len++; /* trailing null */
2752 strncpy(pSMB->FileName, searchName, name_len);
2753 }
2754 pSMB->BufferFormat = 0x04;
2755 name_len++; /* account for buffer type byte */
2756 pSMB->hdr.smb_buf_length += (__u16) name_len;
2757 pSMB->ByteCount = cpu_to_le16(name_len);
2758
2759 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2761 if (rc) {
2762 cFYI(1, ("Send error in QueryInfo = %d", rc));
2763 } else if (pFinfo) { /* decode response */
2764 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002765 pFinfo->AllocationSize =
2766 cpu_to_le64(le32_to_cpu(pSMBr->size));
2767 pFinfo->EndOfFile = pFinfo->AllocationSize;
2768 pFinfo->Attributes =
2769 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002770 } else
2771 rc = -EIO; /* bad buffer passed in */
2772
2773 cifs_buf_release(pSMB);
2774
2775 if (rc == -EAGAIN)
2776 goto QInfRetry;
2777
2778 return rc;
2779}
2780
2781
2782
2783
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784int
2785CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2786 const unsigned char *searchName,
2787 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002788 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789{
2790/* level 263 SMB_QUERY_FILE_ALL_INFO */
2791 TRANSACTION2_QPI_REQ *pSMB = NULL;
2792 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2793 int rc = 0;
2794 int bytes_returned;
2795 int name_len;
2796 __u16 params, byte_count;
2797
2798/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2799QPathInfoRetry:
2800 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2801 (void **) &pSMBr);
2802 if (rc)
2803 return rc;
2804
2805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2806 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002807 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002808 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 name_len++; /* trailing null */
2810 name_len *= 2;
2811 } else { /* BB improve the check for buffer overruns BB */
2812 name_len = strnlen(searchName, PATH_MAX);
2813 name_len++; /* trailing null */
2814 strncpy(pSMB->FileName, searchName, name_len);
2815 }
2816
2817 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2818 pSMB->TotalDataCount = 0;
2819 pSMB->MaxParameterCount = cpu_to_le16(2);
2820 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2821 pSMB->MaxSetupCount = 0;
2822 pSMB->Reserved = 0;
2823 pSMB->Flags = 0;
2824 pSMB->Timeout = 0;
2825 pSMB->Reserved2 = 0;
2826 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2827 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2828 pSMB->DataCount = 0;
2829 pSMB->DataOffset = 0;
2830 pSMB->SetupCount = 1;
2831 pSMB->Reserved3 = 0;
2832 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2833 byte_count = params + 1 /* pad */ ;
2834 pSMB->TotalParameterCount = cpu_to_le16(params);
2835 pSMB->ParameterCount = pSMB->TotalParameterCount;
2836 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2837 pSMB->Reserved4 = 0;
2838 pSMB->hdr.smb_buf_length += byte_count;
2839 pSMB->ByteCount = cpu_to_le16(byte_count);
2840
2841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2842 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2843 if (rc) {
2844 cFYI(1, ("Send error in QPathInfo = %d", rc));
2845 } else { /* decode response */
2846 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2847
2848 if (rc || (pSMBr->ByteCount < 40))
2849 rc = -EIO; /* bad smb */
2850 else if (pFindData){
2851 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2852 memcpy((char *) pFindData,
2853 (char *) &pSMBr->hdr.Protocol +
2854 data_offset, sizeof (FILE_ALL_INFO));
2855 } else
2856 rc = -ENOMEM;
2857 }
2858 cifs_buf_release(pSMB);
2859 if (rc == -EAGAIN)
2860 goto QPathInfoRetry;
2861
2862 return rc;
2863}
2864
2865int
2866CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2867 const unsigned char *searchName,
2868 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002869 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870{
2871/* SMB_QUERY_FILE_UNIX_BASIC */
2872 TRANSACTION2_QPI_REQ *pSMB = NULL;
2873 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2874 int rc = 0;
2875 int bytes_returned = 0;
2876 int name_len;
2877 __u16 params, byte_count;
2878
2879 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2880UnixQPathInfoRetry:
2881 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2882 (void **) &pSMBr);
2883 if (rc)
2884 return rc;
2885
2886 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2887 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002888 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002889 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 name_len++; /* trailing null */
2891 name_len *= 2;
2892 } else { /* BB improve the check for buffer overruns BB */
2893 name_len = strnlen(searchName, PATH_MAX);
2894 name_len++; /* trailing null */
2895 strncpy(pSMB->FileName, searchName, name_len);
2896 }
2897
2898 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2899 pSMB->TotalDataCount = 0;
2900 pSMB->MaxParameterCount = cpu_to_le16(2);
2901 /* BB find exact max SMB PDU from sess structure BB */
2902 pSMB->MaxDataCount = cpu_to_le16(4000);
2903 pSMB->MaxSetupCount = 0;
2904 pSMB->Reserved = 0;
2905 pSMB->Flags = 0;
2906 pSMB->Timeout = 0;
2907 pSMB->Reserved2 = 0;
2908 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2909 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2910 pSMB->DataCount = 0;
2911 pSMB->DataOffset = 0;
2912 pSMB->SetupCount = 1;
2913 pSMB->Reserved3 = 0;
2914 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2915 byte_count = params + 1 /* pad */ ;
2916 pSMB->TotalParameterCount = cpu_to_le16(params);
2917 pSMB->ParameterCount = pSMB->TotalParameterCount;
2918 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2919 pSMB->Reserved4 = 0;
2920 pSMB->hdr.smb_buf_length += byte_count;
2921 pSMB->ByteCount = cpu_to_le16(byte_count);
2922
2923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2925 if (rc) {
2926 cFYI(1, ("Send error in QPathInfo = %d", rc));
2927 } else { /* decode response */
2928 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2929
2930 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2931 rc = -EIO; /* bad smb */
2932 } else {
2933 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2934 memcpy((char *) pFindData,
2935 (char *) &pSMBr->hdr.Protocol +
2936 data_offset,
2937 sizeof (FILE_UNIX_BASIC_INFO));
2938 }
2939 }
2940 cifs_buf_release(pSMB);
2941 if (rc == -EAGAIN)
2942 goto UnixQPathInfoRetry;
2943
2944 return rc;
2945}
2946
2947#if 0 /* function unused at present */
2948int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2949 const char *searchName, FILE_ALL_INFO * findData,
2950 const struct nls_table *nls_codepage)
2951{
2952/* level 257 SMB_ */
2953 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2954 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2955 int rc = 0;
2956 int bytes_returned;
2957 int name_len;
2958 __u16 params, byte_count;
2959
2960 cFYI(1, ("In FindUnique"));
2961findUniqueRetry:
2962 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2963 (void **) &pSMBr);
2964 if (rc)
2965 return rc;
2966
2967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2968 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002969 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 /* find define for this maxpathcomponent */
2971 , nls_codepage);
2972 name_len++; /* trailing null */
2973 name_len *= 2;
2974 } else { /* BB improve the check for buffer overruns BB */
2975 name_len = strnlen(searchName, PATH_MAX);
2976 name_len++; /* trailing null */
2977 strncpy(pSMB->FileName, searchName, name_len);
2978 }
2979
2980 params = 12 + name_len /* includes null */ ;
2981 pSMB->TotalDataCount = 0; /* no EAs */
2982 pSMB->MaxParameterCount = cpu_to_le16(2);
2983 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2984 pSMB->MaxSetupCount = 0;
2985 pSMB->Reserved = 0;
2986 pSMB->Flags = 0;
2987 pSMB->Timeout = 0;
2988 pSMB->Reserved2 = 0;
2989 pSMB->ParameterOffset = cpu_to_le16(
2990 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2991 pSMB->DataCount = 0;
2992 pSMB->DataOffset = 0;
2993 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2994 pSMB->Reserved3 = 0;
2995 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2996 byte_count = params + 1 /* pad */ ;
2997 pSMB->TotalParameterCount = cpu_to_le16(params);
2998 pSMB->ParameterCount = pSMB->TotalParameterCount;
2999 pSMB->SearchAttributes =
3000 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3001 ATTR_DIRECTORY);
3002 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3003 pSMB->SearchFlags = cpu_to_le16(1);
3004 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3005 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3006 pSMB->hdr.smb_buf_length += byte_count;
3007 pSMB->ByteCount = cpu_to_le16(byte_count);
3008
3009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3011
3012 if (rc) {
3013 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3014 } else { /* decode response */
Steve Frencha45443472005-08-24 13:59:35 -07003015 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 /* BB fill in */
3017 }
3018
3019 cifs_buf_release(pSMB);
3020 if (rc == -EAGAIN)
3021 goto findUniqueRetry;
3022
3023 return rc;
3024}
3025#endif /* end unused (temporarily) function */
3026
3027/* xid, tcon, searchName and codepage are input parms, rest are returned */
3028int
3029CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3030 const char *searchName,
3031 const struct nls_table *nls_codepage,
3032 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003033 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034{
3035/* level 257 SMB_ */
3036 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3037 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3038 T2_FFIRST_RSP_PARMS * parms;
3039 int rc = 0;
3040 int bytes_returned = 0;
3041 int name_len;
3042 __u16 params, byte_count;
3043
Steve French737b7582005-04-28 22:41:06 -07003044 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
3046findFirstRetry:
3047 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3048 (void **) &pSMBr);
3049 if (rc)
3050 return rc;
3051
3052 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3053 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003054 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003055 PATH_MAX, nls_codepage, remap);
3056 /* We can not add the asterik earlier in case
3057 it got remapped to 0xF03A as if it were part of the
3058 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003060 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003061 pSMB->FileName[name_len+1] = 0;
3062 pSMB->FileName[name_len+2] = '*';
3063 pSMB->FileName[name_len+3] = 0;
3064 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3066 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003067 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 } else { /* BB add check for overrun of SMB buf BB */
3069 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070/* BB fix here and in unicode clause above ie
3071 if(name_len > buffersize-header)
3072 free buffer exit; BB */
3073 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003074 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003075 pSMB->FileName[name_len+1] = '*';
3076 pSMB->FileName[name_len+2] = 0;
3077 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 }
3079
3080 params = 12 + name_len /* includes null */ ;
3081 pSMB->TotalDataCount = 0; /* no EAs */
3082 pSMB->MaxParameterCount = cpu_to_le16(10);
3083 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3084 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3085 pSMB->MaxSetupCount = 0;
3086 pSMB->Reserved = 0;
3087 pSMB->Flags = 0;
3088 pSMB->Timeout = 0;
3089 pSMB->Reserved2 = 0;
3090 byte_count = params + 1 /* pad */ ;
3091 pSMB->TotalParameterCount = cpu_to_le16(params);
3092 pSMB->ParameterCount = pSMB->TotalParameterCount;
3093 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003094 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3095 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 pSMB->DataCount = 0;
3097 pSMB->DataOffset = 0;
3098 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3099 pSMB->Reserved3 = 0;
3100 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3101 pSMB->SearchAttributes =
3102 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3103 ATTR_DIRECTORY);
3104 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3105 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3106 CIFS_SEARCH_RETURN_RESUME);
3107 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3108
3109 /* BB what should we set StorageType to? Does it matter? BB */
3110 pSMB->SearchStorageType = 0;
3111 pSMB->hdr.smb_buf_length += byte_count;
3112 pSMB->ByteCount = cpu_to_le16(byte_count);
3113
3114 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3115 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003116 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
Steve French88274812006-03-09 22:21:45 +00003118 if (rc) {/* BB add logic to retry regular search if Unix search
3119 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 /* BB Add code to handle unsupported level rc */
3121 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003122
Steve French88274812006-03-09 22:21:45 +00003123 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124
3125 /* BB eventually could optimize out free and realloc of buf */
3126 /* for this case */
3127 if (rc == -EAGAIN)
3128 goto findFirstRetry;
3129 } else { /* decode response */
3130 /* BB remember to free buffer if error BB */
3131 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3132 if(rc == 0) {
3133 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3134 psrch_inf->unicode = TRUE;
3135 else
3136 psrch_inf->unicode = FALSE;
3137
3138 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003139 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 psrch_inf->srch_entries_start =
3141 (char *) &pSMBr->hdr.Protocol +
3142 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3144 le16_to_cpu(pSMBr->t2.ParameterOffset));
3145
3146 if(parms->EndofSearch)
3147 psrch_inf->endOfSearch = TRUE;
3148 else
3149 psrch_inf->endOfSearch = FALSE;
3150
3151 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003152 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 *pnetfid = parms->SearchHandle;
3155 } else {
3156 cifs_buf_release(pSMB);
3157 }
3158 }
3159
3160 return rc;
3161}
3162
3163int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3164 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3165{
3166 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3167 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3168 T2_FNEXT_RSP_PARMS * parms;
3169 char *response_data;
3170 int rc = 0;
3171 int bytes_returned, name_len;
3172 __u16 params, byte_count;
3173
3174 cFYI(1, ("In FindNext"));
3175
3176 if(psrch_inf->endOfSearch == TRUE)
3177 return -ENOENT;
3178
3179 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3180 (void **) &pSMBr);
3181 if (rc)
3182 return rc;
3183
3184 params = 14; /* includes 2 bytes of null string, converted to LE below */
3185 byte_count = 0;
3186 pSMB->TotalDataCount = 0; /* no EAs */
3187 pSMB->MaxParameterCount = cpu_to_le16(8);
3188 pSMB->MaxDataCount =
3189 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3190 pSMB->MaxSetupCount = 0;
3191 pSMB->Reserved = 0;
3192 pSMB->Flags = 0;
3193 pSMB->Timeout = 0;
3194 pSMB->Reserved2 = 0;
3195 pSMB->ParameterOffset = cpu_to_le16(
3196 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3197 pSMB->DataCount = 0;
3198 pSMB->DataOffset = 0;
3199 pSMB->SetupCount = 1;
3200 pSMB->Reserved3 = 0;
3201 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3202 pSMB->SearchHandle = searchHandle; /* always kept as le */
3203 pSMB->SearchCount =
3204 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3205 /* test for Unix extensions */
3206/* if (tcon->ses->capabilities & CAP_UNIX) {
3207 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3208 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3209 } else {
3210 pSMB->InformationLevel =
3211 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3212 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3213 } */
3214 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3215 pSMB->ResumeKey = psrch_inf->resume_key;
3216 pSMB->SearchFlags =
3217 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3218
3219 name_len = psrch_inf->resume_name_len;
3220 params += name_len;
3221 if(name_len < PATH_MAX) {
3222 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3223 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003224 /* 14 byte parm len above enough for 2 byte null terminator */
3225 pSMB->ResumeFileName[name_len] = 0;
3226 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 } else {
3228 rc = -EINVAL;
3229 goto FNext2_err_exit;
3230 }
3231 byte_count = params + 1 /* pad */ ;
3232 pSMB->TotalParameterCount = cpu_to_le16(params);
3233 pSMB->ParameterCount = pSMB->TotalParameterCount;
3234 pSMB->hdr.smb_buf_length += byte_count;
3235 pSMB->ByteCount = cpu_to_le16(byte_count);
3236
3237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3238 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003239 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 if (rc) {
3241 if (rc == -EBADF) {
3242 psrch_inf->endOfSearch = TRUE;
3243 rc = 0; /* search probably was closed at end of search above */
3244 } else
3245 cFYI(1, ("FindNext returned = %d", rc));
3246 } else { /* decode response */
3247 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3248
3249 if(rc == 0) {
3250 /* BB fixme add lock for file (srch_info) struct here */
3251 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3252 psrch_inf->unicode = TRUE;
3253 else
3254 psrch_inf->unicode = FALSE;
3255 response_data = (char *) &pSMBr->hdr.Protocol +
3256 le16_to_cpu(pSMBr->t2.ParameterOffset);
3257 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3258 response_data = (char *)&pSMBr->hdr.Protocol +
3259 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003260 if(psrch_inf->smallBuf)
3261 cifs_small_buf_release(
3262 psrch_inf->ntwrk_buf_start);
3263 else
3264 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 psrch_inf->srch_entries_start = response_data;
3266 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003267 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 if(parms->EndofSearch)
3269 psrch_inf->endOfSearch = TRUE;
3270 else
3271 psrch_inf->endOfSearch = FALSE;
3272
3273 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3274 psrch_inf->index_of_last_entry +=
3275 psrch_inf->entries_in_buffer;
3276/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3277
3278 /* BB fixme add unlock here */
3279 }
3280
3281 }
3282
3283 /* BB On error, should we leave previous search buf (and count and
3284 last entry fields) intact or free the previous one? */
3285
3286 /* Note: On -EAGAIN error only caller can retry on handle based calls
3287 since file handle passed in no longer valid */
3288FNext2_err_exit:
3289 if (rc != 0)
3290 cifs_buf_release(pSMB);
3291
3292 return rc;
3293}
3294
3295int
3296CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3297{
3298 int rc = 0;
3299 FINDCLOSE_REQ *pSMB = NULL;
3300 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3301 int bytes_returned;
3302
3303 cFYI(1, ("In CIFSSMBFindClose"));
3304 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3305
3306 /* no sense returning error if session restarted
3307 as file handle has been closed */
3308 if(rc == -EAGAIN)
3309 return 0;
3310 if (rc)
3311 return rc;
3312
3313 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3314 pSMB->FileID = searchHandle;
3315 pSMB->ByteCount = 0;
3316 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3317 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3318 if (rc) {
3319 cERROR(1, ("Send error in FindClose = %d", rc));
3320 }
Steve Frencha45443472005-08-24 13:59:35 -07003321 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 cifs_small_buf_release(pSMB);
3323
3324 /* Since session is dead, search handle closed on server already */
3325 if (rc == -EAGAIN)
3326 rc = 0;
3327
3328 return rc;
3329}
3330
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331int
3332CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3333 const unsigned char *searchName,
3334 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003335 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336{
3337 int rc = 0;
3338 TRANSACTION2_QPI_REQ *pSMB = NULL;
3339 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3340 int name_len, bytes_returned;
3341 __u16 params, byte_count;
3342
3343 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3344 if(tcon == NULL)
3345 return -ENODEV;
3346
3347GetInodeNumberRetry:
3348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3349 (void **) &pSMBr);
3350 if (rc)
3351 return rc;
3352
3353
3354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3355 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003356 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003357 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 name_len++; /* trailing null */
3359 name_len *= 2;
3360 } else { /* BB improve the check for buffer overruns BB */
3361 name_len = strnlen(searchName, PATH_MAX);
3362 name_len++; /* trailing null */
3363 strncpy(pSMB->FileName, searchName, name_len);
3364 }
3365
3366 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3367 pSMB->TotalDataCount = 0;
3368 pSMB->MaxParameterCount = cpu_to_le16(2);
3369 /* BB find exact max data count below from sess structure BB */
3370 pSMB->MaxDataCount = cpu_to_le16(4000);
3371 pSMB->MaxSetupCount = 0;
3372 pSMB->Reserved = 0;
3373 pSMB->Flags = 0;
3374 pSMB->Timeout = 0;
3375 pSMB->Reserved2 = 0;
3376 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3377 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3378 pSMB->DataCount = 0;
3379 pSMB->DataOffset = 0;
3380 pSMB->SetupCount = 1;
3381 pSMB->Reserved3 = 0;
3382 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3383 byte_count = params + 1 /* pad */ ;
3384 pSMB->TotalParameterCount = cpu_to_le16(params);
3385 pSMB->ParameterCount = pSMB->TotalParameterCount;
3386 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3387 pSMB->Reserved4 = 0;
3388 pSMB->hdr.smb_buf_length += byte_count;
3389 pSMB->ByteCount = cpu_to_le16(byte_count);
3390
3391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3392 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3393 if (rc) {
3394 cFYI(1, ("error %d in QueryInternalInfo", rc));
3395 } else {
3396 /* decode response */
3397 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3398 if (rc || (pSMBr->ByteCount < 2))
3399 /* BB also check enough total bytes returned */
3400 /* If rc should we check for EOPNOSUPP and
3401 disable the srvino flag? or in caller? */
3402 rc = -EIO; /* bad smb */
3403 else {
3404 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3405 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3406 struct file_internal_info * pfinfo;
3407 /* BB Do we need a cast or hash here ? */
3408 if(count < 8) {
3409 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3410 rc = -EIO;
3411 goto GetInodeNumOut;
3412 }
3413 pfinfo = (struct file_internal_info *)
3414 (data_offset + (char *) &pSMBr->hdr.Protocol);
3415 *inode_number = pfinfo->UniqueId;
3416 }
3417 }
3418GetInodeNumOut:
3419 cifs_buf_release(pSMB);
3420 if (rc == -EAGAIN)
3421 goto GetInodeNumberRetry;
3422 return rc;
3423}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424
3425int
3426CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3427 const unsigned char *searchName,
3428 unsigned char **targetUNCs,
3429 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003430 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431{
3432/* TRANS2_GET_DFS_REFERRAL */
3433 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3434 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3435 struct dfs_referral_level_3 * referrals = NULL;
3436 int rc = 0;
3437 int bytes_returned;
3438 int name_len;
3439 unsigned int i;
3440 char * temp;
3441 __u16 params, byte_count;
3442 *number_of_UNC_in_array = 0;
3443 *targetUNCs = NULL;
3444
3445 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3446 if (ses == NULL)
3447 return -ENODEV;
3448getDFSRetry:
3449 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3450 (void **) &pSMBr);
3451 if (rc)
3452 return rc;
Steve French1982c342005-08-17 12:38:22 -07003453
3454 /* server pointer checked in called function,
3455 but should never be null here anyway */
3456 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 pSMB->hdr.Tid = ses->ipc_tid;
3458 pSMB->hdr.Uid = ses->Suid;
3459 if (ses->capabilities & CAP_STATUS32) {
3460 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3461 }
3462 if (ses->capabilities & CAP_DFS) {
3463 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3464 }
3465
3466 if (ses->capabilities & CAP_UNICODE) {
3467 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3468 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003469 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003470 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 name_len++; /* trailing null */
3472 name_len *= 2;
3473 } else { /* BB improve the check for buffer overruns BB */
3474 name_len = strnlen(searchName, PATH_MAX);
3475 name_len++; /* trailing null */
3476 strncpy(pSMB->RequestFileName, searchName, name_len);
3477 }
3478
3479 params = 2 /* level */ + name_len /*includes null */ ;
3480 pSMB->TotalDataCount = 0;
3481 pSMB->DataCount = 0;
3482 pSMB->DataOffset = 0;
3483 pSMB->MaxParameterCount = 0;
3484 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3485 pSMB->MaxSetupCount = 0;
3486 pSMB->Reserved = 0;
3487 pSMB->Flags = 0;
3488 pSMB->Timeout = 0;
3489 pSMB->Reserved2 = 0;
3490 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3491 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3492 pSMB->SetupCount = 1;
3493 pSMB->Reserved3 = 0;
3494 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3495 byte_count = params + 3 /* pad */ ;
3496 pSMB->ParameterCount = cpu_to_le16(params);
3497 pSMB->TotalParameterCount = pSMB->ParameterCount;
3498 pSMB->MaxReferralLevel = cpu_to_le16(3);
3499 pSMB->hdr.smb_buf_length += byte_count;
3500 pSMB->ByteCount = cpu_to_le16(byte_count);
3501
3502 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3504 if (rc) {
3505 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3506 } else { /* decode response */
3507/* BB Add logic to parse referrals here */
3508 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3509
3510 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3511 rc = -EIO; /* bad smb */
3512 else {
3513 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3514 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3515
3516 cFYI(1,
3517 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3518 pSMBr->ByteCount, data_offset));
3519 referrals =
3520 (struct dfs_referral_level_3 *)
3521 (8 /* sizeof start of data block */ +
3522 data_offset +
3523 (char *) &pSMBr->hdr.Protocol);
3524 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",
3525 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)));
3526 /* BB This field is actually two bytes in from start of
3527 data block so we could do safety check that DataBlock
3528 begins at address of pSMBr->NumberOfReferrals */
3529 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3530
3531 /* BB Fix below so can return more than one referral */
3532 if(*number_of_UNC_in_array > 1)
3533 *number_of_UNC_in_array = 1;
3534
3535 /* get the length of the strings describing refs */
3536 name_len = 0;
3537 for(i=0;i<*number_of_UNC_in_array;i++) {
3538 /* make sure that DfsPathOffset not past end */
3539 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3540 if (offset > data_count) {
3541 /* if invalid referral, stop here and do
3542 not try to copy any more */
3543 *number_of_UNC_in_array = i;
3544 break;
3545 }
3546 temp = ((char *)referrals) + offset;
3547
3548 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3549 name_len += UniStrnlen((wchar_t *)temp,data_count);
3550 } else {
3551 name_len += strnlen(temp,data_count);
3552 }
3553 referrals++;
3554 /* BB add check that referral pointer does not fall off end PDU */
3555
3556 }
3557 /* BB add check for name_len bigger than bcc */
3558 *targetUNCs =
3559 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3560 if(*targetUNCs == NULL) {
3561 rc = -ENOMEM;
3562 goto GetDFSRefExit;
3563 }
3564 /* copy the ref strings */
3565 referrals =
3566 (struct dfs_referral_level_3 *)
3567 (8 /* sizeof data hdr */ +
3568 data_offset +
3569 (char *) &pSMBr->hdr.Protocol);
3570
3571 for(i=0;i<*number_of_UNC_in_array;i++) {
3572 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3573 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3574 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003575 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 } else {
3577 strncpy(*targetUNCs,temp,name_len);
3578 }
3579 /* BB update target_uncs pointers */
3580 referrals++;
3581 }
3582 temp = *targetUNCs;
3583 temp[name_len] = 0;
3584 }
3585
3586 }
3587GetDFSRefExit:
3588 if (pSMB)
3589 cifs_buf_release(pSMB);
3590
3591 if (rc == -EAGAIN)
3592 goto getDFSRetry;
3593
3594 return rc;
3595}
3596
Steve French20962432005-09-21 22:05:57 -07003597/* Query File System Info such as free space to old servers such as Win 9x */
3598int
3599SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3600{
3601/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3602 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3603 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3604 FILE_SYSTEM_ALLOC_INFO *response_data;
3605 int rc = 0;
3606 int bytes_returned = 0;
3607 __u16 params, byte_count;
3608
3609 cFYI(1, ("OldQFSInfo"));
3610oldQFSInfoRetry:
3611 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3612 (void **) &pSMBr);
3613 if (rc)
3614 return rc;
3615 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3616 (void **) &pSMBr);
3617 if (rc)
3618 return rc;
3619
3620 params = 2; /* level */
3621 pSMB->TotalDataCount = 0;
3622 pSMB->MaxParameterCount = cpu_to_le16(2);
3623 pSMB->MaxDataCount = cpu_to_le16(1000);
3624 pSMB->MaxSetupCount = 0;
3625 pSMB->Reserved = 0;
3626 pSMB->Flags = 0;
3627 pSMB->Timeout = 0;
3628 pSMB->Reserved2 = 0;
3629 byte_count = params + 1 /* pad */ ;
3630 pSMB->TotalParameterCount = cpu_to_le16(params);
3631 pSMB->ParameterCount = pSMB->TotalParameterCount;
3632 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3633 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3634 pSMB->DataCount = 0;
3635 pSMB->DataOffset = 0;
3636 pSMB->SetupCount = 1;
3637 pSMB->Reserved3 = 0;
3638 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3639 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3640 pSMB->hdr.smb_buf_length += byte_count;
3641 pSMB->ByteCount = cpu_to_le16(byte_count);
3642
3643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3645 if (rc) {
3646 cFYI(1, ("Send error in QFSInfo = %d", rc));
3647 } else { /* decode response */
3648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3649
3650 if (rc || (pSMBr->ByteCount < 18))
3651 rc = -EIO; /* bad smb */
3652 else {
3653 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3654 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3655 pSMBr->ByteCount, data_offset));
3656
3657 response_data =
3658 (FILE_SYSTEM_ALLOC_INFO *)
3659 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3660 FSData->f_bsize =
3661 le16_to_cpu(response_data->BytesPerSector) *
3662 le32_to_cpu(response_data->
3663 SectorsPerAllocationUnit);
3664 FSData->f_blocks =
3665 le32_to_cpu(response_data->TotalAllocationUnits);
3666 FSData->f_bfree = FSData->f_bavail =
3667 le32_to_cpu(response_data->FreeAllocationUnits);
3668 cFYI(1,
3669 ("Blocks: %lld Free: %lld Block size %ld",
3670 (unsigned long long)FSData->f_blocks,
3671 (unsigned long long)FSData->f_bfree,
3672 FSData->f_bsize));
3673 }
3674 }
3675 cifs_buf_release(pSMB);
3676
3677 if (rc == -EAGAIN)
3678 goto oldQFSInfoRetry;
3679
3680 return rc;
3681}
3682
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683int
Steve French737b7582005-04-28 22:41:06 -07003684CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685{
3686/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3687 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3688 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3689 FILE_SYSTEM_INFO *response_data;
3690 int rc = 0;
3691 int bytes_returned = 0;
3692 __u16 params, byte_count;
3693
3694 cFYI(1, ("In QFSInfo"));
3695QFSInfoRetry:
3696 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3697 (void **) &pSMBr);
3698 if (rc)
3699 return rc;
3700
3701 params = 2; /* level */
3702 pSMB->TotalDataCount = 0;
3703 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003704 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 pSMB->MaxSetupCount = 0;
3706 pSMB->Reserved = 0;
3707 pSMB->Flags = 0;
3708 pSMB->Timeout = 0;
3709 pSMB->Reserved2 = 0;
3710 byte_count = params + 1 /* pad */ ;
3711 pSMB->TotalParameterCount = cpu_to_le16(params);
3712 pSMB->ParameterCount = pSMB->TotalParameterCount;
3713 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3714 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3715 pSMB->DataCount = 0;
3716 pSMB->DataOffset = 0;
3717 pSMB->SetupCount = 1;
3718 pSMB->Reserved3 = 0;
3719 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3720 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3721 pSMB->hdr.smb_buf_length += byte_count;
3722 pSMB->ByteCount = cpu_to_le16(byte_count);
3723
3724 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3725 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3726 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003727 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 } else { /* decode response */
3729 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3730
Steve French20962432005-09-21 22:05:57 -07003731 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 rc = -EIO; /* bad smb */
3733 else {
3734 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735
3736 response_data =
3737 (FILE_SYSTEM_INFO
3738 *) (((char *) &pSMBr->hdr.Protocol) +
3739 data_offset);
3740 FSData->f_bsize =
3741 le32_to_cpu(response_data->BytesPerSector) *
3742 le32_to_cpu(response_data->
3743 SectorsPerAllocationUnit);
3744 FSData->f_blocks =
3745 le64_to_cpu(response_data->TotalAllocationUnits);
3746 FSData->f_bfree = FSData->f_bavail =
3747 le64_to_cpu(response_data->FreeAllocationUnits);
3748 cFYI(1,
3749 ("Blocks: %lld Free: %lld Block size %ld",
3750 (unsigned long long)FSData->f_blocks,
3751 (unsigned long long)FSData->f_bfree,
3752 FSData->f_bsize));
3753 }
3754 }
3755 cifs_buf_release(pSMB);
3756
3757 if (rc == -EAGAIN)
3758 goto QFSInfoRetry;
3759
3760 return rc;
3761}
3762
3763int
Steve French737b7582005-04-28 22:41:06 -07003764CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765{
3766/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3767 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3768 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3769 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3770 int rc = 0;
3771 int bytes_returned = 0;
3772 __u16 params, byte_count;
3773
3774 cFYI(1, ("In QFSAttributeInfo"));
3775QFSAttributeRetry:
3776 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3777 (void **) &pSMBr);
3778 if (rc)
3779 return rc;
3780
3781 params = 2; /* level */
3782 pSMB->TotalDataCount = 0;
3783 pSMB->MaxParameterCount = cpu_to_le16(2);
3784 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3785 pSMB->MaxSetupCount = 0;
3786 pSMB->Reserved = 0;
3787 pSMB->Flags = 0;
3788 pSMB->Timeout = 0;
3789 pSMB->Reserved2 = 0;
3790 byte_count = params + 1 /* pad */ ;
3791 pSMB->TotalParameterCount = cpu_to_le16(params);
3792 pSMB->ParameterCount = pSMB->TotalParameterCount;
3793 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3794 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3795 pSMB->DataCount = 0;
3796 pSMB->DataOffset = 0;
3797 pSMB->SetupCount = 1;
3798 pSMB->Reserved3 = 0;
3799 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3800 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3801 pSMB->hdr.smb_buf_length += byte_count;
3802 pSMB->ByteCount = cpu_to_le16(byte_count);
3803
3804 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3805 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3806 if (rc) {
3807 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3808 } else { /* decode response */
3809 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3810
3811 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3812 rc = -EIO; /* bad smb */
3813 } else {
3814 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3815 response_data =
3816 (FILE_SYSTEM_ATTRIBUTE_INFO
3817 *) (((char *) &pSMBr->hdr.Protocol) +
3818 data_offset);
3819 memcpy(&tcon->fsAttrInfo, response_data,
3820 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3821 }
3822 }
3823 cifs_buf_release(pSMB);
3824
3825 if (rc == -EAGAIN)
3826 goto QFSAttributeRetry;
3827
3828 return rc;
3829}
3830
3831int
Steve French737b7582005-04-28 22:41:06 -07003832CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833{
3834/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3835 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3836 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3837 FILE_SYSTEM_DEVICE_INFO *response_data;
3838 int rc = 0;
3839 int bytes_returned = 0;
3840 __u16 params, byte_count;
3841
3842 cFYI(1, ("In QFSDeviceInfo"));
3843QFSDeviceRetry:
3844 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3845 (void **) &pSMBr);
3846 if (rc)
3847 return rc;
3848
3849 params = 2; /* level */
3850 pSMB->TotalDataCount = 0;
3851 pSMB->MaxParameterCount = cpu_to_le16(2);
3852 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3853 pSMB->MaxSetupCount = 0;
3854 pSMB->Reserved = 0;
3855 pSMB->Flags = 0;
3856 pSMB->Timeout = 0;
3857 pSMB->Reserved2 = 0;
3858 byte_count = params + 1 /* pad */ ;
3859 pSMB->TotalParameterCount = cpu_to_le16(params);
3860 pSMB->ParameterCount = pSMB->TotalParameterCount;
3861 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3862 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3863
3864 pSMB->DataCount = 0;
3865 pSMB->DataOffset = 0;
3866 pSMB->SetupCount = 1;
3867 pSMB->Reserved3 = 0;
3868 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3869 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3870 pSMB->hdr.smb_buf_length += byte_count;
3871 pSMB->ByteCount = cpu_to_le16(byte_count);
3872
3873 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3874 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3875 if (rc) {
3876 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3877 } else { /* decode response */
3878 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3879
3880 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3881 rc = -EIO; /* bad smb */
3882 else {
3883 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3884 response_data =
Steve French737b7582005-04-28 22:41:06 -07003885 (FILE_SYSTEM_DEVICE_INFO *)
3886 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 data_offset);
3888 memcpy(&tcon->fsDevInfo, response_data,
3889 sizeof (FILE_SYSTEM_DEVICE_INFO));
3890 }
3891 }
3892 cifs_buf_release(pSMB);
3893
3894 if (rc == -EAGAIN)
3895 goto QFSDeviceRetry;
3896
3897 return rc;
3898}
3899
3900int
Steve French737b7582005-04-28 22:41:06 -07003901CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902{
3903/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3904 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3905 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3906 FILE_SYSTEM_UNIX_INFO *response_data;
3907 int rc = 0;
3908 int bytes_returned = 0;
3909 __u16 params, byte_count;
3910
3911 cFYI(1, ("In QFSUnixInfo"));
3912QFSUnixRetry:
3913 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3914 (void **) &pSMBr);
3915 if (rc)
3916 return rc;
3917
3918 params = 2; /* level */
3919 pSMB->TotalDataCount = 0;
3920 pSMB->DataCount = 0;
3921 pSMB->DataOffset = 0;
3922 pSMB->MaxParameterCount = cpu_to_le16(2);
3923 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3924 pSMB->MaxSetupCount = 0;
3925 pSMB->Reserved = 0;
3926 pSMB->Flags = 0;
3927 pSMB->Timeout = 0;
3928 pSMB->Reserved2 = 0;
3929 byte_count = params + 1 /* pad */ ;
3930 pSMB->ParameterCount = cpu_to_le16(params);
3931 pSMB->TotalParameterCount = pSMB->ParameterCount;
3932 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3933 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3934 pSMB->SetupCount = 1;
3935 pSMB->Reserved3 = 0;
3936 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3937 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3938 pSMB->hdr.smb_buf_length += byte_count;
3939 pSMB->ByteCount = cpu_to_le16(byte_count);
3940
3941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3943 if (rc) {
3944 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3945 } else { /* decode response */
3946 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3947
3948 if (rc || (pSMBr->ByteCount < 13)) {
3949 rc = -EIO; /* bad smb */
3950 } else {
3951 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3952 response_data =
3953 (FILE_SYSTEM_UNIX_INFO
3954 *) (((char *) &pSMBr->hdr.Protocol) +
3955 data_offset);
3956 memcpy(&tcon->fsUnixInfo, response_data,
3957 sizeof (FILE_SYSTEM_UNIX_INFO));
3958 }
3959 }
3960 cifs_buf_release(pSMB);
3961
3962 if (rc == -EAGAIN)
3963 goto QFSUnixRetry;
3964
3965
3966 return rc;
3967}
3968
Jeremy Allisonac670552005-06-22 17:26:35 -07003969int
Steve French45abc6e2005-06-23 13:42:03 -05003970CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003971{
3972/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3973 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3974 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3975 int rc = 0;
3976 int bytes_returned = 0;
3977 __u16 params, param_offset, offset, byte_count;
3978
3979 cFYI(1, ("In SETFSUnixInfo"));
3980SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00003981 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07003982 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3983 (void **) &pSMBr);
3984 if (rc)
3985 return rc;
3986
3987 params = 4; /* 2 bytes zero followed by info level. */
3988 pSMB->MaxSetupCount = 0;
3989 pSMB->Reserved = 0;
3990 pSMB->Flags = 0;
3991 pSMB->Timeout = 0;
3992 pSMB->Reserved2 = 0;
3993 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3994 offset = param_offset + params;
3995
3996 pSMB->MaxParameterCount = cpu_to_le16(4);
3997 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3998 pSMB->SetupCount = 1;
3999 pSMB->Reserved3 = 0;
4000 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4001 byte_count = 1 /* pad */ + params + 12;
4002
4003 pSMB->DataCount = cpu_to_le16(12);
4004 pSMB->ParameterCount = cpu_to_le16(params);
4005 pSMB->TotalDataCount = pSMB->DataCount;
4006 pSMB->TotalParameterCount = pSMB->ParameterCount;
4007 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4008 pSMB->DataOffset = cpu_to_le16(offset);
4009
4010 /* Params. */
4011 pSMB->FileNum = 0;
4012 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4013
4014 /* Data. */
4015 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4016 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4017 pSMB->ClientUnixCap = cpu_to_le64(cap);
4018
4019 pSMB->hdr.smb_buf_length += byte_count;
4020 pSMB->ByteCount = cpu_to_le16(byte_count);
4021
4022 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4024 if (rc) {
4025 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4026 } else { /* decode response */
4027 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4028 if (rc) {
4029 rc = -EIO; /* bad smb */
4030 }
4031 }
4032 cifs_buf_release(pSMB);
4033
4034 if (rc == -EAGAIN)
4035 goto SETFSUnixRetry;
4036
4037 return rc;
4038}
4039
4040
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041
4042int
4043CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004044 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045{
4046/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4047 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4048 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4049 FILE_SYSTEM_POSIX_INFO *response_data;
4050 int rc = 0;
4051 int bytes_returned = 0;
4052 __u16 params, byte_count;
4053
4054 cFYI(1, ("In QFSPosixInfo"));
4055QFSPosixRetry:
4056 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4057 (void **) &pSMBr);
4058 if (rc)
4059 return rc;
4060
4061 params = 2; /* level */
4062 pSMB->TotalDataCount = 0;
4063 pSMB->DataCount = 0;
4064 pSMB->DataOffset = 0;
4065 pSMB->MaxParameterCount = cpu_to_le16(2);
4066 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4067 pSMB->MaxSetupCount = 0;
4068 pSMB->Reserved = 0;
4069 pSMB->Flags = 0;
4070 pSMB->Timeout = 0;
4071 pSMB->Reserved2 = 0;
4072 byte_count = params + 1 /* pad */ ;
4073 pSMB->ParameterCount = cpu_to_le16(params);
4074 pSMB->TotalParameterCount = pSMB->ParameterCount;
4075 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4076 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4077 pSMB->SetupCount = 1;
4078 pSMB->Reserved3 = 0;
4079 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4080 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4081 pSMB->hdr.smb_buf_length += byte_count;
4082 pSMB->ByteCount = cpu_to_le16(byte_count);
4083
4084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4086 if (rc) {
4087 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4088 } else { /* decode response */
4089 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4090
4091 if (rc || (pSMBr->ByteCount < 13)) {
4092 rc = -EIO; /* bad smb */
4093 } else {
4094 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4095 response_data =
4096 (FILE_SYSTEM_POSIX_INFO
4097 *) (((char *) &pSMBr->hdr.Protocol) +
4098 data_offset);
4099 FSData->f_bsize =
4100 le32_to_cpu(response_data->BlockSize);
4101 FSData->f_blocks =
4102 le64_to_cpu(response_data->TotalBlocks);
4103 FSData->f_bfree =
4104 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004105 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 FSData->f_bavail = FSData->f_bfree;
4107 } else {
4108 FSData->f_bavail =
4109 le64_to_cpu(response_data->UserBlocksAvail);
4110 }
Steve French70ca7342005-09-22 16:32:06 -07004111 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 FSData->f_files =
4113 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004114 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 FSData->f_ffree =
4116 le64_to_cpu(response_data->FreeFileNodes);
4117 }
4118 }
4119 cifs_buf_release(pSMB);
4120
4121 if (rc == -EAGAIN)
4122 goto QFSPosixRetry;
4123
4124 return rc;
4125}
4126
4127
4128/* We can not use write of zero bytes trick to
4129 set file size due to need for large file support. Also note that
4130 this SetPathInfo is preferred to SetFileInfo based method in next
4131 routine which is only needed to work around a sharing violation bug
4132 in Samba which this routine can run into */
4133
4134int
4135CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004136 __u64 size, int SetAllocation,
4137 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138{
4139 struct smb_com_transaction2_spi_req *pSMB = NULL;
4140 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4141 struct file_end_of_file_info *parm_data;
4142 int name_len;
4143 int rc = 0;
4144 int bytes_returned = 0;
4145 __u16 params, byte_count, data_count, param_offset, offset;
4146
4147 cFYI(1, ("In SetEOF"));
4148SetEOFRetry:
4149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150 (void **) &pSMBr);
4151 if (rc)
4152 return rc;
4153
4154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4155 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004156 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004157 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 name_len++; /* trailing null */
4159 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004160 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 name_len = strnlen(fileName, PATH_MAX);
4162 name_len++; /* trailing null */
4163 strncpy(pSMB->FileName, fileName, name_len);
4164 }
4165 params = 6 + name_len;
4166 data_count = sizeof (struct file_end_of_file_info);
4167 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004168 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 pSMB->MaxSetupCount = 0;
4170 pSMB->Reserved = 0;
4171 pSMB->Flags = 0;
4172 pSMB->Timeout = 0;
4173 pSMB->Reserved2 = 0;
4174 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4175 InformationLevel) - 4;
4176 offset = param_offset + params;
4177 if(SetAllocation) {
4178 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4179 pSMB->InformationLevel =
4180 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4181 else
4182 pSMB->InformationLevel =
4183 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4184 } else /* Set File Size */ {
4185 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4186 pSMB->InformationLevel =
4187 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4188 else
4189 pSMB->InformationLevel =
4190 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4191 }
4192
4193 parm_data =
4194 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4195 offset);
4196 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4197 pSMB->DataOffset = cpu_to_le16(offset);
4198 pSMB->SetupCount = 1;
4199 pSMB->Reserved3 = 0;
4200 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4201 byte_count = 3 /* pad */ + params + data_count;
4202 pSMB->DataCount = cpu_to_le16(data_count);
4203 pSMB->TotalDataCount = pSMB->DataCount;
4204 pSMB->ParameterCount = cpu_to_le16(params);
4205 pSMB->TotalParameterCount = pSMB->ParameterCount;
4206 pSMB->Reserved4 = 0;
4207 pSMB->hdr.smb_buf_length += byte_count;
4208 parm_data->FileSize = cpu_to_le64(size);
4209 pSMB->ByteCount = cpu_to_le16(byte_count);
4210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4212 if (rc) {
4213 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4214 }
4215
4216 cifs_buf_release(pSMB);
4217
4218 if (rc == -EAGAIN)
4219 goto SetEOFRetry;
4220
4221 return rc;
4222}
4223
4224int
4225CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4226 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4227{
4228 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4229 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4230 char *data_offset;
4231 struct file_end_of_file_info *parm_data;
4232 int rc = 0;
4233 int bytes_returned = 0;
4234 __u16 params, param_offset, offset, byte_count, count;
4235
4236 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4237 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004238 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4239
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 if (rc)
4241 return rc;
4242
Steve Frenchcd634992005-04-28 22:41:10 -07004243 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4244
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4246 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4247
4248 params = 6;
4249 pSMB->MaxSetupCount = 0;
4250 pSMB->Reserved = 0;
4251 pSMB->Flags = 0;
4252 pSMB->Timeout = 0;
4253 pSMB->Reserved2 = 0;
4254 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4255 offset = param_offset + params;
4256
4257 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4258
4259 count = sizeof(struct file_end_of_file_info);
4260 pSMB->MaxParameterCount = cpu_to_le16(2);
4261 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4262 pSMB->SetupCount = 1;
4263 pSMB->Reserved3 = 0;
4264 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4265 byte_count = 3 /* pad */ + params + count;
4266 pSMB->DataCount = cpu_to_le16(count);
4267 pSMB->ParameterCount = cpu_to_le16(params);
4268 pSMB->TotalDataCount = pSMB->DataCount;
4269 pSMB->TotalParameterCount = pSMB->ParameterCount;
4270 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4271 parm_data =
4272 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4273 offset);
4274 pSMB->DataOffset = cpu_to_le16(offset);
4275 parm_data->FileSize = cpu_to_le64(size);
4276 pSMB->Fid = fid;
4277 if(SetAllocation) {
4278 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4279 pSMB->InformationLevel =
4280 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4281 else
4282 pSMB->InformationLevel =
4283 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4284 } else /* Set File Size */ {
4285 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4286 pSMB->InformationLevel =
4287 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4288 else
4289 pSMB->InformationLevel =
4290 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4291 }
4292 pSMB->Reserved4 = 0;
4293 pSMB->hdr.smb_buf_length += byte_count;
4294 pSMB->ByteCount = cpu_to_le16(byte_count);
4295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4297 if (rc) {
4298 cFYI(1,
4299 ("Send error in SetFileInfo (SetFileSize) = %d",
4300 rc));
4301 }
4302
4303 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004304 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305
4306 /* Note: On -EAGAIN error only caller can retry on handle based calls
4307 since file handle passed in no longer valid */
4308
4309 return rc;
4310}
4311
4312/* Some legacy servers such as NT4 require that the file times be set on
4313 an open handle, rather than by pathname - this is awkward due to
4314 potential access conflicts on the open, but it is unavoidable for these
4315 old servers since the only other choice is to go from 100 nanosecond DCE
4316 time and resort to the original setpathinfo level which takes the ancient
4317 DOS time format with 2 second granularity */
4318int
4319CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4320 __u16 fid)
4321{
4322 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4323 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4324 char *data_offset;
4325 int rc = 0;
4326 int bytes_returned = 0;
4327 __u16 params, param_offset, offset, byte_count, count;
4328
4329 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004330 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4331
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 if (rc)
4333 return rc;
4334
Steve Frenchcd634992005-04-28 22:41:10 -07004335 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4336
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 /* At this point there is no need to override the current pid
4338 with the pid of the opener, but that could change if we someday
4339 use an existing handle (rather than opening one on the fly) */
4340 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4341 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4342
4343 params = 6;
4344 pSMB->MaxSetupCount = 0;
4345 pSMB->Reserved = 0;
4346 pSMB->Flags = 0;
4347 pSMB->Timeout = 0;
4348 pSMB->Reserved2 = 0;
4349 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4350 offset = param_offset + params;
4351
4352 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4353
4354 count = sizeof (FILE_BASIC_INFO);
4355 pSMB->MaxParameterCount = cpu_to_le16(2);
4356 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4357 pSMB->SetupCount = 1;
4358 pSMB->Reserved3 = 0;
4359 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4360 byte_count = 3 /* pad */ + params + count;
4361 pSMB->DataCount = cpu_to_le16(count);
4362 pSMB->ParameterCount = cpu_to_le16(params);
4363 pSMB->TotalDataCount = pSMB->DataCount;
4364 pSMB->TotalParameterCount = pSMB->ParameterCount;
4365 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4366 pSMB->DataOffset = cpu_to_le16(offset);
4367 pSMB->Fid = fid;
4368 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4369 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4370 else
4371 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4372 pSMB->Reserved4 = 0;
4373 pSMB->hdr.smb_buf_length += byte_count;
4374 pSMB->ByteCount = cpu_to_le16(byte_count);
4375 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4378 if (rc) {
4379 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4380 }
4381
Steve Frenchcd634992005-04-28 22:41:10 -07004382 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383
4384 /* Note: On -EAGAIN error only caller can retry on handle based calls
4385 since file handle passed in no longer valid */
4386
4387 return rc;
4388}
4389
4390
4391int
4392CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4393 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004394 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395{
4396 TRANSACTION2_SPI_REQ *pSMB = NULL;
4397 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4398 int name_len;
4399 int rc = 0;
4400 int bytes_returned = 0;
4401 char *data_offset;
4402 __u16 params, param_offset, offset, byte_count, count;
4403
4404 cFYI(1, ("In SetTimes"));
4405
4406SetTimesRetry:
4407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4408 (void **) &pSMBr);
4409 if (rc)
4410 return rc;
4411
4412 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4413 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004414 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004415 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 name_len++; /* trailing null */
4417 name_len *= 2;
4418 } else { /* BB improve the check for buffer overruns BB */
4419 name_len = strnlen(fileName, PATH_MAX);
4420 name_len++; /* trailing null */
4421 strncpy(pSMB->FileName, fileName, name_len);
4422 }
4423
4424 params = 6 + name_len;
4425 count = sizeof (FILE_BASIC_INFO);
4426 pSMB->MaxParameterCount = cpu_to_le16(2);
4427 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4428 pSMB->MaxSetupCount = 0;
4429 pSMB->Reserved = 0;
4430 pSMB->Flags = 0;
4431 pSMB->Timeout = 0;
4432 pSMB->Reserved2 = 0;
4433 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4434 InformationLevel) - 4;
4435 offset = param_offset + params;
4436 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4437 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4438 pSMB->DataOffset = cpu_to_le16(offset);
4439 pSMB->SetupCount = 1;
4440 pSMB->Reserved3 = 0;
4441 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4442 byte_count = 3 /* pad */ + params + count;
4443
4444 pSMB->DataCount = cpu_to_le16(count);
4445 pSMB->ParameterCount = cpu_to_le16(params);
4446 pSMB->TotalDataCount = pSMB->DataCount;
4447 pSMB->TotalParameterCount = pSMB->ParameterCount;
4448 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4449 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4450 else
4451 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4452 pSMB->Reserved4 = 0;
4453 pSMB->hdr.smb_buf_length += byte_count;
4454 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4455 pSMB->ByteCount = cpu_to_le16(byte_count);
4456 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4457 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4458 if (rc) {
4459 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4460 }
4461
4462 cifs_buf_release(pSMB);
4463
4464 if (rc == -EAGAIN)
4465 goto SetTimesRetry;
4466
4467 return rc;
4468}
4469
4470/* Can not be used to set time stamps yet (due to old DOS time format) */
4471/* Can be used to set attributes */
4472#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4473 handling it anyway and NT4 was what we thought it would be needed for
4474 Do not delete it until we prove whether needed for Win9x though */
4475int
4476CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4477 __u16 dos_attrs, const struct nls_table *nls_codepage)
4478{
4479 SETATTR_REQ *pSMB = NULL;
4480 SETATTR_RSP *pSMBr = NULL;
4481 int rc = 0;
4482 int bytes_returned;
4483 int name_len;
4484
4485 cFYI(1, ("In SetAttrLegacy"));
4486
4487SetAttrLgcyRetry:
4488 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4489 (void **) &pSMBr);
4490 if (rc)
4491 return rc;
4492
4493 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4494 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004495 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 PATH_MAX, nls_codepage);
4497 name_len++; /* trailing null */
4498 name_len *= 2;
4499 } else { /* BB improve the check for buffer overruns BB */
4500 name_len = strnlen(fileName, PATH_MAX);
4501 name_len++; /* trailing null */
4502 strncpy(pSMB->fileName, fileName, name_len);
4503 }
4504 pSMB->attr = cpu_to_le16(dos_attrs);
4505 pSMB->BufferFormat = 0x04;
4506 pSMB->hdr.smb_buf_length += name_len + 1;
4507 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4510 if (rc) {
4511 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4512 }
4513
4514 cifs_buf_release(pSMB);
4515
4516 if (rc == -EAGAIN)
4517 goto SetAttrLgcyRetry;
4518
4519 return rc;
4520}
4521#endif /* temporarily unneeded SetAttr legacy function */
4522
4523int
4524CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004525 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4526 dev_t device, const struct nls_table *nls_codepage,
4527 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528{
4529 TRANSACTION2_SPI_REQ *pSMB = NULL;
4530 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4531 int name_len;
4532 int rc = 0;
4533 int bytes_returned = 0;
4534 FILE_UNIX_BASIC_INFO *data_offset;
4535 __u16 params, param_offset, offset, count, byte_count;
4536
4537 cFYI(1, ("In SetUID/GID/Mode"));
4538setPermsRetry:
4539 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4540 (void **) &pSMBr);
4541 if (rc)
4542 return rc;
4543
4544 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4545 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004546 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004547 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 name_len++; /* trailing null */
4549 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004550 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 name_len = strnlen(fileName, PATH_MAX);
4552 name_len++; /* trailing null */
4553 strncpy(pSMB->FileName, fileName, name_len);
4554 }
4555
4556 params = 6 + name_len;
4557 count = sizeof (FILE_UNIX_BASIC_INFO);
4558 pSMB->MaxParameterCount = cpu_to_le16(2);
4559 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4560 pSMB->MaxSetupCount = 0;
4561 pSMB->Reserved = 0;
4562 pSMB->Flags = 0;
4563 pSMB->Timeout = 0;
4564 pSMB->Reserved2 = 0;
4565 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4566 InformationLevel) - 4;
4567 offset = param_offset + params;
4568 data_offset =
4569 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4570 offset);
4571 memset(data_offset, 0, count);
4572 pSMB->DataOffset = cpu_to_le16(offset);
4573 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4574 pSMB->SetupCount = 1;
4575 pSMB->Reserved3 = 0;
4576 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4577 byte_count = 3 /* pad */ + params + count;
4578 pSMB->ParameterCount = cpu_to_le16(params);
4579 pSMB->DataCount = cpu_to_le16(count);
4580 pSMB->TotalParameterCount = pSMB->ParameterCount;
4581 pSMB->TotalDataCount = pSMB->DataCount;
4582 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4583 pSMB->Reserved4 = 0;
4584 pSMB->hdr.smb_buf_length += byte_count;
4585 data_offset->Uid = cpu_to_le64(uid);
4586 data_offset->Gid = cpu_to_le64(gid);
4587 /* better to leave device as zero when it is */
4588 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4589 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4590 data_offset->Permissions = cpu_to_le64(mode);
4591
4592 if(S_ISREG(mode))
4593 data_offset->Type = cpu_to_le32(UNIX_FILE);
4594 else if(S_ISDIR(mode))
4595 data_offset->Type = cpu_to_le32(UNIX_DIR);
4596 else if(S_ISLNK(mode))
4597 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4598 else if(S_ISCHR(mode))
4599 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4600 else if(S_ISBLK(mode))
4601 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4602 else if(S_ISFIFO(mode))
4603 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4604 else if(S_ISSOCK(mode))
4605 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4606
4607
4608 pSMB->ByteCount = cpu_to_le16(byte_count);
4609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4610 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4611 if (rc) {
4612 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4613 }
4614
4615 if (pSMB)
4616 cifs_buf_release(pSMB);
4617 if (rc == -EAGAIN)
4618 goto setPermsRetry;
4619 return rc;
4620}
4621
4622int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004623 const int notify_subdirs, const __u16 netfid,
4624 __u32 filter, struct file * pfile, int multishot,
4625 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626{
4627 int rc = 0;
4628 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004629 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004630 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 int bytes_returned;
4632
4633 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4634 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4635 (void **) &pSMBr);
4636 if (rc)
4637 return rc;
4638
4639 pSMB->TotalParameterCount = 0 ;
4640 pSMB->TotalDataCount = 0;
4641 pSMB->MaxParameterCount = cpu_to_le32(2);
4642 /* BB find exact data count max from sess structure BB */
4643 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004644/* BB VERIFY verify which is correct for above BB */
4645 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4646 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4647
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 pSMB->MaxSetupCount = 4;
4649 pSMB->Reserved = 0;
4650 pSMB->ParameterOffset = 0;
4651 pSMB->DataCount = 0;
4652 pSMB->DataOffset = 0;
4653 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4654 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4655 pSMB->ParameterCount = pSMB->TotalParameterCount;
4656 if(notify_subdirs)
4657 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4658 pSMB->Reserved2 = 0;
4659 pSMB->CompletionFilter = cpu_to_le32(filter);
4660 pSMB->Fid = netfid; /* file handle always le */
4661 pSMB->ByteCount = 0;
4662
4663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4664 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4665 if (rc) {
4666 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004667 } else {
4668 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004669 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004670 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004671 sizeof(struct dir_notify_req),
4672 GFP_KERNEL);
4673 if(dnotify_req) {
4674 dnotify_req->Pid = pSMB->hdr.Pid;
4675 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4676 dnotify_req->Mid = pSMB->hdr.Mid;
4677 dnotify_req->Tid = pSMB->hdr.Tid;
4678 dnotify_req->Uid = pSMB->hdr.Uid;
4679 dnotify_req->netfid = netfid;
4680 dnotify_req->pfile = pfile;
4681 dnotify_req->filter = filter;
4682 dnotify_req->multishot = multishot;
4683 spin_lock(&GlobalMid_Lock);
4684 list_add_tail(&dnotify_req->lhead,
4685 &GlobalDnotifyReqList);
4686 spin_unlock(&GlobalMid_Lock);
4687 } else
4688 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 }
4690 cifs_buf_release(pSMB);
4691 return rc;
4692}
4693#ifdef CONFIG_CIFS_XATTR
4694ssize_t
4695CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4696 const unsigned char *searchName,
4697 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004698 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699{
4700 /* BB assumes one setup word */
4701 TRANSACTION2_QPI_REQ *pSMB = NULL;
4702 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4703 int rc = 0;
4704 int bytes_returned;
4705 int name_len;
4706 struct fea * temp_fea;
4707 char * temp_ptr;
4708 __u16 params, byte_count;
4709
4710 cFYI(1, ("In Query All EAs path %s", searchName));
4711QAllEAsRetry:
4712 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4713 (void **) &pSMBr);
4714 if (rc)
4715 return rc;
4716
4717 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4718 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004719 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004720 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 name_len++; /* trailing null */
4722 name_len *= 2;
4723 } else { /* BB improve the check for buffer overruns BB */
4724 name_len = strnlen(searchName, PATH_MAX);
4725 name_len++; /* trailing null */
4726 strncpy(pSMB->FileName, searchName, name_len);
4727 }
4728
4729 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4730 pSMB->TotalDataCount = 0;
4731 pSMB->MaxParameterCount = cpu_to_le16(2);
4732 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4733 pSMB->MaxSetupCount = 0;
4734 pSMB->Reserved = 0;
4735 pSMB->Flags = 0;
4736 pSMB->Timeout = 0;
4737 pSMB->Reserved2 = 0;
4738 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4739 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4740 pSMB->DataCount = 0;
4741 pSMB->DataOffset = 0;
4742 pSMB->SetupCount = 1;
4743 pSMB->Reserved3 = 0;
4744 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4745 byte_count = params + 1 /* pad */ ;
4746 pSMB->TotalParameterCount = cpu_to_le16(params);
4747 pSMB->ParameterCount = pSMB->TotalParameterCount;
4748 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4749 pSMB->Reserved4 = 0;
4750 pSMB->hdr.smb_buf_length += byte_count;
4751 pSMB->ByteCount = cpu_to_le16(byte_count);
4752
4753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4754 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4755 if (rc) {
4756 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4757 } else { /* decode response */
4758 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4759
4760 /* BB also check enough total bytes returned */
4761 /* BB we need to improve the validity checking
4762 of these trans2 responses */
4763 if (rc || (pSMBr->ByteCount < 4))
4764 rc = -EIO; /* bad smb */
4765 /* else if (pFindData){
4766 memcpy((char *) pFindData,
4767 (char *) &pSMBr->hdr.Protocol +
4768 data_offset, kl);
4769 }*/ else {
4770 /* check that length of list is not more than bcc */
4771 /* check that each entry does not go beyond length
4772 of list */
4773 /* check that each element of each entry does not
4774 go beyond end of list */
4775 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4776 struct fealist * ea_response_data;
4777 rc = 0;
4778 /* validate_trans2_offsets() */
4779 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4780 ea_response_data = (struct fealist *)
4781 (((char *) &pSMBr->hdr.Protocol) +
4782 data_offset);
4783 name_len = le32_to_cpu(ea_response_data->list_len);
4784 cFYI(1,("ea length %d", name_len));
4785 if(name_len <= 8) {
4786 /* returned EA size zeroed at top of function */
4787 cFYI(1,("empty EA list returned from server"));
4788 } else {
4789 /* account for ea list len */
4790 name_len -= 4;
4791 temp_fea = ea_response_data->list;
4792 temp_ptr = (char *)temp_fea;
4793 while(name_len > 0) {
4794 __u16 value_len;
4795 name_len -= 4;
4796 temp_ptr += 4;
4797 rc += temp_fea->name_len;
4798 /* account for prefix user. and trailing null */
4799 rc = rc + 5 + 1;
4800 if(rc<(int)buf_size) {
4801 memcpy(EAData,"user.",5);
4802 EAData+=5;
4803 memcpy(EAData,temp_ptr,temp_fea->name_len);
4804 EAData+=temp_fea->name_len;
4805 /* null terminate name */
4806 *EAData = 0;
4807 EAData = EAData + 1;
4808 } else if(buf_size == 0) {
4809 /* skip copy - calc size only */
4810 } else {
4811 /* stop before overrun buffer */
4812 rc = -ERANGE;
4813 break;
4814 }
4815 name_len -= temp_fea->name_len;
4816 temp_ptr += temp_fea->name_len;
4817 /* account for trailing null */
4818 name_len--;
4819 temp_ptr++;
4820 value_len = le16_to_cpu(temp_fea->value_len);
4821 name_len -= value_len;
4822 temp_ptr += value_len;
4823 /* BB check that temp_ptr is still within smb BB*/
4824 /* no trailing null to account for in value len */
4825 /* go on to next EA */
4826 temp_fea = (struct fea *)temp_ptr;
4827 }
4828 }
4829 }
4830 }
4831 if (pSMB)
4832 cifs_buf_release(pSMB);
4833 if (rc == -EAGAIN)
4834 goto QAllEAsRetry;
4835
4836 return (ssize_t)rc;
4837}
4838
4839ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4840 const unsigned char * searchName,const unsigned char * ea_name,
4841 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004842 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843{
4844 TRANSACTION2_QPI_REQ *pSMB = NULL;
4845 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4846 int rc = 0;
4847 int bytes_returned;
4848 int name_len;
4849 struct fea * temp_fea;
4850 char * temp_ptr;
4851 __u16 params, byte_count;
4852
4853 cFYI(1, ("In Query EA path %s", searchName));
4854QEARetry:
4855 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4856 (void **) &pSMBr);
4857 if (rc)
4858 return rc;
4859
4860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4861 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004862 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004863 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 name_len++; /* trailing null */
4865 name_len *= 2;
4866 } else { /* BB improve the check for buffer overruns BB */
4867 name_len = strnlen(searchName, PATH_MAX);
4868 name_len++; /* trailing null */
4869 strncpy(pSMB->FileName, searchName, name_len);
4870 }
4871
4872 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4873 pSMB->TotalDataCount = 0;
4874 pSMB->MaxParameterCount = cpu_to_le16(2);
4875 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4876 pSMB->MaxSetupCount = 0;
4877 pSMB->Reserved = 0;
4878 pSMB->Flags = 0;
4879 pSMB->Timeout = 0;
4880 pSMB->Reserved2 = 0;
4881 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4882 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4883 pSMB->DataCount = 0;
4884 pSMB->DataOffset = 0;
4885 pSMB->SetupCount = 1;
4886 pSMB->Reserved3 = 0;
4887 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4888 byte_count = params + 1 /* pad */ ;
4889 pSMB->TotalParameterCount = cpu_to_le16(params);
4890 pSMB->ParameterCount = pSMB->TotalParameterCount;
4891 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4892 pSMB->Reserved4 = 0;
4893 pSMB->hdr.smb_buf_length += byte_count;
4894 pSMB->ByteCount = cpu_to_le16(byte_count);
4895
4896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4898 if (rc) {
4899 cFYI(1, ("Send error in Query EA = %d", rc));
4900 } else { /* decode response */
4901 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4902
4903 /* BB also check enough total bytes returned */
4904 /* BB we need to improve the validity checking
4905 of these trans2 responses */
4906 if (rc || (pSMBr->ByteCount < 4))
4907 rc = -EIO; /* bad smb */
4908 /* else if (pFindData){
4909 memcpy((char *) pFindData,
4910 (char *) &pSMBr->hdr.Protocol +
4911 data_offset, kl);
4912 }*/ else {
4913 /* check that length of list is not more than bcc */
4914 /* check that each entry does not go beyond length
4915 of list */
4916 /* check that each element of each entry does not
4917 go beyond end of list */
4918 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4919 struct fealist * ea_response_data;
4920 rc = -ENODATA;
4921 /* validate_trans2_offsets() */
4922 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4923 ea_response_data = (struct fealist *)
4924 (((char *) &pSMBr->hdr.Protocol) +
4925 data_offset);
4926 name_len = le32_to_cpu(ea_response_data->list_len);
4927 cFYI(1,("ea length %d", name_len));
4928 if(name_len <= 8) {
4929 /* returned EA size zeroed at top of function */
4930 cFYI(1,("empty EA list returned from server"));
4931 } else {
4932 /* account for ea list len */
4933 name_len -= 4;
4934 temp_fea = ea_response_data->list;
4935 temp_ptr = (char *)temp_fea;
4936 /* loop through checking if we have a matching
4937 name and then return the associated value */
4938 while(name_len > 0) {
4939 __u16 value_len;
4940 name_len -= 4;
4941 temp_ptr += 4;
4942 value_len = le16_to_cpu(temp_fea->value_len);
4943 /* BB validate that value_len falls within SMB,
4944 even though maximum for name_len is 255 */
4945 if(memcmp(temp_fea->name,ea_name,
4946 temp_fea->name_len) == 0) {
4947 /* found a match */
4948 rc = value_len;
4949 /* account for prefix user. and trailing null */
4950 if(rc<=(int)buf_size) {
4951 memcpy(ea_value,
4952 temp_fea->name+temp_fea->name_len+1,
4953 rc);
4954 /* ea values, unlike ea names,
4955 are not null terminated */
4956 } else if(buf_size == 0) {
4957 /* skip copy - calc size only */
4958 } else {
4959 /* stop before overrun buffer */
4960 rc = -ERANGE;
4961 }
4962 break;
4963 }
4964 name_len -= temp_fea->name_len;
4965 temp_ptr += temp_fea->name_len;
4966 /* account for trailing null */
4967 name_len--;
4968 temp_ptr++;
4969 name_len -= value_len;
4970 temp_ptr += value_len;
4971 /* no trailing null to account for in value len */
4972 /* go on to next EA */
4973 temp_fea = (struct fea *)temp_ptr;
4974 }
4975 }
4976 }
4977 }
4978 if (pSMB)
4979 cifs_buf_release(pSMB);
4980 if (rc == -EAGAIN)
4981 goto QEARetry;
4982
4983 return (ssize_t)rc;
4984}
4985
4986int
4987CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4988 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004989 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4990 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991{
4992 struct smb_com_transaction2_spi_req *pSMB = NULL;
4993 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4994 struct fealist *parm_data;
4995 int name_len;
4996 int rc = 0;
4997 int bytes_returned = 0;
4998 __u16 params, param_offset, byte_count, offset, count;
4999
5000 cFYI(1, ("In SetEA"));
5001SetEARetry:
5002 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5003 (void **) &pSMBr);
5004 if (rc)
5005 return rc;
5006
5007 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5008 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005009 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005010 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 name_len++; /* trailing null */
5012 name_len *= 2;
5013 } else { /* BB improve the check for buffer overruns BB */
5014 name_len = strnlen(fileName, PATH_MAX);
5015 name_len++; /* trailing null */
5016 strncpy(pSMB->FileName, fileName, name_len);
5017 }
5018
5019 params = 6 + name_len;
5020
5021 /* done calculating parms using name_len of file name,
5022 now use name_len to calculate length of ea name
5023 we are going to create in the inode xattrs */
5024 if(ea_name == NULL)
5025 name_len = 0;
5026 else
5027 name_len = strnlen(ea_name,255);
5028
5029 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5030 pSMB->MaxParameterCount = cpu_to_le16(2);
5031 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5032 pSMB->MaxSetupCount = 0;
5033 pSMB->Reserved = 0;
5034 pSMB->Flags = 0;
5035 pSMB->Timeout = 0;
5036 pSMB->Reserved2 = 0;
5037 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5038 InformationLevel) - 4;
5039 offset = param_offset + params;
5040 pSMB->InformationLevel =
5041 cpu_to_le16(SMB_SET_FILE_EA);
5042
5043 parm_data =
5044 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5045 offset);
5046 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5047 pSMB->DataOffset = cpu_to_le16(offset);
5048 pSMB->SetupCount = 1;
5049 pSMB->Reserved3 = 0;
5050 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5051 byte_count = 3 /* pad */ + params + count;
5052 pSMB->DataCount = cpu_to_le16(count);
5053 parm_data->list_len = cpu_to_le32(count);
5054 parm_data->list[0].EA_flags = 0;
5055 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005056 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 /* EA names are always ASCII */
5058 if(ea_name)
5059 strncpy(parm_data->list[0].name,ea_name,name_len);
5060 parm_data->list[0].name[name_len] = 0;
5061 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5062 /* caller ensures that ea_value_len is less than 64K but
5063 we need to ensure that it fits within the smb */
5064
5065 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5066 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5067 if(ea_value_len)
5068 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5069
5070 pSMB->TotalDataCount = pSMB->DataCount;
5071 pSMB->ParameterCount = cpu_to_le16(params);
5072 pSMB->TotalParameterCount = pSMB->ParameterCount;
5073 pSMB->Reserved4 = 0;
5074 pSMB->hdr.smb_buf_length += byte_count;
5075 pSMB->ByteCount = cpu_to_le16(byte_count);
5076 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5077 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5078 if (rc) {
5079 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5080 }
5081
5082 cifs_buf_release(pSMB);
5083
5084 if (rc == -EAGAIN)
5085 goto SetEARetry;
5086
5087 return rc;
5088}
5089
5090#endif