blob: 38ab9f67c5f41c3a24b8862e4428c570a76182bc [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 Frenchec637e32005-12-12 20:53:18 -08001073 cifs_small_buf_release(pSMB);
1074 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);
1079 } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
1080 *buf = iov[0].iov_base;
1081 if(resp_buf_type == CIFS_SMALL_BUFFER)
1082 *pbuf_type = CIFS_SMALL_BUFFER;
1083 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1084 *pbuf_type = CIFS_LARGE_BUFFER;
1085 }
1086
1087 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 since file handle passed in no longer valid */
1089 return rc;
1090}
1091
Steve Frenchec637e32005-12-12 20:53:18 -08001092
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093int
1094CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1095 const int netfid, const unsigned int count,
1096 const __u64 offset, unsigned int *nbytes, const char *buf,
1097 const char __user * ubuf, const int long_op)
1098{
1099 int rc = -EACCES;
1100 WRITE_REQ *pSMB = NULL;
1101 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001102 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 __u32 bytes_sent;
1104 __u16 byte_count;
1105
1106 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001107 if(tcon->ses == NULL)
1108 return -ECONNABORTED;
1109
1110 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1111 wct = 14;
1112 else
1113 wct = 12;
1114
1115 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 (void **) &pSMBr);
1117 if (rc)
1118 return rc;
1119 /* tcon and ses pointer are checked in smb_init */
1120 if (tcon->ses->server == NULL)
1121 return -ECONNABORTED;
1122
1123 pSMB->AndXCommand = 0xFF; /* none */
1124 pSMB->Fid = netfid;
1125 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001126 if(wct == 14)
1127 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1128 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1129 return -EIO;
1130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 pSMB->Reserved = 0xFFFFFFFF;
1132 pSMB->WriteMode = 0;
1133 pSMB->Remaining = 0;
1134
1135 /* Can increase buffer size if buffer is big enough in some cases - ie we
1136 can send more if LARGE_WRITE_X capability returned by the server and if
1137 our buffer is big enough or if we convert to iovecs on socket writes
1138 and eliminate the copy to the CIFS buffer */
1139 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1140 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1141 } else {
1142 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1143 & ~0xFF;
1144 }
1145
1146 if (bytes_sent > count)
1147 bytes_sent = count;
1148 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001149 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 if(buf)
1151 memcpy(pSMB->Data,buf,bytes_sent);
1152 else if(ubuf) {
1153 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1154 cifs_buf_release(pSMB);
1155 return -EFAULT;
1156 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001157 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 /* No buffer */
1159 cifs_buf_release(pSMB);
1160 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001161 } /* else setting file size with write of zero bytes */
1162 if(wct == 14)
1163 byte_count = bytes_sent + 1; /* pad */
1164 else /* wct == 12 */ {
1165 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1168 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001169 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001170
1171 if(wct == 14)
1172 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001173 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001174 struct smb_com_writex_req * pSMBW =
1175 (struct smb_com_writex_req *)pSMB;
1176 pSMBW->ByteCount = cpu_to_le16(byte_count);
1177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
1179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1180 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001181 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 if (rc) {
1183 cFYI(1, ("Send error in write = %d", rc));
1184 *nbytes = 0;
1185 } else {
1186 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1187 *nbytes = (*nbytes) << 16;
1188 *nbytes += le16_to_cpu(pSMBr->Count);
1189 }
1190
1191 cifs_buf_release(pSMB);
1192
1193 /* Note: On -EAGAIN error only caller can retry on handle based calls
1194 since file handle passed in no longer valid */
1195
1196 return rc;
1197}
1198
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001199int
1200CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001202 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1203 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204{
1205 int rc = -EACCES;
1206 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001207 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001208 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001209 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Steve Frenchff7feac2005-11-15 16:45:16 -08001211 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1212
Steve French8cc64c62005-10-03 13:49:43 -07001213 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1214 wct = 14;
1215 else
1216 wct = 12;
1217 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if (rc)
1219 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 /* tcon and ses pointer are checked in smb_init */
1221 if (tcon->ses->server == NULL)
1222 return -ECONNABORTED;
1223
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001224 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 pSMB->Fid = netfid;
1226 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001227 if(wct == 14)
1228 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1229 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1230 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 pSMB->Reserved = 0xFFFFFFFF;
1232 pSMB->WriteMode = 0;
1233 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 pSMB->DataOffset =
1236 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1237
Steve French3e844692005-10-03 13:37:24 -07001238 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1239 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001240 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001241 if(wct == 14)
1242 pSMB->hdr.smb_buf_length += count+1;
1243 else /* wct == 12 */
1244 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1245 if(wct == 14)
1246 pSMB->ByteCount = cpu_to_le16(count + 1);
1247 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1248 struct smb_com_writex_req * pSMBW =
1249 (struct smb_com_writex_req *)pSMB;
1250 pSMBW->ByteCount = cpu_to_le16(count + 5);
1251 }
Steve French3e844692005-10-03 13:37:24 -07001252 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001253 if(wct == 14)
1254 iov[0].iov_len = smb_hdr_len + 4;
1255 else /* wct == 12 pad bigger by four bytes */
1256 iov[0].iov_len = smb_hdr_len + 8;
1257
Steve French3e844692005-10-03 13:37:24 -07001258
Steve Frenchec637e32005-12-12 20:53:18 -08001259 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001260 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001261 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001263 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001265 } else if(resp_buf_type == 0) {
1266 /* presumably this can not happen, but best to be safe */
1267 rc = -EIO;
1268 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001269 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001270 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001271 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1272 *nbytes = (*nbytes) << 16;
1273 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
1276 cifs_small_buf_release(pSMB);
Steve Frenchec637e32005-12-12 20:53:18 -08001277 if(resp_buf_type == CIFS_SMALL_BUFFER)
1278 cifs_small_buf_release(iov[0].iov_base);
1279 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1280 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
1282 /* Note: On -EAGAIN error only caller can retry on handle based calls
1283 since file handle passed in no longer valid */
1284
1285 return rc;
1286}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001287
1288
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289int
1290CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1291 const __u16 smb_file_id, const __u64 len,
1292 const __u64 offset, const __u32 numUnlock,
1293 const __u32 numLock, const __u8 lockType, const int waitFlag)
1294{
1295 int rc = 0;
1296 LOCK_REQ *pSMB = NULL;
1297 LOCK_RSP *pSMBr = NULL;
1298 int bytes_returned;
1299 int timeout = 0;
1300 __u16 count;
1301
1302 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001303 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 if (rc)
1306 return rc;
1307
Steve French46810cb2005-04-28 22:41:09 -07001308 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1309
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1311 timeout = -1; /* no response expected */
1312 pSMB->Timeout = 0;
1313 } else if (waitFlag == TRUE) {
1314 timeout = 3; /* blocking operation, no timeout */
1315 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1316 } else {
1317 pSMB->Timeout = 0;
1318 }
1319
1320 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1321 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1322 pSMB->LockType = lockType;
1323 pSMB->AndXCommand = 0xFF; /* none */
1324 pSMB->Fid = smb_file_id; /* netfid stays le */
1325
1326 if((numLock != 0) || (numUnlock != 0)) {
1327 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1328 /* BB where to store pid high? */
1329 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1330 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1331 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1332 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1333 count = sizeof(LOCKING_ANDX_RANGE);
1334 } else {
1335 /* oplock break */
1336 count = 0;
1337 }
1338 pSMB->hdr.smb_buf_length += count;
1339 pSMB->ByteCount = cpu_to_le16(count);
1340
1341 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1342 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha45443472005-08-24 13:59:35 -07001343 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 if (rc) {
1345 cFYI(1, ("Send error in Lock = %d", rc));
1346 }
Steve French46810cb2005-04-28 22:41:09 -07001347 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
1349 /* Note: On -EAGAIN error only caller can retry on handle based calls
1350 since file handle passed in no longer valid */
1351 return rc;
1352}
1353
1354int
1355CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1356{
1357 int rc = 0;
1358 CLOSE_REQ *pSMB = NULL;
1359 CLOSE_RSP *pSMBr = NULL;
1360 int bytes_returned;
1361 cFYI(1, ("In CIFSSMBClose"));
1362
1363/* do not retry on dead session on close */
1364 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1365 if(rc == -EAGAIN)
1366 return 0;
1367 if (rc)
1368 return rc;
1369
1370 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1371
1372 pSMB->FileID = (__u16) smb_file_id;
1373 pSMB->LastWriteTime = 0;
1374 pSMB->ByteCount = 0;
1375 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1376 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001377 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 if (rc) {
1379 if(rc!=-EINTR) {
1380 /* EINTR is expected when user ctl-c to kill app */
1381 cERROR(1, ("Send error in Close = %d", rc));
1382 }
1383 }
1384
1385 cifs_small_buf_release(pSMB);
1386
1387 /* Since session is dead, file will be closed on server already */
1388 if(rc == -EAGAIN)
1389 rc = 0;
1390
1391 return rc;
1392}
1393
1394int
1395CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1396 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001397 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398{
1399 int rc = 0;
1400 RENAME_REQ *pSMB = NULL;
1401 RENAME_RSP *pSMBr = NULL;
1402 int bytes_returned;
1403 int name_len, name_len2;
1404 __u16 count;
1405
1406 cFYI(1, ("In CIFSSMBRename"));
1407renameRetry:
1408 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1409 (void **) &pSMBr);
1410 if (rc)
1411 return rc;
1412
1413 pSMB->BufferFormat = 0x04;
1414 pSMB->SearchAttributes =
1415 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1416 ATTR_DIRECTORY);
1417
1418 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1419 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001420 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001421 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 name_len++; /* trailing null */
1423 name_len *= 2;
1424 pSMB->OldFileName[name_len] = 0x04; /* pad */
1425 /* protocol requires ASCII signature byte on Unicode string */
1426 pSMB->OldFileName[name_len + 1] = 0x00;
1427 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001428 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001429 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1431 name_len2 *= 2; /* convert to bytes */
1432 } else { /* BB improve the check for buffer overruns BB */
1433 name_len = strnlen(fromName, PATH_MAX);
1434 name_len++; /* trailing null */
1435 strncpy(pSMB->OldFileName, fromName, name_len);
1436 name_len2 = strnlen(toName, PATH_MAX);
1437 name_len2++; /* trailing null */
1438 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1439 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1440 name_len2++; /* trailing null */
1441 name_len2++; /* signature byte */
1442 }
1443
1444 count = 1 /* 1st signature byte */ + name_len + name_len2;
1445 pSMB->hdr.smb_buf_length += count;
1446 pSMB->ByteCount = cpu_to_le16(count);
1447
1448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001450 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 if (rc) {
1452 cFYI(1, ("Send error in rename = %d", rc));
1453 }
1454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 cifs_buf_release(pSMB);
1456
1457 if (rc == -EAGAIN)
1458 goto renameRetry;
1459
1460 return rc;
1461}
1462
1463int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001464 int netfid, char * target_name,
1465 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466{
1467 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1468 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1469 struct set_file_rename * rename_info;
1470 char *data_offset;
1471 char dummy_string[30];
1472 int rc = 0;
1473 int bytes_returned = 0;
1474 int len_of_str;
1475 __u16 params, param_offset, offset, count, byte_count;
1476
1477 cFYI(1, ("Rename to File by handle"));
1478 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1479 (void **) &pSMBr);
1480 if (rc)
1481 return rc;
1482
1483 params = 6;
1484 pSMB->MaxSetupCount = 0;
1485 pSMB->Reserved = 0;
1486 pSMB->Flags = 0;
1487 pSMB->Timeout = 0;
1488 pSMB->Reserved2 = 0;
1489 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1490 offset = param_offset + params;
1491
1492 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1493 rename_info = (struct set_file_rename *) data_offset;
1494 pSMB->MaxParameterCount = cpu_to_le16(2);
1495 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1496 pSMB->SetupCount = 1;
1497 pSMB->Reserved3 = 0;
1498 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1499 byte_count = 3 /* pad */ + params;
1500 pSMB->ParameterCount = cpu_to_le16(params);
1501 pSMB->TotalParameterCount = pSMB->ParameterCount;
1502 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1503 pSMB->DataOffset = cpu_to_le16(offset);
1504 /* construct random name ".cifs_tmp<inodenum><mid>" */
1505 rename_info->overwrite = cpu_to_le32(1);
1506 rename_info->root_fid = 0;
1507 /* unicode only call */
1508 if(target_name == NULL) {
1509 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001510 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001511 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001513 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001514 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 }
1516 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1517 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1518 byte_count += count;
1519 pSMB->DataCount = cpu_to_le16(count);
1520 pSMB->TotalDataCount = pSMB->DataCount;
1521 pSMB->Fid = netfid;
1522 pSMB->InformationLevel =
1523 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1524 pSMB->Reserved4 = 0;
1525 pSMB->hdr.smb_buf_length += byte_count;
1526 pSMB->ByteCount = cpu_to_le16(byte_count);
1527 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1528 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001529 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 if (rc) {
1531 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1532 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001533
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 cifs_buf_release(pSMB);
1535
1536 /* Note: On -EAGAIN error only caller can retry on handle based calls
1537 since file handle passed in no longer valid */
1538
1539 return rc;
1540}
1541
1542int
1543CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1544 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001545 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546{
1547 int rc = 0;
1548 COPY_REQ *pSMB = NULL;
1549 COPY_RSP *pSMBr = NULL;
1550 int bytes_returned;
1551 int name_len, name_len2;
1552 __u16 count;
1553
1554 cFYI(1, ("In CIFSSMBCopy"));
1555copyRetry:
1556 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1557 (void **) &pSMBr);
1558 if (rc)
1559 return rc;
1560
1561 pSMB->BufferFormat = 0x04;
1562 pSMB->Tid2 = target_tid;
1563
1564 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1565
1566 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001567 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001568 fromName, PATH_MAX, nls_codepage,
1569 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 name_len++; /* trailing null */
1571 name_len *= 2;
1572 pSMB->OldFileName[name_len] = 0x04; /* pad */
1573 /* protocol requires ASCII signature byte on Unicode string */
1574 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001575 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001576 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1578 name_len2 *= 2; /* convert to bytes */
1579 } else { /* BB improve the check for buffer overruns BB */
1580 name_len = strnlen(fromName, PATH_MAX);
1581 name_len++; /* trailing null */
1582 strncpy(pSMB->OldFileName, fromName, name_len);
1583 name_len2 = strnlen(toName, PATH_MAX);
1584 name_len2++; /* trailing null */
1585 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1586 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1587 name_len2++; /* trailing null */
1588 name_len2++; /* signature byte */
1589 }
1590
1591 count = 1 /* 1st signature byte */ + name_len + name_len2;
1592 pSMB->hdr.smb_buf_length += count;
1593 pSMB->ByteCount = cpu_to_le16(count);
1594
1595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1597 if (rc) {
1598 cFYI(1, ("Send error in copy = %d with %d files copied",
1599 rc, le16_to_cpu(pSMBr->CopyCount)));
1600 }
1601 if (pSMB)
1602 cifs_buf_release(pSMB);
1603
1604 if (rc == -EAGAIN)
1605 goto copyRetry;
1606
1607 return rc;
1608}
1609
1610int
1611CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1612 const char *fromName, const char *toName,
1613 const struct nls_table *nls_codepage)
1614{
1615 TRANSACTION2_SPI_REQ *pSMB = NULL;
1616 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1617 char *data_offset;
1618 int name_len;
1619 int name_len_target;
1620 int rc = 0;
1621 int bytes_returned = 0;
1622 __u16 params, param_offset, offset, byte_count;
1623
1624 cFYI(1, ("In Symlink Unix style"));
1625createSymLinkRetry:
1626 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1627 (void **) &pSMBr);
1628 if (rc)
1629 return rc;
1630
1631 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1632 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001633 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 /* find define for this maxpathcomponent */
1635 , nls_codepage);
1636 name_len++; /* trailing null */
1637 name_len *= 2;
1638
1639 } else { /* BB improve the check for buffer overruns BB */
1640 name_len = strnlen(fromName, PATH_MAX);
1641 name_len++; /* trailing null */
1642 strncpy(pSMB->FileName, fromName, name_len);
1643 }
1644 params = 6 + name_len;
1645 pSMB->MaxSetupCount = 0;
1646 pSMB->Reserved = 0;
1647 pSMB->Flags = 0;
1648 pSMB->Timeout = 0;
1649 pSMB->Reserved2 = 0;
1650 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1651 InformationLevel) - 4;
1652 offset = param_offset + params;
1653
1654 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1655 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1656 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001657 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 /* find define for this maxpathcomponent */
1659 , nls_codepage);
1660 name_len_target++; /* trailing null */
1661 name_len_target *= 2;
1662 } else { /* BB improve the check for buffer overruns BB */
1663 name_len_target = strnlen(toName, PATH_MAX);
1664 name_len_target++; /* trailing null */
1665 strncpy(data_offset, toName, name_len_target);
1666 }
1667
1668 pSMB->MaxParameterCount = cpu_to_le16(2);
1669 /* BB find exact max on data count below from sess */
1670 pSMB->MaxDataCount = cpu_to_le16(1000);
1671 pSMB->SetupCount = 1;
1672 pSMB->Reserved3 = 0;
1673 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1674 byte_count = 3 /* pad */ + params + name_len_target;
1675 pSMB->DataCount = cpu_to_le16(name_len_target);
1676 pSMB->ParameterCount = cpu_to_le16(params);
1677 pSMB->TotalDataCount = pSMB->DataCount;
1678 pSMB->TotalParameterCount = pSMB->ParameterCount;
1679 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1680 pSMB->DataOffset = cpu_to_le16(offset);
1681 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1682 pSMB->Reserved4 = 0;
1683 pSMB->hdr.smb_buf_length += byte_count;
1684 pSMB->ByteCount = cpu_to_le16(byte_count);
1685 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1686 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001687 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 if (rc) {
1689 cFYI(1,
1690 ("Send error in SetPathInfo (create symlink) = %d",
1691 rc));
1692 }
1693
1694 if (pSMB)
1695 cifs_buf_release(pSMB);
1696
1697 if (rc == -EAGAIN)
1698 goto createSymLinkRetry;
1699
1700 return rc;
1701}
1702
1703int
1704CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1705 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001706 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707{
1708 TRANSACTION2_SPI_REQ *pSMB = NULL;
1709 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1710 char *data_offset;
1711 int name_len;
1712 int name_len_target;
1713 int rc = 0;
1714 int bytes_returned = 0;
1715 __u16 params, param_offset, offset, byte_count;
1716
1717 cFYI(1, ("In Create Hard link Unix style"));
1718createHardLinkRetry:
1719 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1720 (void **) &pSMBr);
1721 if (rc)
1722 return rc;
1723
1724 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001725 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001726 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 name_len++; /* trailing null */
1728 name_len *= 2;
1729
1730 } else { /* BB improve the check for buffer overruns BB */
1731 name_len = strnlen(toName, PATH_MAX);
1732 name_len++; /* trailing null */
1733 strncpy(pSMB->FileName, toName, name_len);
1734 }
1735 params = 6 + name_len;
1736 pSMB->MaxSetupCount = 0;
1737 pSMB->Reserved = 0;
1738 pSMB->Flags = 0;
1739 pSMB->Timeout = 0;
1740 pSMB->Reserved2 = 0;
1741 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1742 InformationLevel) - 4;
1743 offset = param_offset + params;
1744
1745 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1746 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1747 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001748 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001749 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 name_len_target++; /* trailing null */
1751 name_len_target *= 2;
1752 } else { /* BB improve the check for buffer overruns BB */
1753 name_len_target = strnlen(fromName, PATH_MAX);
1754 name_len_target++; /* trailing null */
1755 strncpy(data_offset, fromName, name_len_target);
1756 }
1757
1758 pSMB->MaxParameterCount = cpu_to_le16(2);
1759 /* BB find exact max on data count below from sess*/
1760 pSMB->MaxDataCount = cpu_to_le16(1000);
1761 pSMB->SetupCount = 1;
1762 pSMB->Reserved3 = 0;
1763 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1764 byte_count = 3 /* pad */ + params + name_len_target;
1765 pSMB->ParameterCount = cpu_to_le16(params);
1766 pSMB->TotalParameterCount = pSMB->ParameterCount;
1767 pSMB->DataCount = cpu_to_le16(name_len_target);
1768 pSMB->TotalDataCount = pSMB->DataCount;
1769 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1770 pSMB->DataOffset = cpu_to_le16(offset);
1771 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1772 pSMB->Reserved4 = 0;
1773 pSMB->hdr.smb_buf_length += byte_count;
1774 pSMB->ByteCount = cpu_to_le16(byte_count);
1775 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1776 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001777 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if (rc) {
1779 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1780 }
1781
1782 cifs_buf_release(pSMB);
1783 if (rc == -EAGAIN)
1784 goto createHardLinkRetry;
1785
1786 return rc;
1787}
1788
1789int
1790CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1791 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001792 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793{
1794 int rc = 0;
1795 NT_RENAME_REQ *pSMB = NULL;
1796 RENAME_RSP *pSMBr = NULL;
1797 int bytes_returned;
1798 int name_len, name_len2;
1799 __u16 count;
1800
1801 cFYI(1, ("In CIFSCreateHardLink"));
1802winCreateHardLinkRetry:
1803
1804 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1805 (void **) &pSMBr);
1806 if (rc)
1807 return rc;
1808
1809 pSMB->SearchAttributes =
1810 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1811 ATTR_DIRECTORY);
1812 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1813 pSMB->ClusterCount = 0;
1814
1815 pSMB->BufferFormat = 0x04;
1816
1817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1818 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001819 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001820 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 name_len++; /* trailing null */
1822 name_len *= 2;
1823 pSMB->OldFileName[name_len] = 0; /* pad */
1824 pSMB->OldFileName[name_len + 1] = 0x04;
1825 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001826 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001827 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1829 name_len2 *= 2; /* convert to bytes */
1830 } else { /* BB improve the check for buffer overruns BB */
1831 name_len = strnlen(fromName, PATH_MAX);
1832 name_len++; /* trailing null */
1833 strncpy(pSMB->OldFileName, fromName, name_len);
1834 name_len2 = strnlen(toName, PATH_MAX);
1835 name_len2++; /* trailing null */
1836 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1837 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1838 name_len2++; /* trailing null */
1839 name_len2++; /* signature byte */
1840 }
1841
1842 count = 1 /* string type byte */ + name_len + name_len2;
1843 pSMB->hdr.smb_buf_length += count;
1844 pSMB->ByteCount = cpu_to_le16(count);
1845
1846 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1847 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001848 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 if (rc) {
1850 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1851 }
1852 cifs_buf_release(pSMB);
1853 if (rc == -EAGAIN)
1854 goto winCreateHardLinkRetry;
1855
1856 return rc;
1857}
1858
1859int
1860CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1861 const unsigned char *searchName,
1862 char *symlinkinfo, const int buflen,
1863 const struct nls_table *nls_codepage)
1864{
1865/* SMB_QUERY_FILE_UNIX_LINK */
1866 TRANSACTION2_QPI_REQ *pSMB = NULL;
1867 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1868 int rc = 0;
1869 int bytes_returned;
1870 int name_len;
1871 __u16 params, byte_count;
1872
1873 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1874
1875querySymLinkRetry:
1876 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1877 (void **) &pSMBr);
1878 if (rc)
1879 return rc;
1880
1881 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1882 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001883 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 /* find define for this maxpathcomponent */
1885 , nls_codepage);
1886 name_len++; /* trailing null */
1887 name_len *= 2;
1888 } else { /* BB improve the check for buffer overruns BB */
1889 name_len = strnlen(searchName, PATH_MAX);
1890 name_len++; /* trailing null */
1891 strncpy(pSMB->FileName, searchName, name_len);
1892 }
1893
1894 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1895 pSMB->TotalDataCount = 0;
1896 pSMB->MaxParameterCount = cpu_to_le16(2);
1897 /* BB find exact max data count below from sess structure BB */
1898 pSMB->MaxDataCount = cpu_to_le16(4000);
1899 pSMB->MaxSetupCount = 0;
1900 pSMB->Reserved = 0;
1901 pSMB->Flags = 0;
1902 pSMB->Timeout = 0;
1903 pSMB->Reserved2 = 0;
1904 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1905 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1906 pSMB->DataCount = 0;
1907 pSMB->DataOffset = 0;
1908 pSMB->SetupCount = 1;
1909 pSMB->Reserved3 = 0;
1910 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1911 byte_count = params + 1 /* pad */ ;
1912 pSMB->TotalParameterCount = cpu_to_le16(params);
1913 pSMB->ParameterCount = pSMB->TotalParameterCount;
1914 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1915 pSMB->Reserved4 = 0;
1916 pSMB->hdr.smb_buf_length += byte_count;
1917 pSMB->ByteCount = cpu_to_le16(byte_count);
1918
1919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1921 if (rc) {
1922 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1923 } else {
1924 /* decode response */
1925
1926 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1927 if (rc || (pSMBr->ByteCount < 2))
1928 /* BB also check enough total bytes returned */
1929 rc = -EIO; /* bad smb */
1930 else {
1931 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1932 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1933
1934 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1935 name_len = UniStrnlen((wchar_t *) ((char *)
1936 &pSMBr->hdr.Protocol +data_offset),
1937 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001938 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08001940 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 data_offset),
1942 name_len, nls_codepage);
1943 } else {
1944 strncpy(symlinkinfo,
1945 (char *) &pSMBr->hdr.Protocol +
1946 data_offset,
1947 min_t(const int, buflen, count));
1948 }
1949 symlinkinfo[buflen] = 0;
1950 /* just in case so calling code does not go off the end of buffer */
1951 }
1952 }
1953 cifs_buf_release(pSMB);
1954 if (rc == -EAGAIN)
1955 goto querySymLinkRetry;
1956 return rc;
1957}
1958
Steve French0a4b92c2006-01-12 15:44:21 -08001959/* Initialize NT TRANSACT SMB into small smb request buffer.
1960 This assumes that all NT TRANSACTS that we init here have
1961 total parm and data under about 400 bytes (to fit in small cifs
1962 buffer size), which is the case so far, it easily fits. NB:
1963 Setup words themselves and ByteCount
1964 MaxSetupCount (size of returned setup area) and
1965 MaxParameterCount (returned parms size) must be set by caller */
1966static int
1967smb_init_ntransact(const __u16 sub_command, const int setup_count,
1968 const int parm_len, struct cifsTconInfo *tcon,
1969 void ** ret_buf)
1970{
1971 int rc;
1972 __u32 temp_offset;
1973 struct smb_com_ntransact_req * pSMB;
1974
1975 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1976 (void **)&pSMB);
1977 if (rc)
1978 return rc;
1979 *ret_buf = (void *)pSMB;
1980 pSMB->Reserved = 0;
1981 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1982 pSMB->TotalDataCount = 0;
1983 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1984 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1985 pSMB->ParameterCount = pSMB->TotalParameterCount;
1986 pSMB->DataCount = pSMB->TotalDataCount;
1987 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1988 (setup_count * 2) - 4 /* for rfc1001 length itself */;
1989 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1990 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1991 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1992 pSMB->SubCommand = cpu_to_le16(sub_command);
1993 return 0;
1994}
1995
1996static int
1997validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1998 int * pdatalen, int * pparmlen)
1999{
2000 char * end_of_smb;
2001 __u32 data_count, data_offset, parm_count, parm_offset;
2002 struct smb_com_ntransact_rsp * pSMBr;
2003
2004 if(buf == NULL)
2005 return -EINVAL;
2006
2007 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2008
2009 /* ByteCount was converted from little endian in SendReceive */
2010 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2011 (char *)&pSMBr->ByteCount;
2012
2013
2014 data_offset = le32_to_cpu(pSMBr->DataOffset);
2015 data_count = le32_to_cpu(pSMBr->DataCount);
2016 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2017 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2018
2019 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2020 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2021
2022 /* should we also check that parm and data areas do not overlap? */
2023 if(*ppparm > end_of_smb) {
2024 cFYI(1,("parms start after end of smb"));
2025 return -EINVAL;
2026 } else if(parm_count + *ppparm > end_of_smb) {
2027 cFYI(1,("parm end after end of smb"));
2028 return -EINVAL;
2029 } else if(*ppdata > end_of_smb) {
2030 cFYI(1,("data starts after end of smb"));
2031 return -EINVAL;
2032 } else if(data_count + *ppdata > end_of_smb) {
2033 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2034 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2035 return -EINVAL;
2036 } else if(parm_count + data_count > pSMBr->ByteCount) {
2037 cFYI(1,("parm count and data count larger than SMB"));
2038 return -EINVAL;
2039 }
2040 return 0;
2041}
2042
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043int
2044CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2045 const unsigned char *searchName,
2046 char *symlinkinfo, const int buflen,__u16 fid,
2047 const struct nls_table *nls_codepage)
2048{
2049 int rc = 0;
2050 int bytes_returned;
2051 int name_len;
2052 struct smb_com_transaction_ioctl_req * pSMB;
2053 struct smb_com_transaction_ioctl_rsp * pSMBr;
2054
2055 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2056 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2057 (void **) &pSMBr);
2058 if (rc)
2059 return rc;
2060
2061 pSMB->TotalParameterCount = 0 ;
2062 pSMB->TotalDataCount = 0;
2063 pSMB->MaxParameterCount = cpu_to_le32(2);
2064 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002065 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2066 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 pSMB->MaxSetupCount = 4;
2068 pSMB->Reserved = 0;
2069 pSMB->ParameterOffset = 0;
2070 pSMB->DataCount = 0;
2071 pSMB->DataOffset = 0;
2072 pSMB->SetupCount = 4;
2073 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2074 pSMB->ParameterCount = pSMB->TotalParameterCount;
2075 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2076 pSMB->IsFsctl = 1; /* FSCTL */
2077 pSMB->IsRootFlag = 0;
2078 pSMB->Fid = fid; /* file handle always le */
2079 pSMB->ByteCount = 0;
2080
2081 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2082 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2083 if (rc) {
2084 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2085 } else { /* decode response */
2086 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2087 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2088 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2089 /* BB also check enough total bytes returned */
2090 rc = -EIO; /* bad smb */
2091 else {
2092 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002093 char * end_of_smb = 2 /* sizeof byte count */ +
2094 pSMBr->ByteCount +
2095 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096
2097 struct reparse_data * reparse_buf = (struct reparse_data *)
2098 ((char *)&pSMBr->hdr.Protocol + data_offset);
2099 if((char*)reparse_buf >= end_of_smb) {
2100 rc = -EIO;
2101 goto qreparse_out;
2102 }
2103 if((reparse_buf->LinkNamesBuf +
2104 reparse_buf->TargetNameOffset +
2105 reparse_buf->TargetNameLen) >
2106 end_of_smb) {
2107 cFYI(1,("reparse buf extended beyond SMB"));
2108 rc = -EIO;
2109 goto qreparse_out;
2110 }
2111
2112 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2113 name_len = UniStrnlen((wchar_t *)
2114 (reparse_buf->LinkNamesBuf +
2115 reparse_buf->TargetNameOffset),
2116 min(buflen/2, reparse_buf->TargetNameLen / 2));
2117 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002118 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 reparse_buf->TargetNameOffset),
2120 name_len, nls_codepage);
2121 } else { /* ASCII names */
2122 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2123 reparse_buf->TargetNameOffset,
2124 min_t(const int, buflen, reparse_buf->TargetNameLen));
2125 }
2126 } else {
2127 rc = -EIO;
2128 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2129 }
2130 symlinkinfo[buflen] = 0; /* just in case so the caller
2131 does not go off the end of the buffer */
2132 cFYI(1,("readlink result - %s ",symlinkinfo));
2133 }
2134 }
2135qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002136 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
2138 /* Note: On -EAGAIN error only caller can retry on handle based calls
2139 since file handle passed in no longer valid */
2140
2141 return rc;
2142}
2143
2144#ifdef CONFIG_CIFS_POSIX
2145
2146/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2147static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2148{
2149 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002150 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2151 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2152 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2154
2155 return;
2156}
2157
2158/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002159static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2160 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161{
2162 int size = 0;
2163 int i;
2164 __u16 count;
2165 struct cifs_posix_ace * pACE;
2166 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2167 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2168
2169 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2170 return -EOPNOTSUPP;
2171
2172 if(acl_type & ACL_TYPE_ACCESS) {
2173 count = le16_to_cpu(cifs_acl->access_entry_count);
2174 pACE = &cifs_acl->ace_array[0];
2175 size = sizeof(struct cifs_posix_acl);
2176 size += sizeof(struct cifs_posix_ace) * count;
2177 /* check if we would go beyond end of SMB */
2178 if(size_of_data_area < size) {
2179 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2180 return -EINVAL;
2181 }
2182 } else if(acl_type & ACL_TYPE_DEFAULT) {
2183 count = le16_to_cpu(cifs_acl->access_entry_count);
2184 size = sizeof(struct cifs_posix_acl);
2185 size += sizeof(struct cifs_posix_ace) * count;
2186/* skip past access ACEs to get to default ACEs */
2187 pACE = &cifs_acl->ace_array[count];
2188 count = le16_to_cpu(cifs_acl->default_entry_count);
2189 size += sizeof(struct cifs_posix_ace) * count;
2190 /* check if we would go beyond end of SMB */
2191 if(size_of_data_area < size)
2192 return -EINVAL;
2193 } else {
2194 /* illegal type */
2195 return -EINVAL;
2196 }
2197
2198 size = posix_acl_xattr_size(count);
2199 if((buflen == 0) || (local_acl == NULL)) {
2200 /* used to query ACL EA size */
2201 } else if(size > buflen) {
2202 return -ERANGE;
2203 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002204 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 for(i = 0;i < count ;i++) {
2206 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2207 pACE ++;
2208 }
2209 }
2210 return size;
2211}
2212
2213static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2214 const posix_acl_xattr_entry * local_ace)
2215{
2216 __u16 rc = 0; /* 0 = ACL converted ok */
2217
Steve Frenchff7feac2005-11-15 16:45:16 -08002218 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2219 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002221 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 /* Probably no need to le convert -1 on any arch but can not hurt */
2223 cifs_ace->cifs_uid = cpu_to_le64(-1);
2224 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002225 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2227 return rc;
2228}
2229
2230/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2231static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2232 const int acl_type)
2233{
2234 __u16 rc = 0;
2235 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2236 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2237 int count;
2238 int i;
2239
2240 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2241 return 0;
2242
2243 count = posix_acl_xattr_count((size_t)buflen);
2244 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002245 count, buflen, le32_to_cpu(local_acl->a_version)));
2246 if(le32_to_cpu(local_acl->a_version) != 2) {
2247 cFYI(1,("unknown POSIX ACL version %d",
2248 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 return 0;
2250 }
2251 cifs_acl->version = cpu_to_le16(1);
2252 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002253 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002255 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 else {
2257 cFYI(1,("unknown ACL type %d",acl_type));
2258 return 0;
2259 }
2260 for(i=0;i<count;i++) {
2261 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2262 &local_acl->a_entries[i]);
2263 if(rc != 0) {
2264 /* ACE not converted */
2265 break;
2266 }
2267 }
2268 if(rc == 0) {
2269 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2270 rc += sizeof(struct cifs_posix_acl);
2271 /* BB add check to make sure ACL does not overflow SMB */
2272 }
2273 return rc;
2274}
2275
2276int
2277CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2278 const unsigned char *searchName,
2279 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002280 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281{
2282/* SMB_QUERY_POSIX_ACL */
2283 TRANSACTION2_QPI_REQ *pSMB = NULL;
2284 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2285 int rc = 0;
2286 int bytes_returned;
2287 int name_len;
2288 __u16 params, byte_count;
2289
2290 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2291
2292queryAclRetry:
2293 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2294 (void **) &pSMBr);
2295 if (rc)
2296 return rc;
2297
2298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2299 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002300 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002301 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 name_len++; /* trailing null */
2303 name_len *= 2;
2304 pSMB->FileName[name_len] = 0;
2305 pSMB->FileName[name_len+1] = 0;
2306 } else { /* BB improve the check for buffer overruns BB */
2307 name_len = strnlen(searchName, PATH_MAX);
2308 name_len++; /* trailing null */
2309 strncpy(pSMB->FileName, searchName, name_len);
2310 }
2311
2312 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2313 pSMB->TotalDataCount = 0;
2314 pSMB->MaxParameterCount = cpu_to_le16(2);
2315 /* BB find exact max data count below from sess structure BB */
2316 pSMB->MaxDataCount = cpu_to_le16(4000);
2317 pSMB->MaxSetupCount = 0;
2318 pSMB->Reserved = 0;
2319 pSMB->Flags = 0;
2320 pSMB->Timeout = 0;
2321 pSMB->Reserved2 = 0;
2322 pSMB->ParameterOffset = cpu_to_le16(
2323 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2324 pSMB->DataCount = 0;
2325 pSMB->DataOffset = 0;
2326 pSMB->SetupCount = 1;
2327 pSMB->Reserved3 = 0;
2328 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2329 byte_count = params + 1 /* pad */ ;
2330 pSMB->TotalParameterCount = cpu_to_le16(params);
2331 pSMB->ParameterCount = pSMB->TotalParameterCount;
2332 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2333 pSMB->Reserved4 = 0;
2334 pSMB->hdr.smb_buf_length += byte_count;
2335 pSMB->ByteCount = cpu_to_le16(byte_count);
2336
2337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2338 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002339 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 if (rc) {
2341 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2342 } else {
2343 /* decode response */
2344
2345 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2346 if (rc || (pSMBr->ByteCount < 2))
2347 /* BB also check enough total bytes returned */
2348 rc = -EIO; /* bad smb */
2349 else {
2350 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2351 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2352 rc = cifs_copy_posix_acl(acl_inf,
2353 (char *)&pSMBr->hdr.Protocol+data_offset,
2354 buflen,acl_type,count);
2355 }
2356 }
2357 cifs_buf_release(pSMB);
2358 if (rc == -EAGAIN)
2359 goto queryAclRetry;
2360 return rc;
2361}
2362
2363int
2364CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2365 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002366 const char *local_acl, const int buflen,
2367 const int acl_type,
2368 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369{
2370 struct smb_com_transaction2_spi_req *pSMB = NULL;
2371 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2372 char *parm_data;
2373 int name_len;
2374 int rc = 0;
2375 int bytes_returned = 0;
2376 __u16 params, byte_count, data_count, param_offset, offset;
2377
2378 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2379setAclRetry:
2380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2381 (void **) &pSMBr);
2382 if (rc)
2383 return rc;
2384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2385 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002386 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002387 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 name_len++; /* trailing null */
2389 name_len *= 2;
2390 } else { /* BB improve the check for buffer overruns BB */
2391 name_len = strnlen(fileName, PATH_MAX);
2392 name_len++; /* trailing null */
2393 strncpy(pSMB->FileName, fileName, name_len);
2394 }
2395 params = 6 + name_len;
2396 pSMB->MaxParameterCount = cpu_to_le16(2);
2397 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2398 pSMB->MaxSetupCount = 0;
2399 pSMB->Reserved = 0;
2400 pSMB->Flags = 0;
2401 pSMB->Timeout = 0;
2402 pSMB->Reserved2 = 0;
2403 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2404 InformationLevel) - 4;
2405 offset = param_offset + params;
2406 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2407 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2408
2409 /* convert to on the wire format for POSIX ACL */
2410 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2411
2412 if(data_count == 0) {
2413 rc = -EOPNOTSUPP;
2414 goto setACLerrorExit;
2415 }
2416 pSMB->DataOffset = cpu_to_le16(offset);
2417 pSMB->SetupCount = 1;
2418 pSMB->Reserved3 = 0;
2419 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2420 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2421 byte_count = 3 /* pad */ + params + data_count;
2422 pSMB->DataCount = cpu_to_le16(data_count);
2423 pSMB->TotalDataCount = pSMB->DataCount;
2424 pSMB->ParameterCount = cpu_to_le16(params);
2425 pSMB->TotalParameterCount = pSMB->ParameterCount;
2426 pSMB->Reserved4 = 0;
2427 pSMB->hdr.smb_buf_length += byte_count;
2428 pSMB->ByteCount = cpu_to_le16(byte_count);
2429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2431 if (rc) {
2432 cFYI(1, ("Set POSIX ACL returned %d", rc));
2433 }
2434
2435setACLerrorExit:
2436 cifs_buf_release(pSMB);
2437 if (rc == -EAGAIN)
2438 goto setAclRetry;
2439 return rc;
2440}
2441
Steve Frenchf654bac2005-04-28 22:41:04 -07002442/* BB fix tabs in this function FIXME BB */
2443int
2444CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2445 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2446{
2447 int rc = 0;
2448 struct smb_t2_qfi_req *pSMB = NULL;
2449 struct smb_t2_qfi_rsp *pSMBr = NULL;
2450 int bytes_returned;
2451 __u16 params, byte_count;
2452
2453 cFYI(1,("In GetExtAttr"));
2454 if(tcon == NULL)
2455 return -ENODEV;
2456
2457GetExtAttrRetry:
2458 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2459 (void **) &pSMBr);
2460 if (rc)
2461 return rc;
2462
Steve Frenchc67593a2005-04-28 22:41:04 -07002463 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002464 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002465 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002466 /* BB find exact max data count below from sess structure BB */
2467 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2468 pSMB->t2.MaxSetupCount = 0;
2469 pSMB->t2.Reserved = 0;
2470 pSMB->t2.Flags = 0;
2471 pSMB->t2.Timeout = 0;
2472 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002473 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2474 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002475 pSMB->t2.DataCount = 0;
2476 pSMB->t2.DataOffset = 0;
2477 pSMB->t2.SetupCount = 1;
2478 pSMB->t2.Reserved3 = 0;
2479 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002480 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002481 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2482 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2483 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002484 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002485 pSMB->Fid = netfid;
2486 pSMB->hdr.smb_buf_length += byte_count;
2487 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2488
2489 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2490 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2491 if (rc) {
2492 cFYI(1, ("error %d in GetExtAttr", rc));
2493 } else {
2494 /* decode response */
2495 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2496 if (rc || (pSMBr->ByteCount < 2))
2497 /* BB also check enough total bytes returned */
2498 /* If rc should we check for EOPNOSUPP and
2499 disable the srvino flag? or in caller? */
2500 rc = -EIO; /* bad smb */
2501 else {
2502 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2503 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2504 struct file_chattr_info * pfinfo;
2505 /* BB Do we need a cast or hash here ? */
2506 if(count != 16) {
2507 cFYI(1, ("Illegal size ret in GetExtAttr"));
2508 rc = -EIO;
2509 goto GetExtAttrOut;
2510 }
2511 pfinfo = (struct file_chattr_info *)
2512 (data_offset + (char *) &pSMBr->hdr.Protocol);
2513 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2514 *pMask = le64_to_cpu(pfinfo->mask);
2515 }
2516 }
2517GetExtAttrOut:
2518 cifs_buf_release(pSMB);
2519 if (rc == -EAGAIN)
2520 goto GetExtAttrRetry;
2521 return rc;
2522}
2523
2524
2525#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
Steve Frencheeac8042006-01-13 21:34:58 -08002527
2528/* security id for everyone */
2529const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2530/* group users */
2531const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2532
Steve French0a4b92c2006-01-12 15:44:21 -08002533/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002534static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002535{
Steve French0a4b92c2006-01-12 15:44:21 -08002536 return 0;
2537}
2538
2539/* Get Security Descriptor (by handle) from remote server for a file or dir */
2540int
2541CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2542 /* BB fix up return info */ char *acl_inf, const int buflen,
2543 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2544{
2545 int rc = 0;
2546 int buf_type = 0;
2547 QUERY_SEC_DESC_REQ * pSMB;
2548 struct kvec iov[1];
2549
2550 cFYI(1, ("GetCifsACL"));
2551
2552 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2553 8 /* parm len */, tcon, (void **) &pSMB);
2554 if (rc)
2555 return rc;
2556
2557 pSMB->MaxParameterCount = cpu_to_le32(4);
2558 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2559 pSMB->MaxSetupCount = 0;
2560 pSMB->Fid = fid; /* file handle always le */
2561 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2562 CIFS_ACL_DACL);
2563 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2564 pSMB->hdr.smb_buf_length += 11;
2565 iov[0].iov_base = (char *)pSMB;
2566 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2567
2568 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2569 cifs_stats_inc(&tcon->num_acl_get);
2570 if (rc) {
2571 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2572 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002573 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002574 __le32 * parm;
2575 int parm_len;
2576 int data_len;
2577 int acl_len;
2578 struct smb_com_ntransact_rsp * pSMBr;
2579
2580/* validate_nttransact */
2581 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2582 (char **)&psec_desc,
2583 &parm_len, &data_len);
2584
2585 if(rc)
2586 goto qsec_out;
2587 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2588
2589 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2590
2591 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2592 rc = -EIO; /* bad smb */
2593 goto qsec_out;
2594 }
2595
2596/* BB check that data area is minimum length and as big as acl_len */
2597
2598 acl_len = le32_to_cpu(*(__le32 *)parm);
2599 /* BB check if(acl_len > bufsize) */
2600
2601 parse_sec_desc(psec_desc, acl_len);
2602 }
2603qsec_out:
2604 if(buf_type == CIFS_SMALL_BUFFER)
2605 cifs_small_buf_release(iov[0].iov_base);
2606 else if(buf_type == CIFS_LARGE_BUFFER)
2607 cifs_buf_release(iov[0].iov_base);
2608 cifs_small_buf_release(pSMB);
2609 return rc;
2610}
2611
2612
Steve French6b8edfe2005-08-23 20:26:03 -07002613/* Legacy Query Path Information call for lookup to old servers such
2614 as Win9x/WinME */
2615int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2616 const unsigned char *searchName,
2617 FILE_ALL_INFO * pFinfo,
2618 const struct nls_table *nls_codepage, int remap)
2619{
2620 QUERY_INFORMATION_REQ * pSMB;
2621 QUERY_INFORMATION_RSP * pSMBr;
2622 int rc = 0;
2623 int bytes_returned;
2624 int name_len;
2625
2626 cFYI(1, ("In SMBQPath path %s", searchName));
2627QInfRetry:
2628 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2629 (void **) &pSMBr);
2630 if (rc)
2631 return rc;
2632
2633 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2634 name_len =
2635 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2636 PATH_MAX, nls_codepage, remap);
2637 name_len++; /* trailing null */
2638 name_len *= 2;
2639 } else {
2640 name_len = strnlen(searchName, PATH_MAX);
2641 name_len++; /* trailing null */
2642 strncpy(pSMB->FileName, searchName, name_len);
2643 }
2644 pSMB->BufferFormat = 0x04;
2645 name_len++; /* account for buffer type byte */
2646 pSMB->hdr.smb_buf_length += (__u16) name_len;
2647 pSMB->ByteCount = cpu_to_le16(name_len);
2648
2649 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2650 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2651 if (rc) {
2652 cFYI(1, ("Send error in QueryInfo = %d", rc));
2653 } else if (pFinfo) { /* decode response */
2654 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002655 pFinfo->AllocationSize =
2656 cpu_to_le64(le32_to_cpu(pSMBr->size));
2657 pFinfo->EndOfFile = pFinfo->AllocationSize;
2658 pFinfo->Attributes =
2659 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002660 } else
2661 rc = -EIO; /* bad buffer passed in */
2662
2663 cifs_buf_release(pSMB);
2664
2665 if (rc == -EAGAIN)
2666 goto QInfRetry;
2667
2668 return rc;
2669}
2670
2671
2672
2673
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674int
2675CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2676 const unsigned char *searchName,
2677 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002678 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679{
2680/* level 263 SMB_QUERY_FILE_ALL_INFO */
2681 TRANSACTION2_QPI_REQ *pSMB = NULL;
2682 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2683 int rc = 0;
2684 int bytes_returned;
2685 int name_len;
2686 __u16 params, byte_count;
2687
2688/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2689QPathInfoRetry:
2690 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2691 (void **) &pSMBr);
2692 if (rc)
2693 return rc;
2694
2695 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2696 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002697 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002698 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 name_len++; /* trailing null */
2700 name_len *= 2;
2701 } else { /* BB improve the check for buffer overruns BB */
2702 name_len = strnlen(searchName, PATH_MAX);
2703 name_len++; /* trailing null */
2704 strncpy(pSMB->FileName, searchName, name_len);
2705 }
2706
2707 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2708 pSMB->TotalDataCount = 0;
2709 pSMB->MaxParameterCount = cpu_to_le16(2);
2710 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2711 pSMB->MaxSetupCount = 0;
2712 pSMB->Reserved = 0;
2713 pSMB->Flags = 0;
2714 pSMB->Timeout = 0;
2715 pSMB->Reserved2 = 0;
2716 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2717 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2718 pSMB->DataCount = 0;
2719 pSMB->DataOffset = 0;
2720 pSMB->SetupCount = 1;
2721 pSMB->Reserved3 = 0;
2722 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2723 byte_count = params + 1 /* pad */ ;
2724 pSMB->TotalParameterCount = cpu_to_le16(params);
2725 pSMB->ParameterCount = pSMB->TotalParameterCount;
2726 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2727 pSMB->Reserved4 = 0;
2728 pSMB->hdr.smb_buf_length += byte_count;
2729 pSMB->ByteCount = cpu_to_le16(byte_count);
2730
2731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2732 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2733 if (rc) {
2734 cFYI(1, ("Send error in QPathInfo = %d", rc));
2735 } else { /* decode response */
2736 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2737
2738 if (rc || (pSMBr->ByteCount < 40))
2739 rc = -EIO; /* bad smb */
2740 else if (pFindData){
2741 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2742 memcpy((char *) pFindData,
2743 (char *) &pSMBr->hdr.Protocol +
2744 data_offset, sizeof (FILE_ALL_INFO));
2745 } else
2746 rc = -ENOMEM;
2747 }
2748 cifs_buf_release(pSMB);
2749 if (rc == -EAGAIN)
2750 goto QPathInfoRetry;
2751
2752 return rc;
2753}
2754
2755int
2756CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2757 const unsigned char *searchName,
2758 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002759 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760{
2761/* SMB_QUERY_FILE_UNIX_BASIC */
2762 TRANSACTION2_QPI_REQ *pSMB = NULL;
2763 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2764 int rc = 0;
2765 int bytes_returned = 0;
2766 int name_len;
2767 __u16 params, byte_count;
2768
2769 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2770UnixQPathInfoRetry:
2771 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2772 (void **) &pSMBr);
2773 if (rc)
2774 return rc;
2775
2776 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2777 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002778 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002779 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 name_len++; /* trailing null */
2781 name_len *= 2;
2782 } else { /* BB improve the check for buffer overruns BB */
2783 name_len = strnlen(searchName, PATH_MAX);
2784 name_len++; /* trailing null */
2785 strncpy(pSMB->FileName, searchName, name_len);
2786 }
2787
2788 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2789 pSMB->TotalDataCount = 0;
2790 pSMB->MaxParameterCount = cpu_to_le16(2);
2791 /* BB find exact max SMB PDU from sess structure BB */
2792 pSMB->MaxDataCount = cpu_to_le16(4000);
2793 pSMB->MaxSetupCount = 0;
2794 pSMB->Reserved = 0;
2795 pSMB->Flags = 0;
2796 pSMB->Timeout = 0;
2797 pSMB->Reserved2 = 0;
2798 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2799 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2800 pSMB->DataCount = 0;
2801 pSMB->DataOffset = 0;
2802 pSMB->SetupCount = 1;
2803 pSMB->Reserved3 = 0;
2804 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2805 byte_count = params + 1 /* pad */ ;
2806 pSMB->TotalParameterCount = cpu_to_le16(params);
2807 pSMB->ParameterCount = pSMB->TotalParameterCount;
2808 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2809 pSMB->Reserved4 = 0;
2810 pSMB->hdr.smb_buf_length += byte_count;
2811 pSMB->ByteCount = cpu_to_le16(byte_count);
2812
2813 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2814 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2815 if (rc) {
2816 cFYI(1, ("Send error in QPathInfo = %d", rc));
2817 } else { /* decode response */
2818 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2819
2820 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2821 rc = -EIO; /* bad smb */
2822 } else {
2823 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2824 memcpy((char *) pFindData,
2825 (char *) &pSMBr->hdr.Protocol +
2826 data_offset,
2827 sizeof (FILE_UNIX_BASIC_INFO));
2828 }
2829 }
2830 cifs_buf_release(pSMB);
2831 if (rc == -EAGAIN)
2832 goto UnixQPathInfoRetry;
2833
2834 return rc;
2835}
2836
2837#if 0 /* function unused at present */
2838int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2839 const char *searchName, FILE_ALL_INFO * findData,
2840 const struct nls_table *nls_codepage)
2841{
2842/* level 257 SMB_ */
2843 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2844 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2845 int rc = 0;
2846 int bytes_returned;
2847 int name_len;
2848 __u16 params, byte_count;
2849
2850 cFYI(1, ("In FindUnique"));
2851findUniqueRetry:
2852 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2853 (void **) &pSMBr);
2854 if (rc)
2855 return rc;
2856
2857 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2858 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002859 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 /* find define for this maxpathcomponent */
2861 , nls_codepage);
2862 name_len++; /* trailing null */
2863 name_len *= 2;
2864 } else { /* BB improve the check for buffer overruns BB */
2865 name_len = strnlen(searchName, PATH_MAX);
2866 name_len++; /* trailing null */
2867 strncpy(pSMB->FileName, searchName, name_len);
2868 }
2869
2870 params = 12 + name_len /* includes null */ ;
2871 pSMB->TotalDataCount = 0; /* no EAs */
2872 pSMB->MaxParameterCount = cpu_to_le16(2);
2873 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2874 pSMB->MaxSetupCount = 0;
2875 pSMB->Reserved = 0;
2876 pSMB->Flags = 0;
2877 pSMB->Timeout = 0;
2878 pSMB->Reserved2 = 0;
2879 pSMB->ParameterOffset = cpu_to_le16(
2880 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2881 pSMB->DataCount = 0;
2882 pSMB->DataOffset = 0;
2883 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2884 pSMB->Reserved3 = 0;
2885 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2886 byte_count = params + 1 /* pad */ ;
2887 pSMB->TotalParameterCount = cpu_to_le16(params);
2888 pSMB->ParameterCount = pSMB->TotalParameterCount;
2889 pSMB->SearchAttributes =
2890 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2891 ATTR_DIRECTORY);
2892 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2893 pSMB->SearchFlags = cpu_to_le16(1);
2894 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2895 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2896 pSMB->hdr.smb_buf_length += byte_count;
2897 pSMB->ByteCount = cpu_to_le16(byte_count);
2898
2899 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2900 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2901
2902 if (rc) {
2903 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2904 } else { /* decode response */
Steve Frencha45443472005-08-24 13:59:35 -07002905 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 /* BB fill in */
2907 }
2908
2909 cifs_buf_release(pSMB);
2910 if (rc == -EAGAIN)
2911 goto findUniqueRetry;
2912
2913 return rc;
2914}
2915#endif /* end unused (temporarily) function */
2916
2917/* xid, tcon, searchName and codepage are input parms, rest are returned */
2918int
2919CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2920 const char *searchName,
2921 const struct nls_table *nls_codepage,
2922 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002923 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924{
2925/* level 257 SMB_ */
2926 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2927 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2928 T2_FFIRST_RSP_PARMS * parms;
2929 int rc = 0;
2930 int bytes_returned = 0;
2931 int name_len;
2932 __u16 params, byte_count;
2933
Steve French737b7582005-04-28 22:41:06 -07002934 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936findFirstRetry:
2937 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2938 (void **) &pSMBr);
2939 if (rc)
2940 return rc;
2941
2942 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2943 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002944 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002945 PATH_MAX, nls_codepage, remap);
2946 /* We can not add the asterik earlier in case
2947 it got remapped to 0xF03A as if it were part of the
2948 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002950 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002951 pSMB->FileName[name_len+1] = 0;
2952 pSMB->FileName[name_len+2] = '*';
2953 pSMB->FileName[name_len+3] = 0;
2954 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2956 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002957 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 } else { /* BB add check for overrun of SMB buf BB */
2959 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960/* BB fix here and in unicode clause above ie
2961 if(name_len > buffersize-header)
2962 free buffer exit; BB */
2963 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002964 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002965 pSMB->FileName[name_len+1] = '*';
2966 pSMB->FileName[name_len+2] = 0;
2967 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 }
2969
2970 params = 12 + name_len /* includes null */ ;
2971 pSMB->TotalDataCount = 0; /* no EAs */
2972 pSMB->MaxParameterCount = cpu_to_le16(10);
2973 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2974 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2975 pSMB->MaxSetupCount = 0;
2976 pSMB->Reserved = 0;
2977 pSMB->Flags = 0;
2978 pSMB->Timeout = 0;
2979 pSMB->Reserved2 = 0;
2980 byte_count = params + 1 /* pad */ ;
2981 pSMB->TotalParameterCount = cpu_to_le16(params);
2982 pSMB->ParameterCount = pSMB->TotalParameterCount;
2983 pSMB->ParameterOffset = cpu_to_le16(
2984 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2985 pSMB->DataCount = 0;
2986 pSMB->DataOffset = 0;
2987 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2988 pSMB->Reserved3 = 0;
2989 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2990 pSMB->SearchAttributes =
2991 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2992 ATTR_DIRECTORY);
2993 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2994 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2995 CIFS_SEARCH_RETURN_RESUME);
2996 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2997
2998 /* BB what should we set StorageType to? Does it matter? BB */
2999 pSMB->SearchStorageType = 0;
3000 pSMB->hdr.smb_buf_length += byte_count;
3001 pSMB->ByteCount = cpu_to_le16(byte_count);
3002
3003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003005 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006
Steve French1982c342005-08-17 12:38:22 -07003007 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 /* BB Add code to handle unsupported level rc */
3009 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003010
3011 if (pSMB)
3012 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013
3014 /* BB eventually could optimize out free and realloc of buf */
3015 /* for this case */
3016 if (rc == -EAGAIN)
3017 goto findFirstRetry;
3018 } else { /* decode response */
3019 /* BB remember to free buffer if error BB */
3020 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3021 if(rc == 0) {
3022 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3023 psrch_inf->unicode = TRUE;
3024 else
3025 psrch_inf->unicode = FALSE;
3026
3027 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3028 psrch_inf->srch_entries_start =
3029 (char *) &pSMBr->hdr.Protocol +
3030 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3032 le16_to_cpu(pSMBr->t2.ParameterOffset));
3033
3034 if(parms->EndofSearch)
3035 psrch_inf->endOfSearch = TRUE;
3036 else
3037 psrch_inf->endOfSearch = FALSE;
3038
3039 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3040 psrch_inf->index_of_last_entry =
3041 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 *pnetfid = parms->SearchHandle;
3043 } else {
3044 cifs_buf_release(pSMB);
3045 }
3046 }
3047
3048 return rc;
3049}
3050
3051int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3052 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3053{
3054 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3055 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3056 T2_FNEXT_RSP_PARMS * parms;
3057 char *response_data;
3058 int rc = 0;
3059 int bytes_returned, name_len;
3060 __u16 params, byte_count;
3061
3062 cFYI(1, ("In FindNext"));
3063
3064 if(psrch_inf->endOfSearch == TRUE)
3065 return -ENOENT;
3066
3067 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3068 (void **) &pSMBr);
3069 if (rc)
3070 return rc;
3071
3072 params = 14; /* includes 2 bytes of null string, converted to LE below */
3073 byte_count = 0;
3074 pSMB->TotalDataCount = 0; /* no EAs */
3075 pSMB->MaxParameterCount = cpu_to_le16(8);
3076 pSMB->MaxDataCount =
3077 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3078 pSMB->MaxSetupCount = 0;
3079 pSMB->Reserved = 0;
3080 pSMB->Flags = 0;
3081 pSMB->Timeout = 0;
3082 pSMB->Reserved2 = 0;
3083 pSMB->ParameterOffset = cpu_to_le16(
3084 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3085 pSMB->DataCount = 0;
3086 pSMB->DataOffset = 0;
3087 pSMB->SetupCount = 1;
3088 pSMB->Reserved3 = 0;
3089 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3090 pSMB->SearchHandle = searchHandle; /* always kept as le */
3091 pSMB->SearchCount =
3092 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3093 /* test for Unix extensions */
3094/* if (tcon->ses->capabilities & CAP_UNIX) {
3095 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3096 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3097 } else {
3098 pSMB->InformationLevel =
3099 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3100 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3101 } */
3102 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3103 pSMB->ResumeKey = psrch_inf->resume_key;
3104 pSMB->SearchFlags =
3105 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3106
3107 name_len = psrch_inf->resume_name_len;
3108 params += name_len;
3109 if(name_len < PATH_MAX) {
3110 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3111 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003112 /* 14 byte parm len above enough for 2 byte null terminator */
3113 pSMB->ResumeFileName[name_len] = 0;
3114 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 } else {
3116 rc = -EINVAL;
3117 goto FNext2_err_exit;
3118 }
3119 byte_count = params + 1 /* pad */ ;
3120 pSMB->TotalParameterCount = cpu_to_le16(params);
3121 pSMB->ParameterCount = pSMB->TotalParameterCount;
3122 pSMB->hdr.smb_buf_length += byte_count;
3123 pSMB->ByteCount = cpu_to_le16(byte_count);
3124
3125 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3126 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003127 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 if (rc) {
3129 if (rc == -EBADF) {
3130 psrch_inf->endOfSearch = TRUE;
3131 rc = 0; /* search probably was closed at end of search above */
3132 } else
3133 cFYI(1, ("FindNext returned = %d", rc));
3134 } else { /* decode response */
3135 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3136
3137 if(rc == 0) {
3138 /* BB fixme add lock for file (srch_info) struct here */
3139 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3140 psrch_inf->unicode = TRUE;
3141 else
3142 psrch_inf->unicode = FALSE;
3143 response_data = (char *) &pSMBr->hdr.Protocol +
3144 le16_to_cpu(pSMBr->t2.ParameterOffset);
3145 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3146 response_data = (char *)&pSMBr->hdr.Protocol +
3147 le16_to_cpu(pSMBr->t2.DataOffset);
3148 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3149 psrch_inf->srch_entries_start = response_data;
3150 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3151 if(parms->EndofSearch)
3152 psrch_inf->endOfSearch = TRUE;
3153 else
3154 psrch_inf->endOfSearch = FALSE;
3155
3156 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3157 psrch_inf->index_of_last_entry +=
3158 psrch_inf->entries_in_buffer;
3159/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3160
3161 /* BB fixme add unlock here */
3162 }
3163
3164 }
3165
3166 /* BB On error, should we leave previous search buf (and count and
3167 last entry fields) intact or free the previous one? */
3168
3169 /* Note: On -EAGAIN error only caller can retry on handle based calls
3170 since file handle passed in no longer valid */
3171FNext2_err_exit:
3172 if (rc != 0)
3173 cifs_buf_release(pSMB);
3174
3175 return rc;
3176}
3177
3178int
3179CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3180{
3181 int rc = 0;
3182 FINDCLOSE_REQ *pSMB = NULL;
3183 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3184 int bytes_returned;
3185
3186 cFYI(1, ("In CIFSSMBFindClose"));
3187 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3188
3189 /* no sense returning error if session restarted
3190 as file handle has been closed */
3191 if(rc == -EAGAIN)
3192 return 0;
3193 if (rc)
3194 return rc;
3195
3196 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3197 pSMB->FileID = searchHandle;
3198 pSMB->ByteCount = 0;
3199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3201 if (rc) {
3202 cERROR(1, ("Send error in FindClose = %d", rc));
3203 }
Steve Frencha45443472005-08-24 13:59:35 -07003204 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 cifs_small_buf_release(pSMB);
3206
3207 /* Since session is dead, search handle closed on server already */
3208 if (rc == -EAGAIN)
3209 rc = 0;
3210
3211 return rc;
3212}
3213
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214int
3215CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3216 const unsigned char *searchName,
3217 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003218 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219{
3220 int rc = 0;
3221 TRANSACTION2_QPI_REQ *pSMB = NULL;
3222 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3223 int name_len, bytes_returned;
3224 __u16 params, byte_count;
3225
3226 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3227 if(tcon == NULL)
3228 return -ENODEV;
3229
3230GetInodeNumberRetry:
3231 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3232 (void **) &pSMBr);
3233 if (rc)
3234 return rc;
3235
3236
3237 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3238 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003239 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003240 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 name_len++; /* trailing null */
3242 name_len *= 2;
3243 } else { /* BB improve the check for buffer overruns BB */
3244 name_len = strnlen(searchName, PATH_MAX);
3245 name_len++; /* trailing null */
3246 strncpy(pSMB->FileName, searchName, name_len);
3247 }
3248
3249 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3250 pSMB->TotalDataCount = 0;
3251 pSMB->MaxParameterCount = cpu_to_le16(2);
3252 /* BB find exact max data count below from sess structure BB */
3253 pSMB->MaxDataCount = cpu_to_le16(4000);
3254 pSMB->MaxSetupCount = 0;
3255 pSMB->Reserved = 0;
3256 pSMB->Flags = 0;
3257 pSMB->Timeout = 0;
3258 pSMB->Reserved2 = 0;
3259 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3260 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3261 pSMB->DataCount = 0;
3262 pSMB->DataOffset = 0;
3263 pSMB->SetupCount = 1;
3264 pSMB->Reserved3 = 0;
3265 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3266 byte_count = params + 1 /* pad */ ;
3267 pSMB->TotalParameterCount = cpu_to_le16(params);
3268 pSMB->ParameterCount = pSMB->TotalParameterCount;
3269 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3270 pSMB->Reserved4 = 0;
3271 pSMB->hdr.smb_buf_length += byte_count;
3272 pSMB->ByteCount = cpu_to_le16(byte_count);
3273
3274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3275 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3276 if (rc) {
3277 cFYI(1, ("error %d in QueryInternalInfo", rc));
3278 } else {
3279 /* decode response */
3280 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3281 if (rc || (pSMBr->ByteCount < 2))
3282 /* BB also check enough total bytes returned */
3283 /* If rc should we check for EOPNOSUPP and
3284 disable the srvino flag? or in caller? */
3285 rc = -EIO; /* bad smb */
3286 else {
3287 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3288 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3289 struct file_internal_info * pfinfo;
3290 /* BB Do we need a cast or hash here ? */
3291 if(count < 8) {
3292 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3293 rc = -EIO;
3294 goto GetInodeNumOut;
3295 }
3296 pfinfo = (struct file_internal_info *)
3297 (data_offset + (char *) &pSMBr->hdr.Protocol);
3298 *inode_number = pfinfo->UniqueId;
3299 }
3300 }
3301GetInodeNumOut:
3302 cifs_buf_release(pSMB);
3303 if (rc == -EAGAIN)
3304 goto GetInodeNumberRetry;
3305 return rc;
3306}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307
3308int
3309CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3310 const unsigned char *searchName,
3311 unsigned char **targetUNCs,
3312 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003313 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314{
3315/* TRANS2_GET_DFS_REFERRAL */
3316 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3317 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3318 struct dfs_referral_level_3 * referrals = NULL;
3319 int rc = 0;
3320 int bytes_returned;
3321 int name_len;
3322 unsigned int i;
3323 char * temp;
3324 __u16 params, byte_count;
3325 *number_of_UNC_in_array = 0;
3326 *targetUNCs = NULL;
3327
3328 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3329 if (ses == NULL)
3330 return -ENODEV;
3331getDFSRetry:
3332 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3333 (void **) &pSMBr);
3334 if (rc)
3335 return rc;
Steve French1982c342005-08-17 12:38:22 -07003336
3337 /* server pointer checked in called function,
3338 but should never be null here anyway */
3339 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 pSMB->hdr.Tid = ses->ipc_tid;
3341 pSMB->hdr.Uid = ses->Suid;
3342 if (ses->capabilities & CAP_STATUS32) {
3343 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3344 }
3345 if (ses->capabilities & CAP_DFS) {
3346 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3347 }
3348
3349 if (ses->capabilities & CAP_UNICODE) {
3350 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3351 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003352 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003353 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 name_len++; /* trailing null */
3355 name_len *= 2;
3356 } else { /* BB improve the check for buffer overruns BB */
3357 name_len = strnlen(searchName, PATH_MAX);
3358 name_len++; /* trailing null */
3359 strncpy(pSMB->RequestFileName, searchName, name_len);
3360 }
3361
3362 params = 2 /* level */ + name_len /*includes null */ ;
3363 pSMB->TotalDataCount = 0;
3364 pSMB->DataCount = 0;
3365 pSMB->DataOffset = 0;
3366 pSMB->MaxParameterCount = 0;
3367 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3368 pSMB->MaxSetupCount = 0;
3369 pSMB->Reserved = 0;
3370 pSMB->Flags = 0;
3371 pSMB->Timeout = 0;
3372 pSMB->Reserved2 = 0;
3373 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3374 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3375 pSMB->SetupCount = 1;
3376 pSMB->Reserved3 = 0;
3377 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3378 byte_count = params + 3 /* pad */ ;
3379 pSMB->ParameterCount = cpu_to_le16(params);
3380 pSMB->TotalParameterCount = pSMB->ParameterCount;
3381 pSMB->MaxReferralLevel = cpu_to_le16(3);
3382 pSMB->hdr.smb_buf_length += byte_count;
3383 pSMB->ByteCount = cpu_to_le16(byte_count);
3384
3385 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3386 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3387 if (rc) {
3388 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3389 } else { /* decode response */
3390/* BB Add logic to parse referrals here */
3391 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3392
3393 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3394 rc = -EIO; /* bad smb */
3395 else {
3396 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3397 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3398
3399 cFYI(1,
3400 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3401 pSMBr->ByteCount, data_offset));
3402 referrals =
3403 (struct dfs_referral_level_3 *)
3404 (8 /* sizeof start of data block */ +
3405 data_offset +
3406 (char *) &pSMBr->hdr.Protocol);
3407 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",
3408 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)));
3409 /* BB This field is actually two bytes in from start of
3410 data block so we could do safety check that DataBlock
3411 begins at address of pSMBr->NumberOfReferrals */
3412 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3413
3414 /* BB Fix below so can return more than one referral */
3415 if(*number_of_UNC_in_array > 1)
3416 *number_of_UNC_in_array = 1;
3417
3418 /* get the length of the strings describing refs */
3419 name_len = 0;
3420 for(i=0;i<*number_of_UNC_in_array;i++) {
3421 /* make sure that DfsPathOffset not past end */
3422 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3423 if (offset > data_count) {
3424 /* if invalid referral, stop here and do
3425 not try to copy any more */
3426 *number_of_UNC_in_array = i;
3427 break;
3428 }
3429 temp = ((char *)referrals) + offset;
3430
3431 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3432 name_len += UniStrnlen((wchar_t *)temp,data_count);
3433 } else {
3434 name_len += strnlen(temp,data_count);
3435 }
3436 referrals++;
3437 /* BB add check that referral pointer does not fall off end PDU */
3438
3439 }
3440 /* BB add check for name_len bigger than bcc */
3441 *targetUNCs =
3442 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3443 if(*targetUNCs == NULL) {
3444 rc = -ENOMEM;
3445 goto GetDFSRefExit;
3446 }
3447 /* copy the ref strings */
3448 referrals =
3449 (struct dfs_referral_level_3 *)
3450 (8 /* sizeof data hdr */ +
3451 data_offset +
3452 (char *) &pSMBr->hdr.Protocol);
3453
3454 for(i=0;i<*number_of_UNC_in_array;i++) {
3455 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3456 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3457 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003458 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 } else {
3460 strncpy(*targetUNCs,temp,name_len);
3461 }
3462 /* BB update target_uncs pointers */
3463 referrals++;
3464 }
3465 temp = *targetUNCs;
3466 temp[name_len] = 0;
3467 }
3468
3469 }
3470GetDFSRefExit:
3471 if (pSMB)
3472 cifs_buf_release(pSMB);
3473
3474 if (rc == -EAGAIN)
3475 goto getDFSRetry;
3476
3477 return rc;
3478}
3479
Steve French20962432005-09-21 22:05:57 -07003480/* Query File System Info such as free space to old servers such as Win 9x */
3481int
3482SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3483{
3484/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3485 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3486 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3487 FILE_SYSTEM_ALLOC_INFO *response_data;
3488 int rc = 0;
3489 int bytes_returned = 0;
3490 __u16 params, byte_count;
3491
3492 cFYI(1, ("OldQFSInfo"));
3493oldQFSInfoRetry:
3494 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3495 (void **) &pSMBr);
3496 if (rc)
3497 return rc;
3498 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3499 (void **) &pSMBr);
3500 if (rc)
3501 return rc;
3502
3503 params = 2; /* level */
3504 pSMB->TotalDataCount = 0;
3505 pSMB->MaxParameterCount = cpu_to_le16(2);
3506 pSMB->MaxDataCount = cpu_to_le16(1000);
3507 pSMB->MaxSetupCount = 0;
3508 pSMB->Reserved = 0;
3509 pSMB->Flags = 0;
3510 pSMB->Timeout = 0;
3511 pSMB->Reserved2 = 0;
3512 byte_count = params + 1 /* pad */ ;
3513 pSMB->TotalParameterCount = cpu_to_le16(params);
3514 pSMB->ParameterCount = pSMB->TotalParameterCount;
3515 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3516 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3517 pSMB->DataCount = 0;
3518 pSMB->DataOffset = 0;
3519 pSMB->SetupCount = 1;
3520 pSMB->Reserved3 = 0;
3521 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3522 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3523 pSMB->hdr.smb_buf_length += byte_count;
3524 pSMB->ByteCount = cpu_to_le16(byte_count);
3525
3526 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3527 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3528 if (rc) {
3529 cFYI(1, ("Send error in QFSInfo = %d", rc));
3530 } else { /* decode response */
3531 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3532
3533 if (rc || (pSMBr->ByteCount < 18))
3534 rc = -EIO; /* bad smb */
3535 else {
3536 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3537 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3538 pSMBr->ByteCount, data_offset));
3539
3540 response_data =
3541 (FILE_SYSTEM_ALLOC_INFO *)
3542 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3543 FSData->f_bsize =
3544 le16_to_cpu(response_data->BytesPerSector) *
3545 le32_to_cpu(response_data->
3546 SectorsPerAllocationUnit);
3547 FSData->f_blocks =
3548 le32_to_cpu(response_data->TotalAllocationUnits);
3549 FSData->f_bfree = FSData->f_bavail =
3550 le32_to_cpu(response_data->FreeAllocationUnits);
3551 cFYI(1,
3552 ("Blocks: %lld Free: %lld Block size %ld",
3553 (unsigned long long)FSData->f_blocks,
3554 (unsigned long long)FSData->f_bfree,
3555 FSData->f_bsize));
3556 }
3557 }
3558 cifs_buf_release(pSMB);
3559
3560 if (rc == -EAGAIN)
3561 goto oldQFSInfoRetry;
3562
3563 return rc;
3564}
3565
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566int
Steve French737b7582005-04-28 22:41:06 -07003567CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568{
3569/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3570 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3571 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3572 FILE_SYSTEM_INFO *response_data;
3573 int rc = 0;
3574 int bytes_returned = 0;
3575 __u16 params, byte_count;
3576
3577 cFYI(1, ("In QFSInfo"));
3578QFSInfoRetry:
3579 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3580 (void **) &pSMBr);
3581 if (rc)
3582 return rc;
3583
3584 params = 2; /* level */
3585 pSMB->TotalDataCount = 0;
3586 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003587 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 pSMB->MaxSetupCount = 0;
3589 pSMB->Reserved = 0;
3590 pSMB->Flags = 0;
3591 pSMB->Timeout = 0;
3592 pSMB->Reserved2 = 0;
3593 byte_count = params + 1 /* pad */ ;
3594 pSMB->TotalParameterCount = cpu_to_le16(params);
3595 pSMB->ParameterCount = pSMB->TotalParameterCount;
3596 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3597 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3598 pSMB->DataCount = 0;
3599 pSMB->DataOffset = 0;
3600 pSMB->SetupCount = 1;
3601 pSMB->Reserved3 = 0;
3602 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3603 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3604 pSMB->hdr.smb_buf_length += byte_count;
3605 pSMB->ByteCount = cpu_to_le16(byte_count);
3606
3607 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3609 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003610 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 } else { /* decode response */
3612 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3613
Steve French20962432005-09-21 22:05:57 -07003614 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 rc = -EIO; /* bad smb */
3616 else {
3617 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618
3619 response_data =
3620 (FILE_SYSTEM_INFO
3621 *) (((char *) &pSMBr->hdr.Protocol) +
3622 data_offset);
3623 FSData->f_bsize =
3624 le32_to_cpu(response_data->BytesPerSector) *
3625 le32_to_cpu(response_data->
3626 SectorsPerAllocationUnit);
3627 FSData->f_blocks =
3628 le64_to_cpu(response_data->TotalAllocationUnits);
3629 FSData->f_bfree = FSData->f_bavail =
3630 le64_to_cpu(response_data->FreeAllocationUnits);
3631 cFYI(1,
3632 ("Blocks: %lld Free: %lld Block size %ld",
3633 (unsigned long long)FSData->f_blocks,
3634 (unsigned long long)FSData->f_bfree,
3635 FSData->f_bsize));
3636 }
3637 }
3638 cifs_buf_release(pSMB);
3639
3640 if (rc == -EAGAIN)
3641 goto QFSInfoRetry;
3642
3643 return rc;
3644}
3645
3646int
Steve French737b7582005-04-28 22:41:06 -07003647CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648{
3649/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3650 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3651 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3652 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3653 int rc = 0;
3654 int bytes_returned = 0;
3655 __u16 params, byte_count;
3656
3657 cFYI(1, ("In QFSAttributeInfo"));
3658QFSAttributeRetry:
3659 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3660 (void **) &pSMBr);
3661 if (rc)
3662 return rc;
3663
3664 params = 2; /* level */
3665 pSMB->TotalDataCount = 0;
3666 pSMB->MaxParameterCount = cpu_to_le16(2);
3667 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3668 pSMB->MaxSetupCount = 0;
3669 pSMB->Reserved = 0;
3670 pSMB->Flags = 0;
3671 pSMB->Timeout = 0;
3672 pSMB->Reserved2 = 0;
3673 byte_count = params + 1 /* pad */ ;
3674 pSMB->TotalParameterCount = cpu_to_le16(params);
3675 pSMB->ParameterCount = pSMB->TotalParameterCount;
3676 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3677 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3678 pSMB->DataCount = 0;
3679 pSMB->DataOffset = 0;
3680 pSMB->SetupCount = 1;
3681 pSMB->Reserved3 = 0;
3682 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3683 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3684 pSMB->hdr.smb_buf_length += byte_count;
3685 pSMB->ByteCount = cpu_to_le16(byte_count);
3686
3687 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3688 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3689 if (rc) {
3690 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3691 } else { /* decode response */
3692 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3693
3694 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3695 rc = -EIO; /* bad smb */
3696 } else {
3697 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3698 response_data =
3699 (FILE_SYSTEM_ATTRIBUTE_INFO
3700 *) (((char *) &pSMBr->hdr.Protocol) +
3701 data_offset);
3702 memcpy(&tcon->fsAttrInfo, response_data,
3703 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3704 }
3705 }
3706 cifs_buf_release(pSMB);
3707
3708 if (rc == -EAGAIN)
3709 goto QFSAttributeRetry;
3710
3711 return rc;
3712}
3713
3714int
Steve French737b7582005-04-28 22:41:06 -07003715CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716{
3717/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3718 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3719 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3720 FILE_SYSTEM_DEVICE_INFO *response_data;
3721 int rc = 0;
3722 int bytes_returned = 0;
3723 __u16 params, byte_count;
3724
3725 cFYI(1, ("In QFSDeviceInfo"));
3726QFSDeviceRetry:
3727 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3728 (void **) &pSMBr);
3729 if (rc)
3730 return rc;
3731
3732 params = 2; /* level */
3733 pSMB->TotalDataCount = 0;
3734 pSMB->MaxParameterCount = cpu_to_le16(2);
3735 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3736 pSMB->MaxSetupCount = 0;
3737 pSMB->Reserved = 0;
3738 pSMB->Flags = 0;
3739 pSMB->Timeout = 0;
3740 pSMB->Reserved2 = 0;
3741 byte_count = params + 1 /* pad */ ;
3742 pSMB->TotalParameterCount = cpu_to_le16(params);
3743 pSMB->ParameterCount = pSMB->TotalParameterCount;
3744 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3745 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3746
3747 pSMB->DataCount = 0;
3748 pSMB->DataOffset = 0;
3749 pSMB->SetupCount = 1;
3750 pSMB->Reserved3 = 0;
3751 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3752 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3753 pSMB->hdr.smb_buf_length += byte_count;
3754 pSMB->ByteCount = cpu_to_le16(byte_count);
3755
3756 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3757 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3758 if (rc) {
3759 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3760 } else { /* decode response */
3761 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3762
3763 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3764 rc = -EIO; /* bad smb */
3765 else {
3766 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3767 response_data =
Steve French737b7582005-04-28 22:41:06 -07003768 (FILE_SYSTEM_DEVICE_INFO *)
3769 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 data_offset);
3771 memcpy(&tcon->fsDevInfo, response_data,
3772 sizeof (FILE_SYSTEM_DEVICE_INFO));
3773 }
3774 }
3775 cifs_buf_release(pSMB);
3776
3777 if (rc == -EAGAIN)
3778 goto QFSDeviceRetry;
3779
3780 return rc;
3781}
3782
3783int
Steve French737b7582005-04-28 22:41:06 -07003784CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785{
3786/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3787 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3788 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3789 FILE_SYSTEM_UNIX_INFO *response_data;
3790 int rc = 0;
3791 int bytes_returned = 0;
3792 __u16 params, byte_count;
3793
3794 cFYI(1, ("In QFSUnixInfo"));
3795QFSUnixRetry:
3796 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3797 (void **) &pSMBr);
3798 if (rc)
3799 return rc;
3800
3801 params = 2; /* level */
3802 pSMB->TotalDataCount = 0;
3803 pSMB->DataCount = 0;
3804 pSMB->DataOffset = 0;
3805 pSMB->MaxParameterCount = cpu_to_le16(2);
3806 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3807 pSMB->MaxSetupCount = 0;
3808 pSMB->Reserved = 0;
3809 pSMB->Flags = 0;
3810 pSMB->Timeout = 0;
3811 pSMB->Reserved2 = 0;
3812 byte_count = params + 1 /* pad */ ;
3813 pSMB->ParameterCount = cpu_to_le16(params);
3814 pSMB->TotalParameterCount = pSMB->ParameterCount;
3815 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3816 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3817 pSMB->SetupCount = 1;
3818 pSMB->Reserved3 = 0;
3819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3820 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3821 pSMB->hdr.smb_buf_length += byte_count;
3822 pSMB->ByteCount = cpu_to_le16(byte_count);
3823
3824 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3825 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3826 if (rc) {
3827 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3828 } else { /* decode response */
3829 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3830
3831 if (rc || (pSMBr->ByteCount < 13)) {
3832 rc = -EIO; /* bad smb */
3833 } else {
3834 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3835 response_data =
3836 (FILE_SYSTEM_UNIX_INFO
3837 *) (((char *) &pSMBr->hdr.Protocol) +
3838 data_offset);
3839 memcpy(&tcon->fsUnixInfo, response_data,
3840 sizeof (FILE_SYSTEM_UNIX_INFO));
3841 }
3842 }
3843 cifs_buf_release(pSMB);
3844
3845 if (rc == -EAGAIN)
3846 goto QFSUnixRetry;
3847
3848
3849 return rc;
3850}
3851
Jeremy Allisonac670552005-06-22 17:26:35 -07003852int
Steve French45abc6e2005-06-23 13:42:03 -05003853CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003854{
3855/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3856 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3857 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3858 int rc = 0;
3859 int bytes_returned = 0;
3860 __u16 params, param_offset, offset, byte_count;
3861
3862 cFYI(1, ("In SETFSUnixInfo"));
3863SETFSUnixRetry:
3864 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3865 (void **) &pSMBr);
3866 if (rc)
3867 return rc;
3868
3869 params = 4; /* 2 bytes zero followed by info level. */
3870 pSMB->MaxSetupCount = 0;
3871 pSMB->Reserved = 0;
3872 pSMB->Flags = 0;
3873 pSMB->Timeout = 0;
3874 pSMB->Reserved2 = 0;
3875 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3876 offset = param_offset + params;
3877
3878 pSMB->MaxParameterCount = cpu_to_le16(4);
3879 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3880 pSMB->SetupCount = 1;
3881 pSMB->Reserved3 = 0;
3882 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3883 byte_count = 1 /* pad */ + params + 12;
3884
3885 pSMB->DataCount = cpu_to_le16(12);
3886 pSMB->ParameterCount = cpu_to_le16(params);
3887 pSMB->TotalDataCount = pSMB->DataCount;
3888 pSMB->TotalParameterCount = pSMB->ParameterCount;
3889 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3890 pSMB->DataOffset = cpu_to_le16(offset);
3891
3892 /* Params. */
3893 pSMB->FileNum = 0;
3894 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3895
3896 /* Data. */
3897 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3898 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3899 pSMB->ClientUnixCap = cpu_to_le64(cap);
3900
3901 pSMB->hdr.smb_buf_length += byte_count;
3902 pSMB->ByteCount = cpu_to_le16(byte_count);
3903
3904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3906 if (rc) {
3907 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3908 } else { /* decode response */
3909 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3910 if (rc) {
3911 rc = -EIO; /* bad smb */
3912 }
3913 }
3914 cifs_buf_release(pSMB);
3915
3916 if (rc == -EAGAIN)
3917 goto SETFSUnixRetry;
3918
3919 return rc;
3920}
3921
3922
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923
3924int
3925CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003926 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927{
3928/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3929 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3930 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3931 FILE_SYSTEM_POSIX_INFO *response_data;
3932 int rc = 0;
3933 int bytes_returned = 0;
3934 __u16 params, byte_count;
3935
3936 cFYI(1, ("In QFSPosixInfo"));
3937QFSPosixRetry:
3938 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3939 (void **) &pSMBr);
3940 if (rc)
3941 return rc;
3942
3943 params = 2; /* level */
3944 pSMB->TotalDataCount = 0;
3945 pSMB->DataCount = 0;
3946 pSMB->DataOffset = 0;
3947 pSMB->MaxParameterCount = cpu_to_le16(2);
3948 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3949 pSMB->MaxSetupCount = 0;
3950 pSMB->Reserved = 0;
3951 pSMB->Flags = 0;
3952 pSMB->Timeout = 0;
3953 pSMB->Reserved2 = 0;
3954 byte_count = params + 1 /* pad */ ;
3955 pSMB->ParameterCount = cpu_to_le16(params);
3956 pSMB->TotalParameterCount = pSMB->ParameterCount;
3957 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3958 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3959 pSMB->SetupCount = 1;
3960 pSMB->Reserved3 = 0;
3961 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3962 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3963 pSMB->hdr.smb_buf_length += byte_count;
3964 pSMB->ByteCount = cpu_to_le16(byte_count);
3965
3966 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3967 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3968 if (rc) {
3969 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3970 } else { /* decode response */
3971 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3972
3973 if (rc || (pSMBr->ByteCount < 13)) {
3974 rc = -EIO; /* bad smb */
3975 } else {
3976 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3977 response_data =
3978 (FILE_SYSTEM_POSIX_INFO
3979 *) (((char *) &pSMBr->hdr.Protocol) +
3980 data_offset);
3981 FSData->f_bsize =
3982 le32_to_cpu(response_data->BlockSize);
3983 FSData->f_blocks =
3984 le64_to_cpu(response_data->TotalBlocks);
3985 FSData->f_bfree =
3986 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003987 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 FSData->f_bavail = FSData->f_bfree;
3989 } else {
3990 FSData->f_bavail =
3991 le64_to_cpu(response_data->UserBlocksAvail);
3992 }
Steve French70ca7342005-09-22 16:32:06 -07003993 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 FSData->f_files =
3995 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003996 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 FSData->f_ffree =
3998 le64_to_cpu(response_data->FreeFileNodes);
3999 }
4000 }
4001 cifs_buf_release(pSMB);
4002
4003 if (rc == -EAGAIN)
4004 goto QFSPosixRetry;
4005
4006 return rc;
4007}
4008
4009
4010/* We can not use write of zero bytes trick to
4011 set file size due to need for large file support. Also note that
4012 this SetPathInfo is preferred to SetFileInfo based method in next
4013 routine which is only needed to work around a sharing violation bug
4014 in Samba which this routine can run into */
4015
4016int
4017CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004018 __u64 size, int SetAllocation,
4019 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020{
4021 struct smb_com_transaction2_spi_req *pSMB = NULL;
4022 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4023 struct file_end_of_file_info *parm_data;
4024 int name_len;
4025 int rc = 0;
4026 int bytes_returned = 0;
4027 __u16 params, byte_count, data_count, param_offset, offset;
4028
4029 cFYI(1, ("In SetEOF"));
4030SetEOFRetry:
4031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4032 (void **) &pSMBr);
4033 if (rc)
4034 return rc;
4035
4036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4037 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004038 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004039 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 name_len++; /* trailing null */
4041 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004042 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 name_len = strnlen(fileName, PATH_MAX);
4044 name_len++; /* trailing null */
4045 strncpy(pSMB->FileName, fileName, name_len);
4046 }
4047 params = 6 + name_len;
4048 data_count = sizeof (struct file_end_of_file_info);
4049 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004050 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 pSMB->MaxSetupCount = 0;
4052 pSMB->Reserved = 0;
4053 pSMB->Flags = 0;
4054 pSMB->Timeout = 0;
4055 pSMB->Reserved2 = 0;
4056 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4057 InformationLevel) - 4;
4058 offset = param_offset + params;
4059 if(SetAllocation) {
4060 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4061 pSMB->InformationLevel =
4062 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4063 else
4064 pSMB->InformationLevel =
4065 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4066 } else /* Set File Size */ {
4067 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4068 pSMB->InformationLevel =
4069 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4070 else
4071 pSMB->InformationLevel =
4072 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4073 }
4074
4075 parm_data =
4076 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4077 offset);
4078 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4079 pSMB->DataOffset = cpu_to_le16(offset);
4080 pSMB->SetupCount = 1;
4081 pSMB->Reserved3 = 0;
4082 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4083 byte_count = 3 /* pad */ + params + data_count;
4084 pSMB->DataCount = cpu_to_le16(data_count);
4085 pSMB->TotalDataCount = pSMB->DataCount;
4086 pSMB->ParameterCount = cpu_to_le16(params);
4087 pSMB->TotalParameterCount = pSMB->ParameterCount;
4088 pSMB->Reserved4 = 0;
4089 pSMB->hdr.smb_buf_length += byte_count;
4090 parm_data->FileSize = cpu_to_le64(size);
4091 pSMB->ByteCount = cpu_to_le16(byte_count);
4092 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4093 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4094 if (rc) {
4095 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4096 }
4097
4098 cifs_buf_release(pSMB);
4099
4100 if (rc == -EAGAIN)
4101 goto SetEOFRetry;
4102
4103 return rc;
4104}
4105
4106int
4107CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4108 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4109{
4110 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4111 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4112 char *data_offset;
4113 struct file_end_of_file_info *parm_data;
4114 int rc = 0;
4115 int bytes_returned = 0;
4116 __u16 params, param_offset, offset, byte_count, count;
4117
4118 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4119 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004120 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4121
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 if (rc)
4123 return rc;
4124
Steve Frenchcd634992005-04-28 22:41:10 -07004125 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4126
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4128 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4129
4130 params = 6;
4131 pSMB->MaxSetupCount = 0;
4132 pSMB->Reserved = 0;
4133 pSMB->Flags = 0;
4134 pSMB->Timeout = 0;
4135 pSMB->Reserved2 = 0;
4136 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4137 offset = param_offset + params;
4138
4139 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4140
4141 count = sizeof(struct file_end_of_file_info);
4142 pSMB->MaxParameterCount = cpu_to_le16(2);
4143 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4144 pSMB->SetupCount = 1;
4145 pSMB->Reserved3 = 0;
4146 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4147 byte_count = 3 /* pad */ + params + count;
4148 pSMB->DataCount = cpu_to_le16(count);
4149 pSMB->ParameterCount = cpu_to_le16(params);
4150 pSMB->TotalDataCount = pSMB->DataCount;
4151 pSMB->TotalParameterCount = pSMB->ParameterCount;
4152 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4153 parm_data =
4154 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4155 offset);
4156 pSMB->DataOffset = cpu_to_le16(offset);
4157 parm_data->FileSize = cpu_to_le64(size);
4158 pSMB->Fid = fid;
4159 if(SetAllocation) {
4160 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4161 pSMB->InformationLevel =
4162 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4163 else
4164 pSMB->InformationLevel =
4165 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4166 } else /* Set File Size */ {
4167 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4168 pSMB->InformationLevel =
4169 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4170 else
4171 pSMB->InformationLevel =
4172 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4173 }
4174 pSMB->Reserved4 = 0;
4175 pSMB->hdr.smb_buf_length += byte_count;
4176 pSMB->ByteCount = cpu_to_le16(byte_count);
4177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4179 if (rc) {
4180 cFYI(1,
4181 ("Send error in SetFileInfo (SetFileSize) = %d",
4182 rc));
4183 }
4184
4185 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004186 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
4188 /* Note: On -EAGAIN error only caller can retry on handle based calls
4189 since file handle passed in no longer valid */
4190
4191 return rc;
4192}
4193
4194/* Some legacy servers such as NT4 require that the file times be set on
4195 an open handle, rather than by pathname - this is awkward due to
4196 potential access conflicts on the open, but it is unavoidable for these
4197 old servers since the only other choice is to go from 100 nanosecond DCE
4198 time and resort to the original setpathinfo level which takes the ancient
4199 DOS time format with 2 second granularity */
4200int
4201CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4202 __u16 fid)
4203{
4204 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4205 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4206 char *data_offset;
4207 int rc = 0;
4208 int bytes_returned = 0;
4209 __u16 params, param_offset, offset, byte_count, count;
4210
4211 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004212 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4213
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 if (rc)
4215 return rc;
4216
Steve Frenchcd634992005-04-28 22:41:10 -07004217 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4218
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 /* At this point there is no need to override the current pid
4220 with the pid of the opener, but that could change if we someday
4221 use an existing handle (rather than opening one on the fly) */
4222 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4223 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4224
4225 params = 6;
4226 pSMB->MaxSetupCount = 0;
4227 pSMB->Reserved = 0;
4228 pSMB->Flags = 0;
4229 pSMB->Timeout = 0;
4230 pSMB->Reserved2 = 0;
4231 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4232 offset = param_offset + params;
4233
4234 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4235
4236 count = sizeof (FILE_BASIC_INFO);
4237 pSMB->MaxParameterCount = cpu_to_le16(2);
4238 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4239 pSMB->SetupCount = 1;
4240 pSMB->Reserved3 = 0;
4241 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4242 byte_count = 3 /* pad */ + params + count;
4243 pSMB->DataCount = cpu_to_le16(count);
4244 pSMB->ParameterCount = cpu_to_le16(params);
4245 pSMB->TotalDataCount = pSMB->DataCount;
4246 pSMB->TotalParameterCount = pSMB->ParameterCount;
4247 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4248 pSMB->DataOffset = cpu_to_le16(offset);
4249 pSMB->Fid = fid;
4250 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4251 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4252 else
4253 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4254 pSMB->Reserved4 = 0;
4255 pSMB->hdr.smb_buf_length += byte_count;
4256 pSMB->ByteCount = cpu_to_le16(byte_count);
4257 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4259 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4260 if (rc) {
4261 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4262 }
4263
Steve Frenchcd634992005-04-28 22:41:10 -07004264 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265
4266 /* Note: On -EAGAIN error only caller can retry on handle based calls
4267 since file handle passed in no longer valid */
4268
4269 return rc;
4270}
4271
4272
4273int
4274CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4275 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004276 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277{
4278 TRANSACTION2_SPI_REQ *pSMB = NULL;
4279 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4280 int name_len;
4281 int rc = 0;
4282 int bytes_returned = 0;
4283 char *data_offset;
4284 __u16 params, param_offset, offset, byte_count, count;
4285
4286 cFYI(1, ("In SetTimes"));
4287
4288SetTimesRetry:
4289 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4290 (void **) &pSMBr);
4291 if (rc)
4292 return rc;
4293
4294 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4295 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004296 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004297 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 name_len++; /* trailing null */
4299 name_len *= 2;
4300 } else { /* BB improve the check for buffer overruns BB */
4301 name_len = strnlen(fileName, PATH_MAX);
4302 name_len++; /* trailing null */
4303 strncpy(pSMB->FileName, fileName, name_len);
4304 }
4305
4306 params = 6 + name_len;
4307 count = sizeof (FILE_BASIC_INFO);
4308 pSMB->MaxParameterCount = cpu_to_le16(2);
4309 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4310 pSMB->MaxSetupCount = 0;
4311 pSMB->Reserved = 0;
4312 pSMB->Flags = 0;
4313 pSMB->Timeout = 0;
4314 pSMB->Reserved2 = 0;
4315 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4316 InformationLevel) - 4;
4317 offset = param_offset + params;
4318 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4319 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4320 pSMB->DataOffset = cpu_to_le16(offset);
4321 pSMB->SetupCount = 1;
4322 pSMB->Reserved3 = 0;
4323 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4324 byte_count = 3 /* pad */ + params + count;
4325
4326 pSMB->DataCount = cpu_to_le16(count);
4327 pSMB->ParameterCount = cpu_to_le16(params);
4328 pSMB->TotalDataCount = pSMB->DataCount;
4329 pSMB->TotalParameterCount = pSMB->ParameterCount;
4330 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4331 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4332 else
4333 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4334 pSMB->Reserved4 = 0;
4335 pSMB->hdr.smb_buf_length += byte_count;
4336 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4337 pSMB->ByteCount = cpu_to_le16(byte_count);
4338 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4339 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4340 if (rc) {
4341 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4342 }
4343
4344 cifs_buf_release(pSMB);
4345
4346 if (rc == -EAGAIN)
4347 goto SetTimesRetry;
4348
4349 return rc;
4350}
4351
4352/* Can not be used to set time stamps yet (due to old DOS time format) */
4353/* Can be used to set attributes */
4354#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4355 handling it anyway and NT4 was what we thought it would be needed for
4356 Do not delete it until we prove whether needed for Win9x though */
4357int
4358CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4359 __u16 dos_attrs, const struct nls_table *nls_codepage)
4360{
4361 SETATTR_REQ *pSMB = NULL;
4362 SETATTR_RSP *pSMBr = NULL;
4363 int rc = 0;
4364 int bytes_returned;
4365 int name_len;
4366
4367 cFYI(1, ("In SetAttrLegacy"));
4368
4369SetAttrLgcyRetry:
4370 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4371 (void **) &pSMBr);
4372 if (rc)
4373 return rc;
4374
4375 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4376 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004377 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 PATH_MAX, nls_codepage);
4379 name_len++; /* trailing null */
4380 name_len *= 2;
4381 } else { /* BB improve the check for buffer overruns BB */
4382 name_len = strnlen(fileName, PATH_MAX);
4383 name_len++; /* trailing null */
4384 strncpy(pSMB->fileName, fileName, name_len);
4385 }
4386 pSMB->attr = cpu_to_le16(dos_attrs);
4387 pSMB->BufferFormat = 0x04;
4388 pSMB->hdr.smb_buf_length += name_len + 1;
4389 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4391 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4392 if (rc) {
4393 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4394 }
4395
4396 cifs_buf_release(pSMB);
4397
4398 if (rc == -EAGAIN)
4399 goto SetAttrLgcyRetry;
4400
4401 return rc;
4402}
4403#endif /* temporarily unneeded SetAttr legacy function */
4404
4405int
4406CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004407 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4408 dev_t device, const struct nls_table *nls_codepage,
4409 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410{
4411 TRANSACTION2_SPI_REQ *pSMB = NULL;
4412 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4413 int name_len;
4414 int rc = 0;
4415 int bytes_returned = 0;
4416 FILE_UNIX_BASIC_INFO *data_offset;
4417 __u16 params, param_offset, offset, count, byte_count;
4418
4419 cFYI(1, ("In SetUID/GID/Mode"));
4420setPermsRetry:
4421 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4422 (void **) &pSMBr);
4423 if (rc)
4424 return rc;
4425
4426 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4427 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004428 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004429 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 name_len++; /* trailing null */
4431 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004432 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 name_len = strnlen(fileName, PATH_MAX);
4434 name_len++; /* trailing null */
4435 strncpy(pSMB->FileName, fileName, name_len);
4436 }
4437
4438 params = 6 + name_len;
4439 count = sizeof (FILE_UNIX_BASIC_INFO);
4440 pSMB->MaxParameterCount = cpu_to_le16(2);
4441 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4442 pSMB->MaxSetupCount = 0;
4443 pSMB->Reserved = 0;
4444 pSMB->Flags = 0;
4445 pSMB->Timeout = 0;
4446 pSMB->Reserved2 = 0;
4447 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4448 InformationLevel) - 4;
4449 offset = param_offset + params;
4450 data_offset =
4451 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4452 offset);
4453 memset(data_offset, 0, count);
4454 pSMB->DataOffset = cpu_to_le16(offset);
4455 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4456 pSMB->SetupCount = 1;
4457 pSMB->Reserved3 = 0;
4458 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4459 byte_count = 3 /* pad */ + params + count;
4460 pSMB->ParameterCount = cpu_to_le16(params);
4461 pSMB->DataCount = cpu_to_le16(count);
4462 pSMB->TotalParameterCount = pSMB->ParameterCount;
4463 pSMB->TotalDataCount = pSMB->DataCount;
4464 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4465 pSMB->Reserved4 = 0;
4466 pSMB->hdr.smb_buf_length += byte_count;
4467 data_offset->Uid = cpu_to_le64(uid);
4468 data_offset->Gid = cpu_to_le64(gid);
4469 /* better to leave device as zero when it is */
4470 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4471 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4472 data_offset->Permissions = cpu_to_le64(mode);
4473
4474 if(S_ISREG(mode))
4475 data_offset->Type = cpu_to_le32(UNIX_FILE);
4476 else if(S_ISDIR(mode))
4477 data_offset->Type = cpu_to_le32(UNIX_DIR);
4478 else if(S_ISLNK(mode))
4479 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4480 else if(S_ISCHR(mode))
4481 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4482 else if(S_ISBLK(mode))
4483 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4484 else if(S_ISFIFO(mode))
4485 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4486 else if(S_ISSOCK(mode))
4487 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4488
4489
4490 pSMB->ByteCount = cpu_to_le16(byte_count);
4491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4493 if (rc) {
4494 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4495 }
4496
4497 if (pSMB)
4498 cifs_buf_release(pSMB);
4499 if (rc == -EAGAIN)
4500 goto setPermsRetry;
4501 return rc;
4502}
4503
4504int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004505 const int notify_subdirs, const __u16 netfid,
4506 __u32 filter, struct file * pfile, int multishot,
4507 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508{
4509 int rc = 0;
4510 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004511 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004512 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 int bytes_returned;
4514
4515 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4516 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4517 (void **) &pSMBr);
4518 if (rc)
4519 return rc;
4520
4521 pSMB->TotalParameterCount = 0 ;
4522 pSMB->TotalDataCount = 0;
4523 pSMB->MaxParameterCount = cpu_to_le32(2);
4524 /* BB find exact data count max from sess structure BB */
4525 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004526/* BB VERIFY verify which is correct for above BB */
4527 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4528 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4529
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 pSMB->MaxSetupCount = 4;
4531 pSMB->Reserved = 0;
4532 pSMB->ParameterOffset = 0;
4533 pSMB->DataCount = 0;
4534 pSMB->DataOffset = 0;
4535 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4536 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4537 pSMB->ParameterCount = pSMB->TotalParameterCount;
4538 if(notify_subdirs)
4539 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4540 pSMB->Reserved2 = 0;
4541 pSMB->CompletionFilter = cpu_to_le32(filter);
4542 pSMB->Fid = netfid; /* file handle always le */
4543 pSMB->ByteCount = 0;
4544
4545 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4546 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4547 if (rc) {
4548 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004549 } else {
4550 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004551 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004552 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004553 sizeof(struct dir_notify_req),
4554 GFP_KERNEL);
4555 if(dnotify_req) {
4556 dnotify_req->Pid = pSMB->hdr.Pid;
4557 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4558 dnotify_req->Mid = pSMB->hdr.Mid;
4559 dnotify_req->Tid = pSMB->hdr.Tid;
4560 dnotify_req->Uid = pSMB->hdr.Uid;
4561 dnotify_req->netfid = netfid;
4562 dnotify_req->pfile = pfile;
4563 dnotify_req->filter = filter;
4564 dnotify_req->multishot = multishot;
4565 spin_lock(&GlobalMid_Lock);
4566 list_add_tail(&dnotify_req->lhead,
4567 &GlobalDnotifyReqList);
4568 spin_unlock(&GlobalMid_Lock);
4569 } else
4570 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 }
4572 cifs_buf_release(pSMB);
4573 return rc;
4574}
4575#ifdef CONFIG_CIFS_XATTR
4576ssize_t
4577CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4578 const unsigned char *searchName,
4579 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004580 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581{
4582 /* BB assumes one setup word */
4583 TRANSACTION2_QPI_REQ *pSMB = NULL;
4584 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4585 int rc = 0;
4586 int bytes_returned;
4587 int name_len;
4588 struct fea * temp_fea;
4589 char * temp_ptr;
4590 __u16 params, byte_count;
4591
4592 cFYI(1, ("In Query All EAs path %s", searchName));
4593QAllEAsRetry:
4594 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4595 (void **) &pSMBr);
4596 if (rc)
4597 return rc;
4598
4599 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4600 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004601 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004602 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 name_len++; /* trailing null */
4604 name_len *= 2;
4605 } else { /* BB improve the check for buffer overruns BB */
4606 name_len = strnlen(searchName, PATH_MAX);
4607 name_len++; /* trailing null */
4608 strncpy(pSMB->FileName, searchName, name_len);
4609 }
4610
4611 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4612 pSMB->TotalDataCount = 0;
4613 pSMB->MaxParameterCount = cpu_to_le16(2);
4614 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4615 pSMB->MaxSetupCount = 0;
4616 pSMB->Reserved = 0;
4617 pSMB->Flags = 0;
4618 pSMB->Timeout = 0;
4619 pSMB->Reserved2 = 0;
4620 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4621 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4622 pSMB->DataCount = 0;
4623 pSMB->DataOffset = 0;
4624 pSMB->SetupCount = 1;
4625 pSMB->Reserved3 = 0;
4626 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4627 byte_count = params + 1 /* pad */ ;
4628 pSMB->TotalParameterCount = cpu_to_le16(params);
4629 pSMB->ParameterCount = pSMB->TotalParameterCount;
4630 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4631 pSMB->Reserved4 = 0;
4632 pSMB->hdr.smb_buf_length += byte_count;
4633 pSMB->ByteCount = cpu_to_le16(byte_count);
4634
4635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4637 if (rc) {
4638 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4639 } else { /* decode response */
4640 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4641
4642 /* BB also check enough total bytes returned */
4643 /* BB we need to improve the validity checking
4644 of these trans2 responses */
4645 if (rc || (pSMBr->ByteCount < 4))
4646 rc = -EIO; /* bad smb */
4647 /* else if (pFindData){
4648 memcpy((char *) pFindData,
4649 (char *) &pSMBr->hdr.Protocol +
4650 data_offset, kl);
4651 }*/ else {
4652 /* check that length of list is not more than bcc */
4653 /* check that each entry does not go beyond length
4654 of list */
4655 /* check that each element of each entry does not
4656 go beyond end of list */
4657 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4658 struct fealist * ea_response_data;
4659 rc = 0;
4660 /* validate_trans2_offsets() */
4661 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4662 ea_response_data = (struct fealist *)
4663 (((char *) &pSMBr->hdr.Protocol) +
4664 data_offset);
4665 name_len = le32_to_cpu(ea_response_data->list_len);
4666 cFYI(1,("ea length %d", name_len));
4667 if(name_len <= 8) {
4668 /* returned EA size zeroed at top of function */
4669 cFYI(1,("empty EA list returned from server"));
4670 } else {
4671 /* account for ea list len */
4672 name_len -= 4;
4673 temp_fea = ea_response_data->list;
4674 temp_ptr = (char *)temp_fea;
4675 while(name_len > 0) {
4676 __u16 value_len;
4677 name_len -= 4;
4678 temp_ptr += 4;
4679 rc += temp_fea->name_len;
4680 /* account for prefix user. and trailing null */
4681 rc = rc + 5 + 1;
4682 if(rc<(int)buf_size) {
4683 memcpy(EAData,"user.",5);
4684 EAData+=5;
4685 memcpy(EAData,temp_ptr,temp_fea->name_len);
4686 EAData+=temp_fea->name_len;
4687 /* null terminate name */
4688 *EAData = 0;
4689 EAData = EAData + 1;
4690 } else if(buf_size == 0) {
4691 /* skip copy - calc size only */
4692 } else {
4693 /* stop before overrun buffer */
4694 rc = -ERANGE;
4695 break;
4696 }
4697 name_len -= temp_fea->name_len;
4698 temp_ptr += temp_fea->name_len;
4699 /* account for trailing null */
4700 name_len--;
4701 temp_ptr++;
4702 value_len = le16_to_cpu(temp_fea->value_len);
4703 name_len -= value_len;
4704 temp_ptr += value_len;
4705 /* BB check that temp_ptr is still within smb BB*/
4706 /* no trailing null to account for in value len */
4707 /* go on to next EA */
4708 temp_fea = (struct fea *)temp_ptr;
4709 }
4710 }
4711 }
4712 }
4713 if (pSMB)
4714 cifs_buf_release(pSMB);
4715 if (rc == -EAGAIN)
4716 goto QAllEAsRetry;
4717
4718 return (ssize_t)rc;
4719}
4720
4721ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4722 const unsigned char * searchName,const unsigned char * ea_name,
4723 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004724 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725{
4726 TRANSACTION2_QPI_REQ *pSMB = NULL;
4727 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4728 int rc = 0;
4729 int bytes_returned;
4730 int name_len;
4731 struct fea * temp_fea;
4732 char * temp_ptr;
4733 __u16 params, byte_count;
4734
4735 cFYI(1, ("In Query EA path %s", searchName));
4736QEARetry:
4737 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4738 (void **) &pSMBr);
4739 if (rc)
4740 return rc;
4741
4742 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4743 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004744 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004745 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 name_len++; /* trailing null */
4747 name_len *= 2;
4748 } else { /* BB improve the check for buffer overruns BB */
4749 name_len = strnlen(searchName, PATH_MAX);
4750 name_len++; /* trailing null */
4751 strncpy(pSMB->FileName, searchName, name_len);
4752 }
4753
4754 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4755 pSMB->TotalDataCount = 0;
4756 pSMB->MaxParameterCount = cpu_to_le16(2);
4757 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4758 pSMB->MaxSetupCount = 0;
4759 pSMB->Reserved = 0;
4760 pSMB->Flags = 0;
4761 pSMB->Timeout = 0;
4762 pSMB->Reserved2 = 0;
4763 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4764 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4765 pSMB->DataCount = 0;
4766 pSMB->DataOffset = 0;
4767 pSMB->SetupCount = 1;
4768 pSMB->Reserved3 = 0;
4769 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4770 byte_count = params + 1 /* pad */ ;
4771 pSMB->TotalParameterCount = cpu_to_le16(params);
4772 pSMB->ParameterCount = pSMB->TotalParameterCount;
4773 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4774 pSMB->Reserved4 = 0;
4775 pSMB->hdr.smb_buf_length += byte_count;
4776 pSMB->ByteCount = cpu_to_le16(byte_count);
4777
4778 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4779 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4780 if (rc) {
4781 cFYI(1, ("Send error in Query EA = %d", rc));
4782 } else { /* decode response */
4783 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4784
4785 /* BB also check enough total bytes returned */
4786 /* BB we need to improve the validity checking
4787 of these trans2 responses */
4788 if (rc || (pSMBr->ByteCount < 4))
4789 rc = -EIO; /* bad smb */
4790 /* else if (pFindData){
4791 memcpy((char *) pFindData,
4792 (char *) &pSMBr->hdr.Protocol +
4793 data_offset, kl);
4794 }*/ else {
4795 /* check that length of list is not more than bcc */
4796 /* check that each entry does not go beyond length
4797 of list */
4798 /* check that each element of each entry does not
4799 go beyond end of list */
4800 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4801 struct fealist * ea_response_data;
4802 rc = -ENODATA;
4803 /* validate_trans2_offsets() */
4804 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4805 ea_response_data = (struct fealist *)
4806 (((char *) &pSMBr->hdr.Protocol) +
4807 data_offset);
4808 name_len = le32_to_cpu(ea_response_data->list_len);
4809 cFYI(1,("ea length %d", name_len));
4810 if(name_len <= 8) {
4811 /* returned EA size zeroed at top of function */
4812 cFYI(1,("empty EA list returned from server"));
4813 } else {
4814 /* account for ea list len */
4815 name_len -= 4;
4816 temp_fea = ea_response_data->list;
4817 temp_ptr = (char *)temp_fea;
4818 /* loop through checking if we have a matching
4819 name and then return the associated value */
4820 while(name_len > 0) {
4821 __u16 value_len;
4822 name_len -= 4;
4823 temp_ptr += 4;
4824 value_len = le16_to_cpu(temp_fea->value_len);
4825 /* BB validate that value_len falls within SMB,
4826 even though maximum for name_len is 255 */
4827 if(memcmp(temp_fea->name,ea_name,
4828 temp_fea->name_len) == 0) {
4829 /* found a match */
4830 rc = value_len;
4831 /* account for prefix user. and trailing null */
4832 if(rc<=(int)buf_size) {
4833 memcpy(ea_value,
4834 temp_fea->name+temp_fea->name_len+1,
4835 rc);
4836 /* ea values, unlike ea names,
4837 are not null terminated */
4838 } else if(buf_size == 0) {
4839 /* skip copy - calc size only */
4840 } else {
4841 /* stop before overrun buffer */
4842 rc = -ERANGE;
4843 }
4844 break;
4845 }
4846 name_len -= temp_fea->name_len;
4847 temp_ptr += temp_fea->name_len;
4848 /* account for trailing null */
4849 name_len--;
4850 temp_ptr++;
4851 name_len -= value_len;
4852 temp_ptr += value_len;
4853 /* no trailing null to account for in value len */
4854 /* go on to next EA */
4855 temp_fea = (struct fea *)temp_ptr;
4856 }
4857 }
4858 }
4859 }
4860 if (pSMB)
4861 cifs_buf_release(pSMB);
4862 if (rc == -EAGAIN)
4863 goto QEARetry;
4864
4865 return (ssize_t)rc;
4866}
4867
4868int
4869CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4870 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004871 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4872 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873{
4874 struct smb_com_transaction2_spi_req *pSMB = NULL;
4875 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4876 struct fealist *parm_data;
4877 int name_len;
4878 int rc = 0;
4879 int bytes_returned = 0;
4880 __u16 params, param_offset, byte_count, offset, count;
4881
4882 cFYI(1, ("In SetEA"));
4883SetEARetry:
4884 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4885 (void **) &pSMBr);
4886 if (rc)
4887 return rc;
4888
4889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4890 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004891 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004892 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 name_len++; /* trailing null */
4894 name_len *= 2;
4895 } else { /* BB improve the check for buffer overruns BB */
4896 name_len = strnlen(fileName, PATH_MAX);
4897 name_len++; /* trailing null */
4898 strncpy(pSMB->FileName, fileName, name_len);
4899 }
4900
4901 params = 6 + name_len;
4902
4903 /* done calculating parms using name_len of file name,
4904 now use name_len to calculate length of ea name
4905 we are going to create in the inode xattrs */
4906 if(ea_name == NULL)
4907 name_len = 0;
4908 else
4909 name_len = strnlen(ea_name,255);
4910
4911 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4912 pSMB->MaxParameterCount = cpu_to_le16(2);
4913 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4914 pSMB->MaxSetupCount = 0;
4915 pSMB->Reserved = 0;
4916 pSMB->Flags = 0;
4917 pSMB->Timeout = 0;
4918 pSMB->Reserved2 = 0;
4919 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4920 InformationLevel) - 4;
4921 offset = param_offset + params;
4922 pSMB->InformationLevel =
4923 cpu_to_le16(SMB_SET_FILE_EA);
4924
4925 parm_data =
4926 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4927 offset);
4928 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4929 pSMB->DataOffset = cpu_to_le16(offset);
4930 pSMB->SetupCount = 1;
4931 pSMB->Reserved3 = 0;
4932 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4933 byte_count = 3 /* pad */ + params + count;
4934 pSMB->DataCount = cpu_to_le16(count);
4935 parm_data->list_len = cpu_to_le32(count);
4936 parm_data->list[0].EA_flags = 0;
4937 /* we checked above that name len is less than 255 */
4938 parm_data->list[0].name_len = (__u8)name_len;;
4939 /* EA names are always ASCII */
4940 if(ea_name)
4941 strncpy(parm_data->list[0].name,ea_name,name_len);
4942 parm_data->list[0].name[name_len] = 0;
4943 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4944 /* caller ensures that ea_value_len is less than 64K but
4945 we need to ensure that it fits within the smb */
4946
4947 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4948 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4949 if(ea_value_len)
4950 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4951
4952 pSMB->TotalDataCount = pSMB->DataCount;
4953 pSMB->ParameterCount = cpu_to_le16(params);
4954 pSMB->TotalParameterCount = pSMB->ParameterCount;
4955 pSMB->Reserved4 = 0;
4956 pSMB->hdr.smb_buf_length += byte_count;
4957 pSMB->ByteCount = cpu_to_le16(byte_count);
4958 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4959 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4960 if (rc) {
4961 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4962 }
4963
4964 cifs_buf_release(pSMB);
4965
4966 if (rc == -EAGAIN)
4967 goto SetEARetry;
4968
4969 return rc;
4970}
4971
4972#endif