blob: b8c236be4d85e6ab9b2e31db32b801609af28dce [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[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000051 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 {BAD_PROT, "\2"}
53};
54#else
55static struct {
56 int index;
57 char *name;
58} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000059#ifdef CONFIG_CIFS_WEAK_PW_HASH
60 {LANMAN_PROT, "\2LM1.2X002"},
61#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 {CIFS_PROT, "\2NT LM 0.12"},
63 {BAD_PROT, "\2"}
64};
65#endif
66
Steve French39798772006-05-31 22:40:51 +000067/* define the number of elements in the cifs dialect array */
68#ifdef CONFIG_CIFS_POSIX
69#ifdef CONFIG_CIFS_WEAK_PW_HASH
70#define CIFS_NUM_PROT 3
71#else
72#define CIFS_NUM_PROT 2
73#endif /* CIFS_WEAK_PW_HASH */
74#else /* not posix */
75#ifdef CONFIG_CIFS_WEAK_PW_HASH
76#define CIFS_NUM_PROT 2
77#else
78#define CIFS_NUM_PROT 1
79#endif /* CONFIG_CIFS_WEAK_PW_HASH */
80#endif /* CIFS_POSIX */
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83/* Mark as invalid, all open files on tree connections since they
84 were closed when session to server was lost */
85static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
86{
87 struct cifsFileInfo *open_file = NULL;
88 struct list_head * tmp;
89 struct list_head * tmp1;
90
91/* list all files open on tree connection and mark them invalid */
92 write_lock(&GlobalSMBSeslock);
93 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
94 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
95 if(open_file) {
96 open_file->invalidHandle = TRUE;
97 }
98 }
99 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
104/* If the return code is zero, this function must fill in request_buf pointer */
105static int
106small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
107 void **request_buf /* returned */)
108{
109 int rc = 0;
110
111 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
112 check for tcp and smb session status done differently
113 for those three - in the calling routine */
114 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800115 if(tcon->tidStatus == CifsExiting) {
116 /* only tree disconnect, open, and write,
117 (and ulogoff which does not have tcon)
118 are allowed as we start force umount */
119 if((smb_command != SMB_COM_WRITE_ANDX) &&
120 (smb_command != SMB_COM_OPEN_ANDX) &&
121 (smb_command != SMB_COM_TREE_DISCONNECT)) {
122 cFYI(1,("can not send cmd %d while umounting",
123 smb_command));
124 return -ENODEV;
125 }
126 }
Steve French31ca3bc2005-04-28 22:41:11 -0700127 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
128 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 struct nls_table *nls_codepage;
130 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700131 reconnect, should be greater than cifs socket
132 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
134 wait_event_interruptible_timeout(tcon->ses->server->response_q,
135 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
136 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
137 /* on "soft" mounts we wait once */
138 if((tcon->retry == FALSE) ||
139 (tcon->ses->status == CifsExiting)) {
140 cFYI(1,("gave up waiting on reconnect in smb_init"));
141 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700142 } /* else "hard" mount - keep retrying
143 until process is killed or server
144 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 } else /* TCP session is reestablished now */
146 break;
147
148 }
149
150 nls_codepage = load_nls_default();
151 /* need to prevent multiple threads trying to
152 simultaneously reconnect the same SMB session */
153 down(&tcon->ses->sesSem);
154 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700155 rc = cifs_setup_session(0, tcon->ses,
156 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
158 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700159 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
160 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700162 /* BB FIXME add code to check if wsize needs
163 update due to negotiated smb buffer size
164 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 if(rc == 0)
166 atomic_inc(&tconInfoReconnectCount);
167
168 cFYI(1, ("reconnect tcon rc = %d", rc));
169 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700170 it is safer (and faster) to reopen files
171 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700174 know whether we can continue or not without
175 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 switch(smb_command) {
177 case SMB_COM_READ_ANDX:
178 case SMB_COM_WRITE_ANDX:
179 case SMB_COM_CLOSE:
180 case SMB_COM_FIND_CLOSE2:
181 case SMB_COM_LOCKING_ANDX: {
182 unload_nls(nls_codepage);
183 return -EAGAIN;
184 }
185 }
186 } else {
187 up(&tcon->ses->sesSem);
188 }
189 unload_nls(nls_codepage);
190
191 } else {
192 return -EIO;
193 }
194 }
195 if(rc)
196 return rc;
197
198 *request_buf = cifs_small_buf_get();
199 if (*request_buf == NULL) {
200 /* BB should we add a retry in here if not a writepage? */
201 return -ENOMEM;
202 }
203
204 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
205
Steve Frencha4544342005-08-24 13:59:35 -0700206 if(tcon != NULL)
207 cifs_stats_inc(&tcon->num_smbs_sent);
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000210}
211
212#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French12b3b8f2006-02-09 21:12:47 +0000213int
Steve French5815449d2006-02-14 01:36:20 +0000214small_smb_init_no_tc(const int smb_command, const int wct,
215 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000216{
217 int rc;
218 struct smb_hdr * buffer;
219
Steve French5815449d2006-02-14 01:36:20 +0000220 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000221 if(rc)
222 return rc;
223
Steve French04fdabe2006-02-10 05:52:50 +0000224 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000225 buffer->Mid = GetNextMid(ses->server);
226 if (ses->capabilities & CAP_UNICODE)
227 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000228 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000229 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
230
231 /* uid, tid can stay at zero as set in header assemble */
232
233 /* BB add support for turning on the signing when
234 this function is used after 1st of session setup requests */
235
236 return rc;
237}
Steve French5815449d2006-02-14 01:36:20 +0000238#endif /* CONFIG_CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240/* If the return code is zero, this function must fill in request_buf pointer */
241static int
242smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
243 void **request_buf /* returned */ ,
244 void **response_buf /* returned */ )
245{
246 int rc = 0;
247
248 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
249 check for tcp and smb session status done differently
250 for those three - in the calling routine */
251 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800252 if(tcon->tidStatus == CifsExiting) {
253 /* only tree disconnect, open, and write,
254 (and ulogoff which does not have tcon)
255 are allowed as we start force umount */
256 if((smb_command != SMB_COM_WRITE_ANDX) &&
257 (smb_command != SMB_COM_OPEN_ANDX) &&
258 (smb_command != SMB_COM_TREE_DISCONNECT)) {
259 cFYI(1,("can not send cmd %d while umounting",
260 smb_command));
261 return -ENODEV;
262 }
263 }
264
Steve French31ca3bc2005-04-28 22:41:11 -0700265 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
266 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700268 /* Give Demultiplex thread up to 10 seconds to
269 reconnect, should be greater than cifs socket
270 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
272 wait_event_interruptible_timeout(tcon->ses->server->response_q,
273 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700274 if(tcon->ses->server->tcpStatus ==
275 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* on "soft" mounts we wait once */
277 if((tcon->retry == FALSE) ||
278 (tcon->ses->status == CifsExiting)) {
279 cFYI(1,("gave up waiting on reconnect in smb_init"));
280 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700281 } /* else "hard" mount - keep retrying
282 until process is killed or server
283 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 } else /* TCP session is reestablished now */
285 break;
286
287 }
288
289 nls_codepage = load_nls_default();
290 /* need to prevent multiple threads trying to
291 simultaneously reconnect the same SMB session */
292 down(&tcon->ses->sesSem);
293 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700294 rc = cifs_setup_session(0, tcon->ses,
295 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
297 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700298 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
299 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700301 /* BB FIXME add code to check if wsize needs
302 update due to negotiated smb buffer size
303 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 if(rc == 0)
305 atomic_inc(&tconInfoReconnectCount);
306
307 cFYI(1, ("reconnect tcon rc = %d", rc));
308 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700309 it is safer (and faster) to reopen files
310 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700313 know whether we can continue or not without
314 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 switch(smb_command) {
316 case SMB_COM_READ_ANDX:
317 case SMB_COM_WRITE_ANDX:
318 case SMB_COM_CLOSE:
319 case SMB_COM_FIND_CLOSE2:
320 case SMB_COM_LOCKING_ANDX: {
321 unload_nls(nls_codepage);
322 return -EAGAIN;
323 }
324 }
325 } else {
326 up(&tcon->ses->sesSem);
327 }
328 unload_nls(nls_codepage);
329
330 } else {
331 return -EIO;
332 }
333 }
334 if(rc)
335 return rc;
336
337 *request_buf = cifs_buf_get();
338 if (*request_buf == NULL) {
339 /* BB should we add a retry in here if not a writepage? */
340 return -ENOMEM;
341 }
342 /* Although the original thought was we needed the response buf for */
343 /* potential retries of smb operations it turns out we can determine */
344 /* from the mid flags when the request buffer can be resent without */
345 /* having to use a second distinct buffer for the response */
Steve French39798772006-05-31 22:40:51 +0000346 if(response_buf)
347 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
350 wct /*wct */ );
351
Steve Frencha4544342005-08-24 13:59:35 -0700352 if(tcon != NULL)
353 cifs_stats_inc(&tcon->num_smbs_sent);
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return rc;
356}
357
358static int validate_t2(struct smb_t2_rsp * pSMB)
359{
360 int rc = -EINVAL;
361 int total_size;
362 char * pBCC;
363
364 /* check for plausible wct, bcc and t2 data and parm sizes */
365 /* check for parm and data offset going beyond end of smb */
366 if(pSMB->hdr.WordCount >= 10) {
367 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
368 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
369 /* check that bcc is at least as big as parms + data */
370 /* check that bcc is less than negotiated smb buffer */
371 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
372 if(total_size < 512) {
373 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
374 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700375 pBCC = (pSMB->hdr.WordCount * 2) +
376 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 (char *)pSMB;
378 if((total_size <= (*(u16 *)pBCC)) &&
379 (total_size <
380 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
381 return 0;
382 }
383
384 }
385 }
386 }
387 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
388 sizeof(struct smb_t2_rsp) + 16);
389 return rc;
390}
391int
392CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
393{
394 NEGOTIATE_REQ *pSMB;
395 NEGOTIATE_RSP *pSMBr;
396 int rc = 0;
397 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000398 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 struct TCP_Server_Info * server;
400 u16 count;
401
402 if(ses->server)
403 server = ses->server;
404 else {
405 rc = -EIO;
406 return rc;
407 }
408 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
409 (void **) &pSMB, (void **) &pSMBr);
410 if (rc)
411 return rc;
Steve French1982c342005-08-17 12:38:22 -0700412 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French39798772006-05-31 22:40:51 +0000414/* if (extended_security)
415 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/
416
417 count = 0;
418 for(i=0;i<CIFS_NUM_PROT;i++) {
419 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
420 count += strlen(protocols[i].name) + 1;
421 /* null at end of source and target buffers anyway */
422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->hdr.smb_buf_length += count;
424 pSMB->ByteCount = cpu_to_le16(count);
425
426 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
428 if (rc == 0) {
Steve French39798772006-05-31 22:40:51 +0000429 cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
430 /* Check wct = 1 error case */
431 if((pSMBr->hdr.WordCount < 13)
432 || (pSMBr->DialectIndex == BAD_PROT)) {
433 /* core returns wct = 1, but we do not ask for
434 core - otherwise it just comes when dialect
435 index is -1 indicating we could not negotiate
436 a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
Steve French3856a9d2006-06-01 19:38:46 +0000439#ifdef CONFIG_CIFS_WEAK_PW_HASH
440 } else if((pSMBr->hdr.WordCount == 13)
441 && (pSMBr->DialectIndex == LANMAN_PROT)) {
Steve French39798772006-05-31 22:40:51 +0000442 struct lanman_neg_rsp * rsp =
443 (struct lanman_neg_rsp *)pSMBr;
444
Steve French7c7b25b2006-06-01 19:20:10 +0000445 if((extended_security & CIFSSEC_MAY_LANMAN) ||
446 (extended_security & CIFSSEC_MAY_PLNTXT))
447 server->secType = LANMAN;
448 else {
449 cERROR(1, ("mount failed weak security disabled"
450 " in /proc/fs/cifs/SecurityFlags"));
451 rc = -EOPNOTSUPP;
452 goto neg_err_exit;
453 }
Steve French39798772006-05-31 22:40:51 +0000454 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
455 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
456 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
457 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
458
459 /* BB what do we do with raw mode? BB */
460 server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
461 /* Do we have to set signing flags? no signing
462 was available LANMAN - default should be ok */
463
464 /* BB FIXME set default dummy capabilities since
465 they are not returned by the server in this dialect */
466
467 /* get server time for time conversions and add
468 code to use it and timezone since this is not UTC */
469
470 if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
471 memcpy(server->cryptKey, rsp->EncryptionKey,
472 CIFS_CRYPTO_KEY_SIZE);
473 } else {
474 rc = -EIO;
475 goto neg_err_exit;
476 }
477
478 cFYI(1,("LANMAN negotiated")); /* BB removeme BB */
Steve French7c7b25b2006-06-01 19:20:10 +0000479#else /* weak security disabled */
Steve French7a0d2232006-06-01 19:44:37 +0000480 } else if(pSMBr->hdr.WordCount == 13) {
Steve French3856a9d2006-06-01 19:38:46 +0000481 cERROR(1,("mount failed, cifs module not built "
482 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000483 rc = -EOPNOTSUPP;
484#endif /* WEAK_PW_HASH */
Steve French39798772006-05-31 22:40:51 +0000485 goto neg_err_exit;
486 } else if(pSMBr->hdr.WordCount != 17) {
487 /* unknown wct */
488 rc = -EOPNOTSUPP;
489 goto neg_err_exit;
490 }
491
Steve Frencheeac8042006-01-13 21:34:58 -0800492 server->secMode = pSMBr->SecurityMode;
493 if((server->secMode & SECMODE_USER) == 0)
494 cFYI(1,("share mode security"));
Steve French7c7b25b2006-06-01 19:20:10 +0000495
496 if(extended_security & CIFSSEC_MUST_NTLMV2)
497 server->secType = NTLMv2;
498 else
499 server->secType = NTLM;
500 /* else krb5 ... */
501
Steve French09d1db52005-04-28 22:41:08 -0700502 /* one byte - no need to convert this or EncryptionKeyLen
503 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
505 /* probably no need to store and check maxvcs */
506 server->maxBuf =
507 min(le32_to_cpu(pSMBr->MaxBufferSize),
508 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
509 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve Frencheeac8042006-01-13 21:34:58 -0800510 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
512 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
513 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
514 /* BB with UTC do we ever need to be using srvr timezone? */
515 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
516 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
517 CIFS_CRYPTO_KEY_SIZE);
518 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
519 && (pSMBr->EncryptionKeyLength == 0)) {
520 /* decode security blob */
521 } else
522 rc = -EIO;
523
524 /* BB might be helpful to save off the domain of server here */
525
526 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
527 (server->capabilities & CAP_EXTENDED_SECURITY)) {
528 count = pSMBr->ByteCount;
529 if (count < 16)
530 rc = -EIO;
531 else if (count == 16) {
532 server->secType = RawNTLMSSP;
533 if (server->socketUseCount.counter > 1) {
534 if (memcmp
535 (server->server_GUID,
536 pSMBr->u.extended_response.
537 GUID, 16) != 0) {
Steve Frencheeac8042006-01-13 21:34:58 -0800538 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 memcpy(server->
540 server_GUID,
541 pSMBr->u.
542 extended_response.
543 GUID, 16);
544 }
545 } else
546 memcpy(server->server_GUID,
547 pSMBr->u.extended_response.
548 GUID, 16);
549 } else {
550 rc = decode_negTokenInit(pSMBr->u.
551 extended_response.
552 SecurityBlob,
553 count - 16,
554 &server->secType);
555 if(rc == 1) {
556 /* BB Need to fill struct for sessetup here */
557 rc = -EOPNOTSUPP;
558 } else {
559 rc = -EINVAL;
560 }
561 }
562 } else
563 server->capabilities &= ~CAP_EXTENDED_SECURITY;
564 if(sign_CIFS_PDUs == FALSE) {
565 if(server->secMode & SECMODE_SIGN_REQUIRED)
566 cERROR(1,
567 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700568 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 } else if(sign_CIFS_PDUs == 1) {
570 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700571 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 }
573
574 }
Steve French39798772006-05-31 22:40:51 +0000575neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700576 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return rc;
578}
579
580int
581CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
582{
583 struct smb_hdr *smb_buffer;
584 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
585 int rc = 0;
586 int length;
587
588 cFYI(1, ("In tree disconnect"));
589 /*
590 * If last user of the connection and
591 * connection alive - disconnect it
592 * If this is the last connection on the server session disconnect it
593 * (and inside session disconnect we should check if tcp socket needs
594 * to be freed and kernel thread woken up).
595 */
596 if (tcon)
597 down(&tcon->tconSem);
598 else
599 return -EIO;
600
601 atomic_dec(&tcon->useCount);
602 if (atomic_read(&tcon->useCount) > 0) {
603 up(&tcon->tconSem);
604 return -EBUSY;
605 }
606
607 /* No need to return error on this operation if tid invalidated and
608 closed on server already e.g. due to tcp session crashing */
609 if(tcon->tidStatus == CifsNeedReconnect) {
610 up(&tcon->tconSem);
611 return 0;
612 }
613
614 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
615 up(&tcon->tconSem);
616 return -EIO;
617 }
Steve French09d1db52005-04-28 22:41:08 -0700618 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
619 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 if (rc) {
621 up(&tcon->tconSem);
622 return rc;
623 } else {
624 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
627 &length, 0);
628 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700629 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
631 if (smb_buffer)
632 cifs_small_buf_release(smb_buffer);
633 up(&tcon->tconSem);
634
635 /* No need to return error on this operation if tid invalidated and
636 closed on server already e.g. due to tcp session crashing */
637 if (rc == -EAGAIN)
638 rc = 0;
639
640 return rc;
641}
642
643int
644CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
645{
646 struct smb_hdr *smb_buffer_response;
647 LOGOFF_ANDX_REQ *pSMB;
648 int rc = 0;
649 int length;
650
651 cFYI(1, ("In SMBLogoff for session disconnect"));
652 if (ses)
653 down(&ses->sesSem);
654 else
655 return -EIO;
656
657 atomic_dec(&ses->inUse);
658 if (atomic_read(&ses->inUse) > 0) {
659 up(&ses->sesSem);
660 return -EBUSY;
661 }
662 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
663 if (rc) {
664 up(&ses->sesSem);
665 return rc;
666 }
667
668 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
669
670 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700671 pSMB->hdr.Mid = GetNextMid(ses->server);
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if(ses->server->secMode &
674 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
675 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
676 }
677
678 pSMB->hdr.Uid = ses->Suid;
679
680 pSMB->AndXCommand = 0xFF;
681 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
682 smb_buffer_response, &length, 0);
683 if (ses->server) {
684 atomic_dec(&ses->server->socketUseCount);
685 if (atomic_read(&ses->server->socketUseCount) == 0) {
686 spin_lock(&GlobalMid_Lock);
687 ses->server->tcpStatus = CifsExiting;
688 spin_unlock(&GlobalMid_Lock);
689 rc = -ESHUTDOWN;
690 }
691 }
Steve Frencha59c6582005-08-17 12:12:19 -0700692 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700693 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 /* if session dead then we do not need to do ulogoff,
696 since server closed smb session, no sense reporting
697 error */
698 if (rc == -EAGAIN)
699 rc = 0;
700 return rc;
701}
702
703int
Steve French737b7582005-04-28 22:41:06 -0700704CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
705 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
707 DELETE_FILE_REQ *pSMB = NULL;
708 DELETE_FILE_RSP *pSMBr = NULL;
709 int rc = 0;
710 int bytes_returned;
711 int name_len;
712
713DelFileRetry:
714 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
715 (void **) &pSMBr);
716 if (rc)
717 return rc;
718
719 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
720 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500721 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700722 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 name_len++; /* trailing null */
724 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700725 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 name_len = strnlen(fileName, PATH_MAX);
727 name_len++; /* trailing null */
728 strncpy(pSMB->fileName, fileName, name_len);
729 }
730 pSMB->SearchAttributes =
731 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
732 pSMB->BufferFormat = 0x04;
733 pSMB->hdr.smb_buf_length += name_len + 1;
734 pSMB->ByteCount = cpu_to_le16(name_len + 1);
735 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
736 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700737 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (rc) {
739 cFYI(1, ("Error in RMFile = %d", rc));
740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 cifs_buf_release(pSMB);
743 if (rc == -EAGAIN)
744 goto DelFileRetry;
745
746 return rc;
747}
748
749int
Steve French737b7582005-04-28 22:41:06 -0700750CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
751 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
753 DELETE_DIRECTORY_REQ *pSMB = NULL;
754 DELETE_DIRECTORY_RSP *pSMBr = NULL;
755 int rc = 0;
756 int bytes_returned;
757 int name_len;
758
759 cFYI(1, ("In CIFSSMBRmDir"));
760RmDirRetry:
761 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
762 (void **) &pSMBr);
763 if (rc)
764 return rc;
765
766 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700767 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
768 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 name_len++; /* trailing null */
770 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700771 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 name_len = strnlen(dirName, PATH_MAX);
773 name_len++; /* trailing null */
774 strncpy(pSMB->DirName, dirName, name_len);
775 }
776
777 pSMB->BufferFormat = 0x04;
778 pSMB->hdr.smb_buf_length += name_len + 1;
779 pSMB->ByteCount = cpu_to_le16(name_len + 1);
780 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
781 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700782 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (rc) {
784 cFYI(1, ("Error in RMDir = %d", rc));
785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 cifs_buf_release(pSMB);
788 if (rc == -EAGAIN)
789 goto RmDirRetry;
790 return rc;
791}
792
793int
794CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700795 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 int rc = 0;
798 CREATE_DIRECTORY_REQ *pSMB = NULL;
799 CREATE_DIRECTORY_RSP *pSMBr = NULL;
800 int bytes_returned;
801 int name_len;
802
803 cFYI(1, ("In CIFSSMBMkDir"));
804MkDirRetry:
805 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
806 (void **) &pSMBr);
807 if (rc)
808 return rc;
809
810 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500811 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700812 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 name_len++; /* trailing null */
814 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700815 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 name_len = strnlen(name, PATH_MAX);
817 name_len++; /* trailing null */
818 strncpy(pSMB->DirName, name, name_len);
819 }
820
821 pSMB->BufferFormat = 0x04;
822 pSMB->hdr.smb_buf_length += name_len + 1;
823 pSMB->ByteCount = cpu_to_le16(name_len + 1);
824 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
825 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700826 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (rc) {
828 cFYI(1, ("Error in Mkdir = %d", rc));
829 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 cifs_buf_release(pSMB);
832 if (rc == -EAGAIN)
833 goto MkDirRetry;
834 return rc;
835}
836
Steve Frencha9d02ad2005-08-24 23:06:05 -0700837static __u16 convert_disposition(int disposition)
838{
839 __u16 ofun = 0;
840
841 switch (disposition) {
842 case FILE_SUPERSEDE:
843 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
844 break;
845 case FILE_OPEN:
846 ofun = SMBOPEN_OAPPEND;
847 break;
848 case FILE_CREATE:
849 ofun = SMBOPEN_OCREATE;
850 break;
851 case FILE_OPEN_IF:
852 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
853 break;
854 case FILE_OVERWRITE:
855 ofun = SMBOPEN_OTRUNC;
856 break;
857 case FILE_OVERWRITE_IF:
858 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
859 break;
860 default:
861 cFYI(1,("unknown disposition %d",disposition));
862 ofun = SMBOPEN_OAPPEND; /* regular open */
863 }
864 return ofun;
865}
866
867int
868SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
869 const char *fileName, const int openDisposition,
870 const int access_flags, const int create_options, __u16 * netfid,
871 int *pOplock, FILE_ALL_INFO * pfile_info,
872 const struct nls_table *nls_codepage, int remap)
873{
874 int rc = -EACCES;
875 OPENX_REQ *pSMB = NULL;
876 OPENX_RSP *pSMBr = NULL;
877 int bytes_returned;
878 int name_len;
879 __u16 count;
880
881OldOpenRetry:
882 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
883 (void **) &pSMBr);
884 if (rc)
885 return rc;
886
887 pSMB->AndXCommand = 0xFF; /* none */
888
889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
890 count = 1; /* account for one byte pad to word boundary */
891 name_len =
892 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
893 fileName, PATH_MAX, nls_codepage, remap);
894 name_len++; /* trailing null */
895 name_len *= 2;
896 } else { /* BB improve check for buffer overruns BB */
897 count = 0; /* no pad */
898 name_len = strnlen(fileName, PATH_MAX);
899 name_len++; /* trailing null */
900 strncpy(pSMB->fileName, fileName, name_len);
901 }
902 if (*pOplock & REQ_OPLOCK)
903 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
904 else if (*pOplock & REQ_BATCHOPLOCK) {
905 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
906 }
907 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
908 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
909 /* 0 = read
910 1 = write
911 2 = rw
912 3 = execute
913 */
914 pSMB->Mode = cpu_to_le16(2);
915 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
916 /* set file as system file if special file such
917 as fifo and server expecting SFU style and
918 no Unix extensions */
919
920 if(create_options & CREATE_OPTION_SPECIAL)
921 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
922 else
Steve French3e87d802005-09-18 20:49:21 -0700923 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700924
925 /* if ((omode & S_IWUGO) == 0)
926 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
927 /* Above line causes problems due to vfs splitting create into two
928 pieces - need to set mode after file created not while it is
929 being created */
930
931 /* BB FIXME BB */
932/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
933 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700934
935 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700936 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700937 count += name_len;
938 pSMB->hdr.smb_buf_length += count;
939
940 pSMB->ByteCount = cpu_to_le16(count);
941 /* long_op set to 1 to allow for oplock break timeouts */
942 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
943 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
944 cifs_stats_inc(&tcon->num_opens);
945 if (rc) {
946 cFYI(1, ("Error in Open = %d", rc));
947 } else {
948 /* BB verify if wct == 15 */
949
950/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
951
952 *netfid = pSMBr->Fid; /* cifs fid stays in le */
953 /* Let caller know file was created so we can set the mode. */
954 /* Do we care about the CreateAction in any other cases? */
955 /* BB FIXME BB */
956/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
957 *pOplock |= CIFS_CREATE_ACTION; */
958 /* BB FIXME END */
959
960 if(pfile_info) {
961 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
962 pfile_info->LastAccessTime = 0; /* BB fixme */
963 pfile_info->LastWriteTime = 0; /* BB fixme */
964 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700965 pfile_info->Attributes =
966 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700967 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700968 pfile_info->AllocationSize =
969 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
970 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700971 pfile_info->NumberOfLinks = cpu_to_le32(1);
972 }
973 }
974
975 cifs_buf_release(pSMB);
976 if (rc == -EAGAIN)
977 goto OldOpenRetry;
978 return rc;
979}
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981int
982CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
983 const char *fileName, const int openDisposition,
984 const int access_flags, const int create_options, __u16 * netfid,
985 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700986 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
988 int rc = -EACCES;
989 OPEN_REQ *pSMB = NULL;
990 OPEN_RSP *pSMBr = NULL;
991 int bytes_returned;
992 int name_len;
993 __u16 count;
994
995openRetry:
996 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
997 (void **) &pSMBr);
998 if (rc)
999 return rc;
1000
1001 pSMB->AndXCommand = 0xFF; /* none */
1002
1003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1004 count = 1; /* account for one byte pad to word boundary */
1005 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001006 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001007 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 name_len++; /* trailing null */
1009 name_len *= 2;
1010 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001011 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 count = 0; /* no pad */
1013 name_len = strnlen(fileName, PATH_MAX);
1014 name_len++; /* trailing null */
1015 pSMB->NameLength = cpu_to_le16(name_len);
1016 strncpy(pSMB->fileName, fileName, name_len);
1017 }
1018 if (*pOplock & REQ_OPLOCK)
1019 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1020 else if (*pOplock & REQ_BATCHOPLOCK) {
1021 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1022 }
1023 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1024 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001025 /* set file as system file if special file such
1026 as fifo and server expecting SFU style and
1027 no Unix extensions */
1028 if(create_options & CREATE_OPTION_SPECIAL)
1029 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1030 else
1031 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 /* XP does not handle ATTR_POSIX_SEMANTICS */
1033 /* but it helps speed up case sensitive checks for other
1034 servers such as Samba */
1035 if (tcon->ses->capabilities & CAP_UNIX)
1036 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1037
1038 /* if ((omode & S_IWUGO) == 0)
1039 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1040 /* Above line causes problems due to vfs splitting create into two
1041 pieces - need to set mode after file created not while it is
1042 being created */
1043 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1044 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001045 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001046 /* BB Expirement with various impersonation levels and verify */
1047 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 pSMB->SecurityFlags =
1049 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1050
1051 count += name_len;
1052 pSMB->hdr.smb_buf_length += count;
1053
1054 pSMB->ByteCount = cpu_to_le16(count);
1055 /* long_op set to 1 to allow for oplock break timeouts */
1056 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1057 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001058 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 if (rc) {
1060 cFYI(1, ("Error in Open = %d", rc));
1061 } else {
Steve French09d1db52005-04-28 22:41:08 -07001062 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1064 /* Let caller know file was created so we can set the mode. */
1065 /* Do we care about the CreateAction in any other cases? */
1066 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1067 *pOplock |= CIFS_CREATE_ACTION;
1068 if(pfile_info) {
1069 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1070 36 /* CreationTime to Attributes */);
1071 /* the file_info buf is endian converted by caller */
1072 pfile_info->AllocationSize = pSMBr->AllocationSize;
1073 pfile_info->EndOfFile = pSMBr->EndOfFile;
1074 pfile_info->NumberOfLinks = cpu_to_le32(1);
1075 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001077
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 cifs_buf_release(pSMB);
1079 if (rc == -EAGAIN)
1080 goto openRetry;
1081 return rc;
1082}
1083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084int
1085CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001086 const int netfid, const unsigned int count,
1087 const __u64 lseek, unsigned int *nbytes, char **buf,
1088 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089{
1090 int rc = -EACCES;
1091 READ_REQ *pSMB = NULL;
1092 READ_RSP *pSMBr = NULL;
1093 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001094 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001095 int resp_buf_type = 0;
1096 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
1098 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001099 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1100 wct = 12;
1101 else
1102 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001105 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 if (rc)
1107 return rc;
1108
1109 /* tcon and ses pointer are checked in smb_init */
1110 if (tcon->ses->server == NULL)
1111 return -ECONNABORTED;
1112
Steve Frenchec637e32005-12-12 20:53:18 -08001113 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 pSMB->Fid = netfid;
1115 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001116 if(wct == 12)
1117 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001118 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1119 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 pSMB->Remaining = 0;
1122 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1123 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001124 if(wct == 12)
1125 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1126 else {
1127 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001128 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001129 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001130 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001131 }
Steve Frenchec637e32005-12-12 20:53:18 -08001132
1133 iov[0].iov_base = (char *)pSMB;
1134 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1135 rc = SendReceive2(xid, tcon->ses, iov,
1136 1 /* num iovecs */,
1137 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001138 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001139 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 if (rc) {
1141 cERROR(1, ("Send error in read = %d", rc));
1142 } else {
1143 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1144 data_length = data_length << 16;
1145 data_length += le16_to_cpu(pSMBr->DataLength);
1146 *nbytes = data_length;
1147
1148 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001149 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 || (data_length > count)) {
1151 cFYI(1,("bad length %d for count %d",data_length,count));
1152 rc = -EIO;
1153 *nbytes = 0;
1154 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001155 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001157/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1158 cERROR(1,("Faulting on read rc = %d",rc));
1159 rc = -EFAULT;
1160 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001162 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
1164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Steve French4b8f9302006-02-26 16:41:18 +00001166/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001167 if(*buf) {
1168 if(resp_buf_type == CIFS_SMALL_BUFFER)
1169 cifs_small_buf_release(iov[0].iov_base);
1170 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1171 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001172 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1173 /* return buffer to caller to free */
1174 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001175 if(resp_buf_type == CIFS_SMALL_BUFFER)
1176 *pbuf_type = CIFS_SMALL_BUFFER;
1177 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1178 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001179 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001180
1181 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 since file handle passed in no longer valid */
1183 return rc;
1184}
1185
Steve Frenchec637e32005-12-12 20:53:18 -08001186
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187int
1188CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1189 const int netfid, const unsigned int count,
1190 const __u64 offset, unsigned int *nbytes, const char *buf,
1191 const char __user * ubuf, const int long_op)
1192{
1193 int rc = -EACCES;
1194 WRITE_REQ *pSMB = NULL;
1195 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001196 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 __u32 bytes_sent;
1198 __u16 byte_count;
1199
1200 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001201 if(tcon->ses == NULL)
1202 return -ECONNABORTED;
1203
1204 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1205 wct = 14;
1206 else
1207 wct = 12;
1208
1209 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 (void **) &pSMBr);
1211 if (rc)
1212 return rc;
1213 /* tcon and ses pointer are checked in smb_init */
1214 if (tcon->ses->server == NULL)
1215 return -ECONNABORTED;
1216
1217 pSMB->AndXCommand = 0xFF; /* none */
1218 pSMB->Fid = netfid;
1219 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001220 if(wct == 14)
1221 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1222 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1223 return -EIO;
1224
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 pSMB->Reserved = 0xFFFFFFFF;
1226 pSMB->WriteMode = 0;
1227 pSMB->Remaining = 0;
1228
1229 /* Can increase buffer size if buffer is big enough in some cases - ie we
1230 can send more if LARGE_WRITE_X capability returned by the server and if
1231 our buffer is big enough or if we convert to iovecs on socket writes
1232 and eliminate the copy to the CIFS buffer */
1233 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1234 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1235 } else {
1236 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1237 & ~0xFF;
1238 }
1239
1240 if (bytes_sent > count)
1241 bytes_sent = count;
1242 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001243 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 if(buf)
1245 memcpy(pSMB->Data,buf,bytes_sent);
1246 else if(ubuf) {
1247 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1248 cifs_buf_release(pSMB);
1249 return -EFAULT;
1250 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001251 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 /* No buffer */
1253 cifs_buf_release(pSMB);
1254 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001255 } /* else setting file size with write of zero bytes */
1256 if(wct == 14)
1257 byte_count = bytes_sent + 1; /* pad */
1258 else /* wct == 12 */ {
1259 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1262 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001263 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001264
1265 if(wct == 14)
1266 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001267 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001268 struct smb_com_writex_req * pSMBW =
1269 (struct smb_com_writex_req *)pSMB;
1270 pSMBW->ByteCount = cpu_to_le16(byte_count);
1271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
1273 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1274 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001275 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 if (rc) {
1277 cFYI(1, ("Send error in write = %d", rc));
1278 *nbytes = 0;
1279 } else {
1280 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1281 *nbytes = (*nbytes) << 16;
1282 *nbytes += le16_to_cpu(pSMBr->Count);
1283 }
1284
1285 cifs_buf_release(pSMB);
1286
1287 /* Note: On -EAGAIN error only caller can retry on handle based calls
1288 since file handle passed in no longer valid */
1289
1290 return rc;
1291}
1292
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001293int
1294CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001296 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1297 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298{
1299 int rc = -EACCES;
1300 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001301 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001302 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001303 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
Steve Frenchff7feac2005-11-15 16:45:16 -08001305 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1306
Steve French8cc64c62005-10-03 13:49:43 -07001307 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1308 wct = 14;
1309 else
1310 wct = 12;
1311 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 if (rc)
1313 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 /* tcon and ses pointer are checked in smb_init */
1315 if (tcon->ses->server == NULL)
1316 return -ECONNABORTED;
1317
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001318 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 pSMB->Fid = netfid;
1320 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001321 if(wct == 14)
1322 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1323 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1324 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->Reserved = 0xFFFFFFFF;
1326 pSMB->WriteMode = 0;
1327 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 pSMB->DataOffset =
1330 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1331
Steve French3e844692005-10-03 13:37:24 -07001332 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1333 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001334 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001335 if(wct == 14)
1336 pSMB->hdr.smb_buf_length += count+1;
1337 else /* wct == 12 */
1338 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1339 if(wct == 14)
1340 pSMB->ByteCount = cpu_to_le16(count + 1);
1341 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1342 struct smb_com_writex_req * pSMBW =
1343 (struct smb_com_writex_req *)pSMB;
1344 pSMBW->ByteCount = cpu_to_le16(count + 5);
1345 }
Steve French3e844692005-10-03 13:37:24 -07001346 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001347 if(wct == 14)
1348 iov[0].iov_len = smb_hdr_len + 4;
1349 else /* wct == 12 pad bigger by four bytes */
1350 iov[0].iov_len = smb_hdr_len + 8;
1351
Steve French3e844692005-10-03 13:37:24 -07001352
Steve Frenchec637e32005-12-12 20:53:18 -08001353 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001354 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001355 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001357 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001359 } else if(resp_buf_type == 0) {
1360 /* presumably this can not happen, but best to be safe */
1361 rc = -EIO;
1362 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001363 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001364 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001365 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1366 *nbytes = (*nbytes) << 16;
1367 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
Steve French4b8f9302006-02-26 16:41:18 +00001370/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001371 if(resp_buf_type == CIFS_SMALL_BUFFER)
1372 cifs_small_buf_release(iov[0].iov_base);
1373 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1374 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
1376 /* Note: On -EAGAIN error only caller can retry on handle based calls
1377 since file handle passed in no longer valid */
1378
1379 return rc;
1380}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001381
1382
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383int
1384CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1385 const __u16 smb_file_id, const __u64 len,
1386 const __u64 offset, const __u32 numUnlock,
1387 const __u32 numLock, const __u8 lockType, const int waitFlag)
1388{
1389 int rc = 0;
1390 LOCK_REQ *pSMB = NULL;
1391 LOCK_RSP *pSMBr = NULL;
1392 int bytes_returned;
1393 int timeout = 0;
1394 __u16 count;
1395
1396 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001397 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 if (rc)
1400 return rc;
1401
Steve French46810cb2005-04-28 22:41:09 -07001402 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1405 timeout = -1; /* no response expected */
1406 pSMB->Timeout = 0;
1407 } else if (waitFlag == TRUE) {
1408 timeout = 3; /* blocking operation, no timeout */
1409 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1410 } else {
1411 pSMB->Timeout = 0;
1412 }
1413
1414 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1415 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1416 pSMB->LockType = lockType;
1417 pSMB->AndXCommand = 0xFF; /* none */
1418 pSMB->Fid = smb_file_id; /* netfid stays le */
1419
1420 if((numLock != 0) || (numUnlock != 0)) {
1421 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1422 /* BB where to store pid high? */
1423 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1424 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1425 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1426 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1427 count = sizeof(LOCKING_ANDX_RANGE);
1428 } else {
1429 /* oplock break */
1430 count = 0;
1431 }
1432 pSMB->hdr.smb_buf_length += count;
1433 pSMB->ByteCount = cpu_to_le16(count);
1434
1435 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1436 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001437 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 if (rc) {
1439 cFYI(1, ("Send error in Lock = %d", rc));
1440 }
Steve French46810cb2005-04-28 22:41:09 -07001441 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
1443 /* Note: On -EAGAIN error only caller can retry on handle based calls
1444 since file handle passed in no longer valid */
1445 return rc;
1446}
1447
1448int
Steve French08547b02006-02-28 22:39:25 +00001449CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1450 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001451 struct file_lock *pLockData, const __u16 lock_type,
1452 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001453{
1454 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1455 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1456 char *data_offset;
1457 struct cifs_posix_lock *parm_data;
1458 int rc = 0;
1459 int bytes_returned = 0;
1460 __u16 params, param_offset, offset, byte_count, count;
1461
1462 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001463
1464 if(pLockData == NULL)
1465 return EINVAL;
1466
Steve French08547b02006-02-28 22:39:25 +00001467 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1468
1469 if (rc)
1470 return rc;
1471
1472 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1473
1474 params = 6;
1475 pSMB->MaxSetupCount = 0;
1476 pSMB->Reserved = 0;
1477 pSMB->Flags = 0;
1478 pSMB->Timeout = 0;
1479 pSMB->Reserved2 = 0;
1480 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1481 offset = param_offset + params;
1482
1483 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1484
1485 count = sizeof(struct cifs_posix_lock);
1486 pSMB->MaxParameterCount = cpu_to_le16(2);
1487 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1488 pSMB->SetupCount = 1;
1489 pSMB->Reserved3 = 0;
1490 if(get_flag)
1491 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1492 else
1493 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1494 byte_count = 3 /* pad */ + params + count;
1495 pSMB->DataCount = cpu_to_le16(count);
1496 pSMB->ParameterCount = cpu_to_le16(params);
1497 pSMB->TotalDataCount = pSMB->DataCount;
1498 pSMB->TotalParameterCount = pSMB->ParameterCount;
1499 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1500 parm_data = (struct cifs_posix_lock *)
1501 (((char *) &pSMB->hdr.Protocol) + offset);
1502
1503 parm_data->lock_type = cpu_to_le16(lock_type);
1504 if(waitFlag)
Steve Frenchcec6815a2006-05-30 18:07:17 +00001505 parm_data->lock_flags = cpu_to_le16(1);
Steve French08547b02006-02-28 22:39:25 +00001506 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001507 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001508 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001509
1510 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001511 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001512 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1513 pSMB->Reserved4 = 0;
1514 pSMB->hdr.smb_buf_length += byte_count;
1515 pSMB->ByteCount = cpu_to_le16(byte_count);
1516 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1517 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1518 if (rc) {
1519 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001520 } else if (get_flag) {
1521 /* lock structure can be returned on get */
1522 __u16 data_offset;
1523 __u16 data_count;
1524 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001525
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001526 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1527 rc = -EIO; /* bad smb */
1528 goto plk_err_exit;
1529 }
1530 if(pLockData == NULL) {
1531 rc = -EINVAL;
1532 goto plk_err_exit;
1533 }
1534 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1535 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1536 if(data_count < sizeof(struct cifs_posix_lock)) {
1537 rc = -EIO;
1538 goto plk_err_exit;
1539 }
1540 parm_data = (struct cifs_posix_lock *)
1541 ((char *)&pSMBr->hdr.Protocol + data_offset);
1542 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1543 pLockData->fl_type = F_UNLCK;
1544 }
1545
1546plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001547 if (pSMB)
1548 cifs_small_buf_release(pSMB);
1549
1550 /* Note: On -EAGAIN error only caller can retry on handle based calls
1551 since file handle passed in no longer valid */
1552
1553 return rc;
1554}
1555
1556
1557int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1559{
1560 int rc = 0;
1561 CLOSE_REQ *pSMB = NULL;
1562 CLOSE_RSP *pSMBr = NULL;
1563 int bytes_returned;
1564 cFYI(1, ("In CIFSSMBClose"));
1565
1566/* do not retry on dead session on close */
1567 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1568 if(rc == -EAGAIN)
1569 return 0;
1570 if (rc)
1571 return rc;
1572
1573 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1574
1575 pSMB->FileID = (__u16) smb_file_id;
1576 pSMB->LastWriteTime = 0;
1577 pSMB->ByteCount = 0;
1578 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1579 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001580 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 if (rc) {
1582 if(rc!=-EINTR) {
1583 /* EINTR is expected when user ctl-c to kill app */
1584 cERROR(1, ("Send error in Close = %d", rc));
1585 }
1586 }
1587
1588 cifs_small_buf_release(pSMB);
1589
1590 /* Since session is dead, file will be closed on server already */
1591 if(rc == -EAGAIN)
1592 rc = 0;
1593
1594 return rc;
1595}
1596
1597int
1598CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1599 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001600 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601{
1602 int rc = 0;
1603 RENAME_REQ *pSMB = NULL;
1604 RENAME_RSP *pSMBr = NULL;
1605 int bytes_returned;
1606 int name_len, name_len2;
1607 __u16 count;
1608
1609 cFYI(1, ("In CIFSSMBRename"));
1610renameRetry:
1611 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1612 (void **) &pSMBr);
1613 if (rc)
1614 return rc;
1615
1616 pSMB->BufferFormat = 0x04;
1617 pSMB->SearchAttributes =
1618 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1619 ATTR_DIRECTORY);
1620
1621 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1622 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001623 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001624 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 name_len++; /* trailing null */
1626 name_len *= 2;
1627 pSMB->OldFileName[name_len] = 0x04; /* pad */
1628 /* protocol requires ASCII signature byte on Unicode string */
1629 pSMB->OldFileName[name_len + 1] = 0x00;
1630 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001631 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001632 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1634 name_len2 *= 2; /* convert to bytes */
1635 } else { /* BB improve the check for buffer overruns BB */
1636 name_len = strnlen(fromName, PATH_MAX);
1637 name_len++; /* trailing null */
1638 strncpy(pSMB->OldFileName, fromName, name_len);
1639 name_len2 = strnlen(toName, PATH_MAX);
1640 name_len2++; /* trailing null */
1641 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1642 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1643 name_len2++; /* trailing null */
1644 name_len2++; /* signature byte */
1645 }
1646
1647 count = 1 /* 1st signature byte */ + name_len + name_len2;
1648 pSMB->hdr.smb_buf_length += count;
1649 pSMB->ByteCount = cpu_to_le16(count);
1650
1651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001653 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 if (rc) {
1655 cFYI(1, ("Send error in rename = %d", rc));
1656 }
1657
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 cifs_buf_release(pSMB);
1659
1660 if (rc == -EAGAIN)
1661 goto renameRetry;
1662
1663 return rc;
1664}
1665
1666int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001667 int netfid, char * target_name,
1668 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669{
1670 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1671 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1672 struct set_file_rename * rename_info;
1673 char *data_offset;
1674 char dummy_string[30];
1675 int rc = 0;
1676 int bytes_returned = 0;
1677 int len_of_str;
1678 __u16 params, param_offset, offset, count, byte_count;
1679
1680 cFYI(1, ("Rename to File by handle"));
1681 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1682 (void **) &pSMBr);
1683 if (rc)
1684 return rc;
1685
1686 params = 6;
1687 pSMB->MaxSetupCount = 0;
1688 pSMB->Reserved = 0;
1689 pSMB->Flags = 0;
1690 pSMB->Timeout = 0;
1691 pSMB->Reserved2 = 0;
1692 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1693 offset = param_offset + params;
1694
1695 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1696 rename_info = (struct set_file_rename *) data_offset;
1697 pSMB->MaxParameterCount = cpu_to_le16(2);
1698 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1699 pSMB->SetupCount = 1;
1700 pSMB->Reserved3 = 0;
1701 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1702 byte_count = 3 /* pad */ + params;
1703 pSMB->ParameterCount = cpu_to_le16(params);
1704 pSMB->TotalParameterCount = pSMB->ParameterCount;
1705 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1706 pSMB->DataOffset = cpu_to_le16(offset);
1707 /* construct random name ".cifs_tmp<inodenum><mid>" */
1708 rename_info->overwrite = cpu_to_le32(1);
1709 rename_info->root_fid = 0;
1710 /* unicode only call */
1711 if(target_name == NULL) {
1712 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001713 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001714 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001716 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001717 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 }
1719 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1720 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1721 byte_count += count;
1722 pSMB->DataCount = cpu_to_le16(count);
1723 pSMB->TotalDataCount = pSMB->DataCount;
1724 pSMB->Fid = netfid;
1725 pSMB->InformationLevel =
1726 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1727 pSMB->Reserved4 = 0;
1728 pSMB->hdr.smb_buf_length += byte_count;
1729 pSMB->ByteCount = cpu_to_le16(byte_count);
1730 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1731 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001732 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 if (rc) {
1734 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1735 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 cifs_buf_release(pSMB);
1738
1739 /* Note: On -EAGAIN error only caller can retry on handle based calls
1740 since file handle passed in no longer valid */
1741
1742 return rc;
1743}
1744
1745int
1746CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1747 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001748 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749{
1750 int rc = 0;
1751 COPY_REQ *pSMB = NULL;
1752 COPY_RSP *pSMBr = NULL;
1753 int bytes_returned;
1754 int name_len, name_len2;
1755 __u16 count;
1756
1757 cFYI(1, ("In CIFSSMBCopy"));
1758copyRetry:
1759 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1760 (void **) &pSMBr);
1761 if (rc)
1762 return rc;
1763
1764 pSMB->BufferFormat = 0x04;
1765 pSMB->Tid2 = target_tid;
1766
1767 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1768
1769 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001770 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001771 fromName, PATH_MAX, nls_codepage,
1772 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 name_len++; /* trailing null */
1774 name_len *= 2;
1775 pSMB->OldFileName[name_len] = 0x04; /* pad */
1776 /* protocol requires ASCII signature byte on Unicode string */
1777 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001778 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001779 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1781 name_len2 *= 2; /* convert to bytes */
1782 } else { /* BB improve the check for buffer overruns BB */
1783 name_len = strnlen(fromName, PATH_MAX);
1784 name_len++; /* trailing null */
1785 strncpy(pSMB->OldFileName, fromName, name_len);
1786 name_len2 = strnlen(toName, PATH_MAX);
1787 name_len2++; /* trailing null */
1788 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1789 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1790 name_len2++; /* trailing null */
1791 name_len2++; /* signature byte */
1792 }
1793
1794 count = 1 /* 1st signature byte */ + name_len + name_len2;
1795 pSMB->hdr.smb_buf_length += count;
1796 pSMB->ByteCount = cpu_to_le16(count);
1797
1798 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1799 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1800 if (rc) {
1801 cFYI(1, ("Send error in copy = %d with %d files copied",
1802 rc, le16_to_cpu(pSMBr->CopyCount)));
1803 }
1804 if (pSMB)
1805 cifs_buf_release(pSMB);
1806
1807 if (rc == -EAGAIN)
1808 goto copyRetry;
1809
1810 return rc;
1811}
1812
1813int
1814CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1815 const char *fromName, const char *toName,
1816 const struct nls_table *nls_codepage)
1817{
1818 TRANSACTION2_SPI_REQ *pSMB = NULL;
1819 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1820 char *data_offset;
1821 int name_len;
1822 int name_len_target;
1823 int rc = 0;
1824 int bytes_returned = 0;
1825 __u16 params, param_offset, offset, byte_count;
1826
1827 cFYI(1, ("In Symlink Unix style"));
1828createSymLinkRetry:
1829 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1830 (void **) &pSMBr);
1831 if (rc)
1832 return rc;
1833
1834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1835 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001836 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 /* find define for this maxpathcomponent */
1838 , nls_codepage);
1839 name_len++; /* trailing null */
1840 name_len *= 2;
1841
1842 } else { /* BB improve the check for buffer overruns BB */
1843 name_len = strnlen(fromName, PATH_MAX);
1844 name_len++; /* trailing null */
1845 strncpy(pSMB->FileName, fromName, name_len);
1846 }
1847 params = 6 + name_len;
1848 pSMB->MaxSetupCount = 0;
1849 pSMB->Reserved = 0;
1850 pSMB->Flags = 0;
1851 pSMB->Timeout = 0;
1852 pSMB->Reserved2 = 0;
1853 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1854 InformationLevel) - 4;
1855 offset = param_offset + params;
1856
1857 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1859 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001860 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 /* find define for this maxpathcomponent */
1862 , nls_codepage);
1863 name_len_target++; /* trailing null */
1864 name_len_target *= 2;
1865 } else { /* BB improve the check for buffer overruns BB */
1866 name_len_target = strnlen(toName, PATH_MAX);
1867 name_len_target++; /* trailing null */
1868 strncpy(data_offset, toName, name_len_target);
1869 }
1870
1871 pSMB->MaxParameterCount = cpu_to_le16(2);
1872 /* BB find exact max on data count below from sess */
1873 pSMB->MaxDataCount = cpu_to_le16(1000);
1874 pSMB->SetupCount = 1;
1875 pSMB->Reserved3 = 0;
1876 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1877 byte_count = 3 /* pad */ + params + name_len_target;
1878 pSMB->DataCount = cpu_to_le16(name_len_target);
1879 pSMB->ParameterCount = cpu_to_le16(params);
1880 pSMB->TotalDataCount = pSMB->DataCount;
1881 pSMB->TotalParameterCount = pSMB->ParameterCount;
1882 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1883 pSMB->DataOffset = cpu_to_le16(offset);
1884 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1885 pSMB->Reserved4 = 0;
1886 pSMB->hdr.smb_buf_length += byte_count;
1887 pSMB->ByteCount = cpu_to_le16(byte_count);
1888 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1889 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001890 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (rc) {
1892 cFYI(1,
1893 ("Send error in SetPathInfo (create symlink) = %d",
1894 rc));
1895 }
1896
1897 if (pSMB)
1898 cifs_buf_release(pSMB);
1899
1900 if (rc == -EAGAIN)
1901 goto createSymLinkRetry;
1902
1903 return rc;
1904}
1905
1906int
1907CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1908 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001909 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910{
1911 TRANSACTION2_SPI_REQ *pSMB = NULL;
1912 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1913 char *data_offset;
1914 int name_len;
1915 int name_len_target;
1916 int rc = 0;
1917 int bytes_returned = 0;
1918 __u16 params, param_offset, offset, byte_count;
1919
1920 cFYI(1, ("In Create Hard link Unix style"));
1921createHardLinkRetry:
1922 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1923 (void **) &pSMBr);
1924 if (rc)
1925 return rc;
1926
1927 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001928 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001929 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 name_len++; /* trailing null */
1931 name_len *= 2;
1932
1933 } else { /* BB improve the check for buffer overruns BB */
1934 name_len = strnlen(toName, PATH_MAX);
1935 name_len++; /* trailing null */
1936 strncpy(pSMB->FileName, toName, name_len);
1937 }
1938 params = 6 + name_len;
1939 pSMB->MaxSetupCount = 0;
1940 pSMB->Reserved = 0;
1941 pSMB->Flags = 0;
1942 pSMB->Timeout = 0;
1943 pSMB->Reserved2 = 0;
1944 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1945 InformationLevel) - 4;
1946 offset = param_offset + params;
1947
1948 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1950 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001951 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001952 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 name_len_target++; /* trailing null */
1954 name_len_target *= 2;
1955 } else { /* BB improve the check for buffer overruns BB */
1956 name_len_target = strnlen(fromName, PATH_MAX);
1957 name_len_target++; /* trailing null */
1958 strncpy(data_offset, fromName, name_len_target);
1959 }
1960
1961 pSMB->MaxParameterCount = cpu_to_le16(2);
1962 /* BB find exact max on data count below from sess*/
1963 pSMB->MaxDataCount = cpu_to_le16(1000);
1964 pSMB->SetupCount = 1;
1965 pSMB->Reserved3 = 0;
1966 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1967 byte_count = 3 /* pad */ + params + name_len_target;
1968 pSMB->ParameterCount = cpu_to_le16(params);
1969 pSMB->TotalParameterCount = pSMB->ParameterCount;
1970 pSMB->DataCount = cpu_to_le16(name_len_target);
1971 pSMB->TotalDataCount = pSMB->DataCount;
1972 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1973 pSMB->DataOffset = cpu_to_le16(offset);
1974 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1975 pSMB->Reserved4 = 0;
1976 pSMB->hdr.smb_buf_length += byte_count;
1977 pSMB->ByteCount = cpu_to_le16(byte_count);
1978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001980 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 if (rc) {
1982 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1983 }
1984
1985 cifs_buf_release(pSMB);
1986 if (rc == -EAGAIN)
1987 goto createHardLinkRetry;
1988
1989 return rc;
1990}
1991
1992int
1993CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1994 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001995 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996{
1997 int rc = 0;
1998 NT_RENAME_REQ *pSMB = NULL;
1999 RENAME_RSP *pSMBr = NULL;
2000 int bytes_returned;
2001 int name_len, name_len2;
2002 __u16 count;
2003
2004 cFYI(1, ("In CIFSCreateHardLink"));
2005winCreateHardLinkRetry:
2006
2007 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2008 (void **) &pSMBr);
2009 if (rc)
2010 return rc;
2011
2012 pSMB->SearchAttributes =
2013 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2014 ATTR_DIRECTORY);
2015 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2016 pSMB->ClusterCount = 0;
2017
2018 pSMB->BufferFormat = 0x04;
2019
2020 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2021 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002022 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002023 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 name_len++; /* trailing null */
2025 name_len *= 2;
2026 pSMB->OldFileName[name_len] = 0; /* pad */
2027 pSMB->OldFileName[name_len + 1] = 0x04;
2028 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002029 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002030 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2032 name_len2 *= 2; /* convert to bytes */
2033 } else { /* BB improve the check for buffer overruns BB */
2034 name_len = strnlen(fromName, PATH_MAX);
2035 name_len++; /* trailing null */
2036 strncpy(pSMB->OldFileName, fromName, name_len);
2037 name_len2 = strnlen(toName, PATH_MAX);
2038 name_len2++; /* trailing null */
2039 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2040 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2041 name_len2++; /* trailing null */
2042 name_len2++; /* signature byte */
2043 }
2044
2045 count = 1 /* string type byte */ + name_len + name_len2;
2046 pSMB->hdr.smb_buf_length += count;
2047 pSMB->ByteCount = cpu_to_le16(count);
2048
2049 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2050 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002051 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 if (rc) {
2053 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2054 }
2055 cifs_buf_release(pSMB);
2056 if (rc == -EAGAIN)
2057 goto winCreateHardLinkRetry;
2058
2059 return rc;
2060}
2061
2062int
2063CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2064 const unsigned char *searchName,
2065 char *symlinkinfo, const int buflen,
2066 const struct nls_table *nls_codepage)
2067{
2068/* SMB_QUERY_FILE_UNIX_LINK */
2069 TRANSACTION2_QPI_REQ *pSMB = NULL;
2070 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2071 int rc = 0;
2072 int bytes_returned;
2073 int name_len;
2074 __u16 params, byte_count;
2075
2076 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2077
2078querySymLinkRetry:
2079 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2080 (void **) &pSMBr);
2081 if (rc)
2082 return rc;
2083
2084 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2085 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002086 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 /* find define for this maxpathcomponent */
2088 , nls_codepage);
2089 name_len++; /* trailing null */
2090 name_len *= 2;
2091 } else { /* BB improve the check for buffer overruns BB */
2092 name_len = strnlen(searchName, PATH_MAX);
2093 name_len++; /* trailing null */
2094 strncpy(pSMB->FileName, searchName, name_len);
2095 }
2096
2097 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2098 pSMB->TotalDataCount = 0;
2099 pSMB->MaxParameterCount = cpu_to_le16(2);
2100 /* BB find exact max data count below from sess structure BB */
2101 pSMB->MaxDataCount = cpu_to_le16(4000);
2102 pSMB->MaxSetupCount = 0;
2103 pSMB->Reserved = 0;
2104 pSMB->Flags = 0;
2105 pSMB->Timeout = 0;
2106 pSMB->Reserved2 = 0;
2107 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2108 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2109 pSMB->DataCount = 0;
2110 pSMB->DataOffset = 0;
2111 pSMB->SetupCount = 1;
2112 pSMB->Reserved3 = 0;
2113 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2114 byte_count = params + 1 /* pad */ ;
2115 pSMB->TotalParameterCount = cpu_to_le16(params);
2116 pSMB->ParameterCount = pSMB->TotalParameterCount;
2117 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2118 pSMB->Reserved4 = 0;
2119 pSMB->hdr.smb_buf_length += byte_count;
2120 pSMB->ByteCount = cpu_to_le16(byte_count);
2121
2122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2124 if (rc) {
2125 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2126 } else {
2127 /* decode response */
2128
2129 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2130 if (rc || (pSMBr->ByteCount < 2))
2131 /* BB also check enough total bytes returned */
2132 rc = -EIO; /* bad smb */
2133 else {
2134 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2135 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2136
2137 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2138 name_len = UniStrnlen((wchar_t *) ((char *)
2139 &pSMBr->hdr.Protocol +data_offset),
2140 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002141 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002143 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 data_offset),
2145 name_len, nls_codepage);
2146 } else {
2147 strncpy(symlinkinfo,
2148 (char *) &pSMBr->hdr.Protocol +
2149 data_offset,
2150 min_t(const int, buflen, count));
2151 }
2152 symlinkinfo[buflen] = 0;
2153 /* just in case so calling code does not go off the end of buffer */
2154 }
2155 }
2156 cifs_buf_release(pSMB);
2157 if (rc == -EAGAIN)
2158 goto querySymLinkRetry;
2159 return rc;
2160}
2161
Steve French0a4b92c2006-01-12 15:44:21 -08002162/* Initialize NT TRANSACT SMB into small smb request buffer.
2163 This assumes that all NT TRANSACTS that we init here have
2164 total parm and data under about 400 bytes (to fit in small cifs
2165 buffer size), which is the case so far, it easily fits. NB:
2166 Setup words themselves and ByteCount
2167 MaxSetupCount (size of returned setup area) and
2168 MaxParameterCount (returned parms size) must be set by caller */
2169static int
2170smb_init_ntransact(const __u16 sub_command, const int setup_count,
2171 const int parm_len, struct cifsTconInfo *tcon,
2172 void ** ret_buf)
2173{
2174 int rc;
2175 __u32 temp_offset;
2176 struct smb_com_ntransact_req * pSMB;
2177
2178 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2179 (void **)&pSMB);
2180 if (rc)
2181 return rc;
2182 *ret_buf = (void *)pSMB;
2183 pSMB->Reserved = 0;
2184 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2185 pSMB->TotalDataCount = 0;
2186 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2187 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2188 pSMB->ParameterCount = pSMB->TotalParameterCount;
2189 pSMB->DataCount = pSMB->TotalDataCount;
2190 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2191 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2192 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2193 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2194 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2195 pSMB->SubCommand = cpu_to_le16(sub_command);
2196 return 0;
2197}
2198
2199static int
2200validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2201 int * pdatalen, int * pparmlen)
2202{
2203 char * end_of_smb;
2204 __u32 data_count, data_offset, parm_count, parm_offset;
2205 struct smb_com_ntransact_rsp * pSMBr;
2206
2207 if(buf == NULL)
2208 return -EINVAL;
2209
2210 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2211
2212 /* ByteCount was converted from little endian in SendReceive */
2213 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2214 (char *)&pSMBr->ByteCount;
2215
2216
2217 data_offset = le32_to_cpu(pSMBr->DataOffset);
2218 data_count = le32_to_cpu(pSMBr->DataCount);
2219 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2220 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2221
2222 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2223 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2224
2225 /* should we also check that parm and data areas do not overlap? */
2226 if(*ppparm > end_of_smb) {
2227 cFYI(1,("parms start after end of smb"));
2228 return -EINVAL;
2229 } else if(parm_count + *ppparm > end_of_smb) {
2230 cFYI(1,("parm end after end of smb"));
2231 return -EINVAL;
2232 } else if(*ppdata > end_of_smb) {
2233 cFYI(1,("data starts after end of smb"));
2234 return -EINVAL;
2235 } else if(data_count + *ppdata > end_of_smb) {
2236 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2237 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2238 return -EINVAL;
2239 } else if(parm_count + data_count > pSMBr->ByteCount) {
2240 cFYI(1,("parm count and data count larger than SMB"));
2241 return -EINVAL;
2242 }
2243 return 0;
2244}
2245
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246int
2247CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2248 const unsigned char *searchName,
2249 char *symlinkinfo, const int buflen,__u16 fid,
2250 const struct nls_table *nls_codepage)
2251{
2252 int rc = 0;
2253 int bytes_returned;
2254 int name_len;
2255 struct smb_com_transaction_ioctl_req * pSMB;
2256 struct smb_com_transaction_ioctl_rsp * pSMBr;
2257
2258 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2259 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2260 (void **) &pSMBr);
2261 if (rc)
2262 return rc;
2263
2264 pSMB->TotalParameterCount = 0 ;
2265 pSMB->TotalDataCount = 0;
2266 pSMB->MaxParameterCount = cpu_to_le32(2);
2267 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002268 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2269 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 pSMB->MaxSetupCount = 4;
2271 pSMB->Reserved = 0;
2272 pSMB->ParameterOffset = 0;
2273 pSMB->DataCount = 0;
2274 pSMB->DataOffset = 0;
2275 pSMB->SetupCount = 4;
2276 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2277 pSMB->ParameterCount = pSMB->TotalParameterCount;
2278 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2279 pSMB->IsFsctl = 1; /* FSCTL */
2280 pSMB->IsRootFlag = 0;
2281 pSMB->Fid = fid; /* file handle always le */
2282 pSMB->ByteCount = 0;
2283
2284 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2285 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2286 if (rc) {
2287 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2288 } else { /* decode response */
2289 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2290 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2291 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2292 /* BB also check enough total bytes returned */
2293 rc = -EIO; /* bad smb */
2294 else {
2295 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002296 char * end_of_smb = 2 /* sizeof byte count */ +
2297 pSMBr->ByteCount +
2298 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
2300 struct reparse_data * reparse_buf = (struct reparse_data *)
2301 ((char *)&pSMBr->hdr.Protocol + data_offset);
2302 if((char*)reparse_buf >= end_of_smb) {
2303 rc = -EIO;
2304 goto qreparse_out;
2305 }
2306 if((reparse_buf->LinkNamesBuf +
2307 reparse_buf->TargetNameOffset +
2308 reparse_buf->TargetNameLen) >
2309 end_of_smb) {
2310 cFYI(1,("reparse buf extended beyond SMB"));
2311 rc = -EIO;
2312 goto qreparse_out;
2313 }
2314
2315 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2316 name_len = UniStrnlen((wchar_t *)
2317 (reparse_buf->LinkNamesBuf +
2318 reparse_buf->TargetNameOffset),
2319 min(buflen/2, reparse_buf->TargetNameLen / 2));
2320 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002321 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 reparse_buf->TargetNameOffset),
2323 name_len, nls_codepage);
2324 } else { /* ASCII names */
2325 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2326 reparse_buf->TargetNameOffset,
2327 min_t(const int, buflen, reparse_buf->TargetNameLen));
2328 }
2329 } else {
2330 rc = -EIO;
2331 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2332 }
2333 symlinkinfo[buflen] = 0; /* just in case so the caller
2334 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002335 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 }
2337 }
2338qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002339 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
2341 /* Note: On -EAGAIN error only caller can retry on handle based calls
2342 since file handle passed in no longer valid */
2343
2344 return rc;
2345}
2346
2347#ifdef CONFIG_CIFS_POSIX
2348
2349/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2350static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2351{
2352 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002353 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2354 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2355 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2357
2358 return;
2359}
2360
2361/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002362static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2363 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364{
2365 int size = 0;
2366 int i;
2367 __u16 count;
2368 struct cifs_posix_ace * pACE;
2369 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2370 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2371
2372 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2373 return -EOPNOTSUPP;
2374
2375 if(acl_type & ACL_TYPE_ACCESS) {
2376 count = le16_to_cpu(cifs_acl->access_entry_count);
2377 pACE = &cifs_acl->ace_array[0];
2378 size = sizeof(struct cifs_posix_acl);
2379 size += sizeof(struct cifs_posix_ace) * count;
2380 /* check if we would go beyond end of SMB */
2381 if(size_of_data_area < size) {
2382 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2383 return -EINVAL;
2384 }
2385 } else if(acl_type & ACL_TYPE_DEFAULT) {
2386 count = le16_to_cpu(cifs_acl->access_entry_count);
2387 size = sizeof(struct cifs_posix_acl);
2388 size += sizeof(struct cifs_posix_ace) * count;
2389/* skip past access ACEs to get to default ACEs */
2390 pACE = &cifs_acl->ace_array[count];
2391 count = le16_to_cpu(cifs_acl->default_entry_count);
2392 size += sizeof(struct cifs_posix_ace) * count;
2393 /* check if we would go beyond end of SMB */
2394 if(size_of_data_area < size)
2395 return -EINVAL;
2396 } else {
2397 /* illegal type */
2398 return -EINVAL;
2399 }
2400
2401 size = posix_acl_xattr_size(count);
2402 if((buflen == 0) || (local_acl == NULL)) {
2403 /* used to query ACL EA size */
2404 } else if(size > buflen) {
2405 return -ERANGE;
2406 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002407 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 for(i = 0;i < count ;i++) {
2409 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2410 pACE ++;
2411 }
2412 }
2413 return size;
2414}
2415
2416static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2417 const posix_acl_xattr_entry * local_ace)
2418{
2419 __u16 rc = 0; /* 0 = ACL converted ok */
2420
Steve Frenchff7feac2005-11-15 16:45:16 -08002421 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2422 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002424 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 /* Probably no need to le convert -1 on any arch but can not hurt */
2426 cifs_ace->cifs_uid = cpu_to_le64(-1);
2427 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002428 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2430 return rc;
2431}
2432
2433/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2434static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2435 const int acl_type)
2436{
2437 __u16 rc = 0;
2438 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2439 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2440 int count;
2441 int i;
2442
2443 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2444 return 0;
2445
2446 count = posix_acl_xattr_count((size_t)buflen);
2447 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002448 count, buflen, le32_to_cpu(local_acl->a_version)));
2449 if(le32_to_cpu(local_acl->a_version) != 2) {
2450 cFYI(1,("unknown POSIX ACL version %d",
2451 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 return 0;
2453 }
2454 cifs_acl->version = cpu_to_le16(1);
2455 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002456 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002458 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 else {
2460 cFYI(1,("unknown ACL type %d",acl_type));
2461 return 0;
2462 }
2463 for(i=0;i<count;i++) {
2464 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2465 &local_acl->a_entries[i]);
2466 if(rc != 0) {
2467 /* ACE not converted */
2468 break;
2469 }
2470 }
2471 if(rc == 0) {
2472 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2473 rc += sizeof(struct cifs_posix_acl);
2474 /* BB add check to make sure ACL does not overflow SMB */
2475 }
2476 return rc;
2477}
2478
2479int
2480CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2481 const unsigned char *searchName,
2482 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002483 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484{
2485/* SMB_QUERY_POSIX_ACL */
2486 TRANSACTION2_QPI_REQ *pSMB = NULL;
2487 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2488 int rc = 0;
2489 int bytes_returned;
2490 int name_len;
2491 __u16 params, byte_count;
2492
2493 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2494
2495queryAclRetry:
2496 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2497 (void **) &pSMBr);
2498 if (rc)
2499 return rc;
2500
2501 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2502 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002503 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002504 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 name_len++; /* trailing null */
2506 name_len *= 2;
2507 pSMB->FileName[name_len] = 0;
2508 pSMB->FileName[name_len+1] = 0;
2509 } else { /* BB improve the check for buffer overruns BB */
2510 name_len = strnlen(searchName, PATH_MAX);
2511 name_len++; /* trailing null */
2512 strncpy(pSMB->FileName, searchName, name_len);
2513 }
2514
2515 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2516 pSMB->TotalDataCount = 0;
2517 pSMB->MaxParameterCount = cpu_to_le16(2);
2518 /* BB find exact max data count below from sess structure BB */
2519 pSMB->MaxDataCount = cpu_to_le16(4000);
2520 pSMB->MaxSetupCount = 0;
2521 pSMB->Reserved = 0;
2522 pSMB->Flags = 0;
2523 pSMB->Timeout = 0;
2524 pSMB->Reserved2 = 0;
2525 pSMB->ParameterOffset = cpu_to_le16(
2526 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2527 pSMB->DataCount = 0;
2528 pSMB->DataOffset = 0;
2529 pSMB->SetupCount = 1;
2530 pSMB->Reserved3 = 0;
2531 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2532 byte_count = params + 1 /* pad */ ;
2533 pSMB->TotalParameterCount = cpu_to_le16(params);
2534 pSMB->ParameterCount = pSMB->TotalParameterCount;
2535 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2536 pSMB->Reserved4 = 0;
2537 pSMB->hdr.smb_buf_length += byte_count;
2538 pSMB->ByteCount = cpu_to_le16(byte_count);
2539
2540 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2541 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002542 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 if (rc) {
2544 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2545 } else {
2546 /* decode response */
2547
2548 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2549 if (rc || (pSMBr->ByteCount < 2))
2550 /* BB also check enough total bytes returned */
2551 rc = -EIO; /* bad smb */
2552 else {
2553 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2554 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2555 rc = cifs_copy_posix_acl(acl_inf,
2556 (char *)&pSMBr->hdr.Protocol+data_offset,
2557 buflen,acl_type,count);
2558 }
2559 }
2560 cifs_buf_release(pSMB);
2561 if (rc == -EAGAIN)
2562 goto queryAclRetry;
2563 return rc;
2564}
2565
2566int
2567CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2568 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002569 const char *local_acl, const int buflen,
2570 const int acl_type,
2571 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572{
2573 struct smb_com_transaction2_spi_req *pSMB = NULL;
2574 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2575 char *parm_data;
2576 int name_len;
2577 int rc = 0;
2578 int bytes_returned = 0;
2579 __u16 params, byte_count, data_count, param_offset, offset;
2580
2581 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2582setAclRetry:
2583 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2584 (void **) &pSMBr);
2585 if (rc)
2586 return rc;
2587 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2588 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002589 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002590 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 name_len++; /* trailing null */
2592 name_len *= 2;
2593 } else { /* BB improve the check for buffer overruns BB */
2594 name_len = strnlen(fileName, PATH_MAX);
2595 name_len++; /* trailing null */
2596 strncpy(pSMB->FileName, fileName, name_len);
2597 }
2598 params = 6 + name_len;
2599 pSMB->MaxParameterCount = cpu_to_le16(2);
2600 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2601 pSMB->MaxSetupCount = 0;
2602 pSMB->Reserved = 0;
2603 pSMB->Flags = 0;
2604 pSMB->Timeout = 0;
2605 pSMB->Reserved2 = 0;
2606 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2607 InformationLevel) - 4;
2608 offset = param_offset + params;
2609 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2610 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2611
2612 /* convert to on the wire format for POSIX ACL */
2613 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2614
2615 if(data_count == 0) {
2616 rc = -EOPNOTSUPP;
2617 goto setACLerrorExit;
2618 }
2619 pSMB->DataOffset = cpu_to_le16(offset);
2620 pSMB->SetupCount = 1;
2621 pSMB->Reserved3 = 0;
2622 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2623 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2624 byte_count = 3 /* pad */ + params + data_count;
2625 pSMB->DataCount = cpu_to_le16(data_count);
2626 pSMB->TotalDataCount = pSMB->DataCount;
2627 pSMB->ParameterCount = cpu_to_le16(params);
2628 pSMB->TotalParameterCount = pSMB->ParameterCount;
2629 pSMB->Reserved4 = 0;
2630 pSMB->hdr.smb_buf_length += byte_count;
2631 pSMB->ByteCount = cpu_to_le16(byte_count);
2632 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2633 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2634 if (rc) {
2635 cFYI(1, ("Set POSIX ACL returned %d", rc));
2636 }
2637
2638setACLerrorExit:
2639 cifs_buf_release(pSMB);
2640 if (rc == -EAGAIN)
2641 goto setAclRetry;
2642 return rc;
2643}
2644
Steve Frenchf654bac2005-04-28 22:41:04 -07002645/* BB fix tabs in this function FIXME BB */
2646int
2647CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2648 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2649{
2650 int rc = 0;
2651 struct smb_t2_qfi_req *pSMB = NULL;
2652 struct smb_t2_qfi_rsp *pSMBr = NULL;
2653 int bytes_returned;
2654 __u16 params, byte_count;
2655
2656 cFYI(1,("In GetExtAttr"));
2657 if(tcon == NULL)
2658 return -ENODEV;
2659
2660GetExtAttrRetry:
2661 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2662 (void **) &pSMBr);
2663 if (rc)
2664 return rc;
2665
Steve Frenchc67593a2005-04-28 22:41:04 -07002666 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002667 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002668 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002669 /* BB find exact max data count below from sess structure BB */
2670 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2671 pSMB->t2.MaxSetupCount = 0;
2672 pSMB->t2.Reserved = 0;
2673 pSMB->t2.Flags = 0;
2674 pSMB->t2.Timeout = 0;
2675 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002676 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2677 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002678 pSMB->t2.DataCount = 0;
2679 pSMB->t2.DataOffset = 0;
2680 pSMB->t2.SetupCount = 1;
2681 pSMB->t2.Reserved3 = 0;
2682 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002683 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002684 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2685 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2686 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002687 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002688 pSMB->Fid = netfid;
2689 pSMB->hdr.smb_buf_length += byte_count;
2690 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2691
2692 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2693 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2694 if (rc) {
2695 cFYI(1, ("error %d in GetExtAttr", rc));
2696 } else {
2697 /* decode response */
2698 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2699 if (rc || (pSMBr->ByteCount < 2))
2700 /* BB also check enough total bytes returned */
2701 /* If rc should we check for EOPNOSUPP and
2702 disable the srvino flag? or in caller? */
2703 rc = -EIO; /* bad smb */
2704 else {
2705 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2706 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2707 struct file_chattr_info * pfinfo;
2708 /* BB Do we need a cast or hash here ? */
2709 if(count != 16) {
2710 cFYI(1, ("Illegal size ret in GetExtAttr"));
2711 rc = -EIO;
2712 goto GetExtAttrOut;
2713 }
2714 pfinfo = (struct file_chattr_info *)
2715 (data_offset + (char *) &pSMBr->hdr.Protocol);
2716 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2717 *pMask = le64_to_cpu(pfinfo->mask);
2718 }
2719 }
2720GetExtAttrOut:
2721 cifs_buf_release(pSMB);
2722 if (rc == -EAGAIN)
2723 goto GetExtAttrRetry;
2724 return rc;
2725}
2726
2727
2728#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
Steve Frencheeac8042006-01-13 21:34:58 -08002730
2731/* security id for everyone */
2732const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2733/* group users */
2734const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2735
Steve French0a4b92c2006-01-12 15:44:21 -08002736/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002737static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002738{
Steve French0a4b92c2006-01-12 15:44:21 -08002739 return 0;
2740}
2741
2742/* Get Security Descriptor (by handle) from remote server for a file or dir */
2743int
2744CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2745 /* BB fix up return info */ char *acl_inf, const int buflen,
2746 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2747{
2748 int rc = 0;
2749 int buf_type = 0;
2750 QUERY_SEC_DESC_REQ * pSMB;
2751 struct kvec iov[1];
2752
2753 cFYI(1, ("GetCifsACL"));
2754
2755 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2756 8 /* parm len */, tcon, (void **) &pSMB);
2757 if (rc)
2758 return rc;
2759
2760 pSMB->MaxParameterCount = cpu_to_le32(4);
2761 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2762 pSMB->MaxSetupCount = 0;
2763 pSMB->Fid = fid; /* file handle always le */
2764 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2765 CIFS_ACL_DACL);
2766 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2767 pSMB->hdr.smb_buf_length += 11;
2768 iov[0].iov_base = (char *)pSMB;
2769 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2770
2771 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2772 cifs_stats_inc(&tcon->num_acl_get);
2773 if (rc) {
2774 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2775 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002776 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002777 __le32 * parm;
2778 int parm_len;
2779 int data_len;
2780 int acl_len;
2781 struct smb_com_ntransact_rsp * pSMBr;
2782
2783/* validate_nttransact */
2784 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2785 (char **)&psec_desc,
2786 &parm_len, &data_len);
2787
2788 if(rc)
2789 goto qsec_out;
2790 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2791
2792 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2793
2794 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2795 rc = -EIO; /* bad smb */
2796 goto qsec_out;
2797 }
2798
2799/* BB check that data area is minimum length and as big as acl_len */
2800
2801 acl_len = le32_to_cpu(*(__le32 *)parm);
2802 /* BB check if(acl_len > bufsize) */
2803
2804 parse_sec_desc(psec_desc, acl_len);
2805 }
2806qsec_out:
2807 if(buf_type == CIFS_SMALL_BUFFER)
2808 cifs_small_buf_release(iov[0].iov_base);
2809 else if(buf_type == CIFS_LARGE_BUFFER)
2810 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002811/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002812 return rc;
2813}
2814
2815
Steve French6b8edfe2005-08-23 20:26:03 -07002816/* Legacy Query Path Information call for lookup to old servers such
2817 as Win9x/WinME */
2818int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2819 const unsigned char *searchName,
2820 FILE_ALL_INFO * pFinfo,
2821 const struct nls_table *nls_codepage, int remap)
2822{
2823 QUERY_INFORMATION_REQ * pSMB;
2824 QUERY_INFORMATION_RSP * pSMBr;
2825 int rc = 0;
2826 int bytes_returned;
2827 int name_len;
2828
2829 cFYI(1, ("In SMBQPath path %s", searchName));
2830QInfRetry:
2831 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2832 (void **) &pSMBr);
2833 if (rc)
2834 return rc;
2835
2836 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2837 name_len =
2838 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2839 PATH_MAX, nls_codepage, remap);
2840 name_len++; /* trailing null */
2841 name_len *= 2;
2842 } else {
2843 name_len = strnlen(searchName, PATH_MAX);
2844 name_len++; /* trailing null */
2845 strncpy(pSMB->FileName, searchName, name_len);
2846 }
2847 pSMB->BufferFormat = 0x04;
2848 name_len++; /* account for buffer type byte */
2849 pSMB->hdr.smb_buf_length += (__u16) name_len;
2850 pSMB->ByteCount = cpu_to_le16(name_len);
2851
2852 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2853 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2854 if (rc) {
2855 cFYI(1, ("Send error in QueryInfo = %d", rc));
2856 } else if (pFinfo) { /* decode response */
2857 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002858 pFinfo->AllocationSize =
2859 cpu_to_le64(le32_to_cpu(pSMBr->size));
2860 pFinfo->EndOfFile = pFinfo->AllocationSize;
2861 pFinfo->Attributes =
2862 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002863 } else
2864 rc = -EIO; /* bad buffer passed in */
2865
2866 cifs_buf_release(pSMB);
2867
2868 if (rc == -EAGAIN)
2869 goto QInfRetry;
2870
2871 return rc;
2872}
2873
2874
2875
2876
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877int
2878CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2879 const unsigned char *searchName,
2880 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002881 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882{
2883/* level 263 SMB_QUERY_FILE_ALL_INFO */
2884 TRANSACTION2_QPI_REQ *pSMB = NULL;
2885 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2886 int rc = 0;
2887 int bytes_returned;
2888 int name_len;
2889 __u16 params, byte_count;
2890
2891/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2892QPathInfoRetry:
2893 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2894 (void **) &pSMBr);
2895 if (rc)
2896 return rc;
2897
2898 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2899 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002900 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002901 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 name_len++; /* trailing null */
2903 name_len *= 2;
2904 } else { /* BB improve the check for buffer overruns BB */
2905 name_len = strnlen(searchName, PATH_MAX);
2906 name_len++; /* trailing null */
2907 strncpy(pSMB->FileName, searchName, name_len);
2908 }
2909
2910 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2911 pSMB->TotalDataCount = 0;
2912 pSMB->MaxParameterCount = cpu_to_le16(2);
2913 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2914 pSMB->MaxSetupCount = 0;
2915 pSMB->Reserved = 0;
2916 pSMB->Flags = 0;
2917 pSMB->Timeout = 0;
2918 pSMB->Reserved2 = 0;
2919 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2920 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2921 pSMB->DataCount = 0;
2922 pSMB->DataOffset = 0;
2923 pSMB->SetupCount = 1;
2924 pSMB->Reserved3 = 0;
2925 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2926 byte_count = params + 1 /* pad */ ;
2927 pSMB->TotalParameterCount = cpu_to_le16(params);
2928 pSMB->ParameterCount = pSMB->TotalParameterCount;
2929 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2930 pSMB->Reserved4 = 0;
2931 pSMB->hdr.smb_buf_length += byte_count;
2932 pSMB->ByteCount = cpu_to_le16(byte_count);
2933
2934 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2935 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2936 if (rc) {
2937 cFYI(1, ("Send error in QPathInfo = %d", rc));
2938 } else { /* decode response */
2939 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2940
2941 if (rc || (pSMBr->ByteCount < 40))
2942 rc = -EIO; /* bad smb */
2943 else if (pFindData){
2944 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2945 memcpy((char *) pFindData,
2946 (char *) &pSMBr->hdr.Protocol +
2947 data_offset, sizeof (FILE_ALL_INFO));
2948 } else
2949 rc = -ENOMEM;
2950 }
2951 cifs_buf_release(pSMB);
2952 if (rc == -EAGAIN)
2953 goto QPathInfoRetry;
2954
2955 return rc;
2956}
2957
2958int
2959CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2960 const unsigned char *searchName,
2961 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002962 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963{
2964/* SMB_QUERY_FILE_UNIX_BASIC */
2965 TRANSACTION2_QPI_REQ *pSMB = NULL;
2966 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2967 int rc = 0;
2968 int bytes_returned = 0;
2969 int name_len;
2970 __u16 params, byte_count;
2971
2972 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2973UnixQPathInfoRetry:
2974 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2975 (void **) &pSMBr);
2976 if (rc)
2977 return rc;
2978
2979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2980 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002981 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 name_len++; /* trailing null */
2984 name_len *= 2;
2985 } else { /* BB improve the check for buffer overruns BB */
2986 name_len = strnlen(searchName, PATH_MAX);
2987 name_len++; /* trailing null */
2988 strncpy(pSMB->FileName, searchName, name_len);
2989 }
2990
2991 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2992 pSMB->TotalDataCount = 0;
2993 pSMB->MaxParameterCount = cpu_to_le16(2);
2994 /* BB find exact max SMB PDU from sess structure BB */
2995 pSMB->MaxDataCount = cpu_to_le16(4000);
2996 pSMB->MaxSetupCount = 0;
2997 pSMB->Reserved = 0;
2998 pSMB->Flags = 0;
2999 pSMB->Timeout = 0;
3000 pSMB->Reserved2 = 0;
3001 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3002 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3003 pSMB->DataCount = 0;
3004 pSMB->DataOffset = 0;
3005 pSMB->SetupCount = 1;
3006 pSMB->Reserved3 = 0;
3007 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3008 byte_count = params + 1 /* pad */ ;
3009 pSMB->TotalParameterCount = cpu_to_le16(params);
3010 pSMB->ParameterCount = pSMB->TotalParameterCount;
3011 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3012 pSMB->Reserved4 = 0;
3013 pSMB->hdr.smb_buf_length += byte_count;
3014 pSMB->ByteCount = cpu_to_le16(byte_count);
3015
3016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3018 if (rc) {
3019 cFYI(1, ("Send error in QPathInfo = %d", rc));
3020 } else { /* decode response */
3021 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3022
3023 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3024 rc = -EIO; /* bad smb */
3025 } else {
3026 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3027 memcpy((char *) pFindData,
3028 (char *) &pSMBr->hdr.Protocol +
3029 data_offset,
3030 sizeof (FILE_UNIX_BASIC_INFO));
3031 }
3032 }
3033 cifs_buf_release(pSMB);
3034 if (rc == -EAGAIN)
3035 goto UnixQPathInfoRetry;
3036
3037 return rc;
3038}
3039
3040#if 0 /* function unused at present */
3041int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3042 const char *searchName, FILE_ALL_INFO * findData,
3043 const struct nls_table *nls_codepage)
3044{
3045/* level 257 SMB_ */
3046 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3047 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3048 int rc = 0;
3049 int bytes_returned;
3050 int name_len;
3051 __u16 params, byte_count;
3052
3053 cFYI(1, ("In FindUnique"));
3054findUniqueRetry:
3055 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3056 (void **) &pSMBr);
3057 if (rc)
3058 return rc;
3059
3060 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3061 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003062 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 /* find define for this maxpathcomponent */
3064 , nls_codepage);
3065 name_len++; /* trailing null */
3066 name_len *= 2;
3067 } else { /* BB improve the check for buffer overruns BB */
3068 name_len = strnlen(searchName, PATH_MAX);
3069 name_len++; /* trailing null */
3070 strncpy(pSMB->FileName, searchName, name_len);
3071 }
3072
3073 params = 12 + name_len /* includes null */ ;
3074 pSMB->TotalDataCount = 0; /* no EAs */
3075 pSMB->MaxParameterCount = cpu_to_le16(2);
3076 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3077 pSMB->MaxSetupCount = 0;
3078 pSMB->Reserved = 0;
3079 pSMB->Flags = 0;
3080 pSMB->Timeout = 0;
3081 pSMB->Reserved2 = 0;
3082 pSMB->ParameterOffset = cpu_to_le16(
3083 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3084 pSMB->DataCount = 0;
3085 pSMB->DataOffset = 0;
3086 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3087 pSMB->Reserved3 = 0;
3088 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3089 byte_count = params + 1 /* pad */ ;
3090 pSMB->TotalParameterCount = cpu_to_le16(params);
3091 pSMB->ParameterCount = pSMB->TotalParameterCount;
3092 pSMB->SearchAttributes =
3093 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3094 ATTR_DIRECTORY);
3095 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3096 pSMB->SearchFlags = cpu_to_le16(1);
3097 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3098 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3099 pSMB->hdr.smb_buf_length += byte_count;
3100 pSMB->ByteCount = cpu_to_le16(byte_count);
3101
3102 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3104
3105 if (rc) {
3106 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3107 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003108 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 /* BB fill in */
3110 }
3111
3112 cifs_buf_release(pSMB);
3113 if (rc == -EAGAIN)
3114 goto findUniqueRetry;
3115
3116 return rc;
3117}
3118#endif /* end unused (temporarily) function */
3119
3120/* xid, tcon, searchName and codepage are input parms, rest are returned */
3121int
3122CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3123 const char *searchName,
3124 const struct nls_table *nls_codepage,
3125 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003126 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127{
3128/* level 257 SMB_ */
3129 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3130 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3131 T2_FFIRST_RSP_PARMS * parms;
3132 int rc = 0;
3133 int bytes_returned = 0;
3134 int name_len;
3135 __u16 params, byte_count;
3136
Steve French737b7582005-04-28 22:41:06 -07003137 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
3139findFirstRetry:
3140 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3141 (void **) &pSMBr);
3142 if (rc)
3143 return rc;
3144
3145 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3146 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003147 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003148 PATH_MAX, nls_codepage, remap);
3149 /* We can not add the asterik earlier in case
3150 it got remapped to 0xF03A as if it were part of the
3151 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003153 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003154 pSMB->FileName[name_len+1] = 0;
3155 pSMB->FileName[name_len+2] = '*';
3156 pSMB->FileName[name_len+3] = 0;
3157 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3159 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003160 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 } else { /* BB add check for overrun of SMB buf BB */
3162 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163/* BB fix here and in unicode clause above ie
3164 if(name_len > buffersize-header)
3165 free buffer exit; BB */
3166 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003167 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003168 pSMB->FileName[name_len+1] = '*';
3169 pSMB->FileName[name_len+2] = 0;
3170 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 }
3172
3173 params = 12 + name_len /* includes null */ ;
3174 pSMB->TotalDataCount = 0; /* no EAs */
3175 pSMB->MaxParameterCount = cpu_to_le16(10);
3176 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3177 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3178 pSMB->MaxSetupCount = 0;
3179 pSMB->Reserved = 0;
3180 pSMB->Flags = 0;
3181 pSMB->Timeout = 0;
3182 pSMB->Reserved2 = 0;
3183 byte_count = params + 1 /* pad */ ;
3184 pSMB->TotalParameterCount = cpu_to_le16(params);
3185 pSMB->ParameterCount = pSMB->TotalParameterCount;
3186 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003187 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3188 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 pSMB->DataCount = 0;
3190 pSMB->DataOffset = 0;
3191 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3192 pSMB->Reserved3 = 0;
3193 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3194 pSMB->SearchAttributes =
3195 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3196 ATTR_DIRECTORY);
3197 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3198 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3199 CIFS_SEARCH_RETURN_RESUME);
3200 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3201
3202 /* BB what should we set StorageType to? Does it matter? BB */
3203 pSMB->SearchStorageType = 0;
3204 pSMB->hdr.smb_buf_length += byte_count;
3205 pSMB->ByteCount = cpu_to_le16(byte_count);
3206
3207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003209 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210
Steve French88274812006-03-09 22:21:45 +00003211 if (rc) {/* BB add logic to retry regular search if Unix search
3212 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 /* BB Add code to handle unsupported level rc */
3214 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003215
Steve French88274812006-03-09 22:21:45 +00003216 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
3218 /* BB eventually could optimize out free and realloc of buf */
3219 /* for this case */
3220 if (rc == -EAGAIN)
3221 goto findFirstRetry;
3222 } else { /* decode response */
3223 /* BB remember to free buffer if error BB */
3224 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3225 if(rc == 0) {
3226 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3227 psrch_inf->unicode = TRUE;
3228 else
3229 psrch_inf->unicode = FALSE;
3230
3231 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003232 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 psrch_inf->srch_entries_start =
3234 (char *) &pSMBr->hdr.Protocol +
3235 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3237 le16_to_cpu(pSMBr->t2.ParameterOffset));
3238
3239 if(parms->EndofSearch)
3240 psrch_inf->endOfSearch = TRUE;
3241 else
3242 psrch_inf->endOfSearch = FALSE;
3243
3244 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003245 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 *pnetfid = parms->SearchHandle;
3248 } else {
3249 cifs_buf_release(pSMB);
3250 }
3251 }
3252
3253 return rc;
3254}
3255
3256int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3257 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3258{
3259 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3260 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3261 T2_FNEXT_RSP_PARMS * parms;
3262 char *response_data;
3263 int rc = 0;
3264 int bytes_returned, name_len;
3265 __u16 params, byte_count;
3266
3267 cFYI(1, ("In FindNext"));
3268
3269 if(psrch_inf->endOfSearch == TRUE)
3270 return -ENOENT;
3271
3272 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3273 (void **) &pSMBr);
3274 if (rc)
3275 return rc;
3276
3277 params = 14; /* includes 2 bytes of null string, converted to LE below */
3278 byte_count = 0;
3279 pSMB->TotalDataCount = 0; /* no EAs */
3280 pSMB->MaxParameterCount = cpu_to_le16(8);
3281 pSMB->MaxDataCount =
3282 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3283 pSMB->MaxSetupCount = 0;
3284 pSMB->Reserved = 0;
3285 pSMB->Flags = 0;
3286 pSMB->Timeout = 0;
3287 pSMB->Reserved2 = 0;
3288 pSMB->ParameterOffset = cpu_to_le16(
3289 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3290 pSMB->DataCount = 0;
3291 pSMB->DataOffset = 0;
3292 pSMB->SetupCount = 1;
3293 pSMB->Reserved3 = 0;
3294 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3295 pSMB->SearchHandle = searchHandle; /* always kept as le */
3296 pSMB->SearchCount =
3297 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3298 /* test for Unix extensions */
3299/* if (tcon->ses->capabilities & CAP_UNIX) {
3300 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3301 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3302 } else {
3303 pSMB->InformationLevel =
3304 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3305 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3306 } */
3307 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3308 pSMB->ResumeKey = psrch_inf->resume_key;
3309 pSMB->SearchFlags =
3310 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3311
3312 name_len = psrch_inf->resume_name_len;
3313 params += name_len;
3314 if(name_len < PATH_MAX) {
3315 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3316 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003317 /* 14 byte parm len above enough for 2 byte null terminator */
3318 pSMB->ResumeFileName[name_len] = 0;
3319 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 } else {
3321 rc = -EINVAL;
3322 goto FNext2_err_exit;
3323 }
3324 byte_count = params + 1 /* pad */ ;
3325 pSMB->TotalParameterCount = cpu_to_le16(params);
3326 pSMB->ParameterCount = pSMB->TotalParameterCount;
3327 pSMB->hdr.smb_buf_length += byte_count;
3328 pSMB->ByteCount = cpu_to_le16(byte_count);
3329
3330 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3331 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003332 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 if (rc) {
3334 if (rc == -EBADF) {
3335 psrch_inf->endOfSearch = TRUE;
3336 rc = 0; /* search probably was closed at end of search above */
3337 } else
3338 cFYI(1, ("FindNext returned = %d", rc));
3339 } else { /* decode response */
3340 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3341
3342 if(rc == 0) {
3343 /* BB fixme add lock for file (srch_info) struct here */
3344 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3345 psrch_inf->unicode = TRUE;
3346 else
3347 psrch_inf->unicode = FALSE;
3348 response_data = (char *) &pSMBr->hdr.Protocol +
3349 le16_to_cpu(pSMBr->t2.ParameterOffset);
3350 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3351 response_data = (char *)&pSMBr->hdr.Protocol +
3352 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003353 if(psrch_inf->smallBuf)
3354 cifs_small_buf_release(
3355 psrch_inf->ntwrk_buf_start);
3356 else
3357 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 psrch_inf->srch_entries_start = response_data;
3359 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003360 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 if(parms->EndofSearch)
3362 psrch_inf->endOfSearch = TRUE;
3363 else
3364 psrch_inf->endOfSearch = FALSE;
3365
3366 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3367 psrch_inf->index_of_last_entry +=
3368 psrch_inf->entries_in_buffer;
3369/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3370
3371 /* BB fixme add unlock here */
3372 }
3373
3374 }
3375
3376 /* BB On error, should we leave previous search buf (and count and
3377 last entry fields) intact or free the previous one? */
3378
3379 /* Note: On -EAGAIN error only caller can retry on handle based calls
3380 since file handle passed in no longer valid */
3381FNext2_err_exit:
3382 if (rc != 0)
3383 cifs_buf_release(pSMB);
3384
3385 return rc;
3386}
3387
3388int
3389CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3390{
3391 int rc = 0;
3392 FINDCLOSE_REQ *pSMB = NULL;
3393 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3394 int bytes_returned;
3395
3396 cFYI(1, ("In CIFSSMBFindClose"));
3397 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3398
3399 /* no sense returning error if session restarted
3400 as file handle has been closed */
3401 if(rc == -EAGAIN)
3402 return 0;
3403 if (rc)
3404 return rc;
3405
3406 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3407 pSMB->FileID = searchHandle;
3408 pSMB->ByteCount = 0;
3409 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3410 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3411 if (rc) {
3412 cERROR(1, ("Send error in FindClose = %d", rc));
3413 }
Steve Frencha4544342005-08-24 13:59:35 -07003414 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 cifs_small_buf_release(pSMB);
3416
3417 /* Since session is dead, search handle closed on server already */
3418 if (rc == -EAGAIN)
3419 rc = 0;
3420
3421 return rc;
3422}
3423
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424int
3425CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3426 const unsigned char *searchName,
3427 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003428 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429{
3430 int rc = 0;
3431 TRANSACTION2_QPI_REQ *pSMB = NULL;
3432 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3433 int name_len, bytes_returned;
3434 __u16 params, byte_count;
3435
3436 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3437 if(tcon == NULL)
3438 return -ENODEV;
3439
3440GetInodeNumberRetry:
3441 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3442 (void **) &pSMBr);
3443 if (rc)
3444 return rc;
3445
3446
3447 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3448 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003449 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003450 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 name_len++; /* trailing null */
3452 name_len *= 2;
3453 } else { /* BB improve the check for buffer overruns BB */
3454 name_len = strnlen(searchName, PATH_MAX);
3455 name_len++; /* trailing null */
3456 strncpy(pSMB->FileName, searchName, name_len);
3457 }
3458
3459 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3460 pSMB->TotalDataCount = 0;
3461 pSMB->MaxParameterCount = cpu_to_le16(2);
3462 /* BB find exact max data count below from sess structure BB */
3463 pSMB->MaxDataCount = cpu_to_le16(4000);
3464 pSMB->MaxSetupCount = 0;
3465 pSMB->Reserved = 0;
3466 pSMB->Flags = 0;
3467 pSMB->Timeout = 0;
3468 pSMB->Reserved2 = 0;
3469 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3470 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3471 pSMB->DataCount = 0;
3472 pSMB->DataOffset = 0;
3473 pSMB->SetupCount = 1;
3474 pSMB->Reserved3 = 0;
3475 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3476 byte_count = params + 1 /* pad */ ;
3477 pSMB->TotalParameterCount = cpu_to_le16(params);
3478 pSMB->ParameterCount = pSMB->TotalParameterCount;
3479 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3480 pSMB->Reserved4 = 0;
3481 pSMB->hdr.smb_buf_length += byte_count;
3482 pSMB->ByteCount = cpu_to_le16(byte_count);
3483
3484 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3485 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3486 if (rc) {
3487 cFYI(1, ("error %d in QueryInternalInfo", rc));
3488 } else {
3489 /* decode response */
3490 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3491 if (rc || (pSMBr->ByteCount < 2))
3492 /* BB also check enough total bytes returned */
3493 /* If rc should we check for EOPNOSUPP and
3494 disable the srvino flag? or in caller? */
3495 rc = -EIO; /* bad smb */
3496 else {
3497 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3498 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3499 struct file_internal_info * pfinfo;
3500 /* BB Do we need a cast or hash here ? */
3501 if(count < 8) {
3502 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3503 rc = -EIO;
3504 goto GetInodeNumOut;
3505 }
3506 pfinfo = (struct file_internal_info *)
3507 (data_offset + (char *) &pSMBr->hdr.Protocol);
3508 *inode_number = pfinfo->UniqueId;
3509 }
3510 }
3511GetInodeNumOut:
3512 cifs_buf_release(pSMB);
3513 if (rc == -EAGAIN)
3514 goto GetInodeNumberRetry;
3515 return rc;
3516}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
3518int
3519CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3520 const unsigned char *searchName,
3521 unsigned char **targetUNCs,
3522 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003523 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524{
3525/* TRANS2_GET_DFS_REFERRAL */
3526 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3527 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3528 struct dfs_referral_level_3 * referrals = NULL;
3529 int rc = 0;
3530 int bytes_returned;
3531 int name_len;
3532 unsigned int i;
3533 char * temp;
3534 __u16 params, byte_count;
3535 *number_of_UNC_in_array = 0;
3536 *targetUNCs = NULL;
3537
3538 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3539 if (ses == NULL)
3540 return -ENODEV;
3541getDFSRetry:
3542 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3543 (void **) &pSMBr);
3544 if (rc)
3545 return rc;
Steve French1982c342005-08-17 12:38:22 -07003546
3547 /* server pointer checked in called function,
3548 but should never be null here anyway */
3549 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 pSMB->hdr.Tid = ses->ipc_tid;
3551 pSMB->hdr.Uid = ses->Suid;
3552 if (ses->capabilities & CAP_STATUS32) {
3553 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3554 }
3555 if (ses->capabilities & CAP_DFS) {
3556 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3557 }
3558
3559 if (ses->capabilities & CAP_UNICODE) {
3560 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3561 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003562 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003563 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 name_len++; /* trailing null */
3565 name_len *= 2;
3566 } else { /* BB improve the check for buffer overruns BB */
3567 name_len = strnlen(searchName, PATH_MAX);
3568 name_len++; /* trailing null */
3569 strncpy(pSMB->RequestFileName, searchName, name_len);
3570 }
3571
3572 params = 2 /* level */ + name_len /*includes null */ ;
3573 pSMB->TotalDataCount = 0;
3574 pSMB->DataCount = 0;
3575 pSMB->DataOffset = 0;
3576 pSMB->MaxParameterCount = 0;
3577 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3578 pSMB->MaxSetupCount = 0;
3579 pSMB->Reserved = 0;
3580 pSMB->Flags = 0;
3581 pSMB->Timeout = 0;
3582 pSMB->Reserved2 = 0;
3583 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3584 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3585 pSMB->SetupCount = 1;
3586 pSMB->Reserved3 = 0;
3587 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3588 byte_count = params + 3 /* pad */ ;
3589 pSMB->ParameterCount = cpu_to_le16(params);
3590 pSMB->TotalParameterCount = pSMB->ParameterCount;
3591 pSMB->MaxReferralLevel = cpu_to_le16(3);
3592 pSMB->hdr.smb_buf_length += byte_count;
3593 pSMB->ByteCount = cpu_to_le16(byte_count);
3594
3595 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3597 if (rc) {
3598 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3599 } else { /* decode response */
3600/* BB Add logic to parse referrals here */
3601 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3602
3603 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3604 rc = -EIO; /* bad smb */
3605 else {
3606 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3607 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3608
3609 cFYI(1,
3610 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3611 pSMBr->ByteCount, data_offset));
3612 referrals =
3613 (struct dfs_referral_level_3 *)
3614 (8 /* sizeof start of data block */ +
3615 data_offset +
3616 (char *) &pSMBr->hdr.Protocol);
3617 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",
3618 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)));
3619 /* BB This field is actually two bytes in from start of
3620 data block so we could do safety check that DataBlock
3621 begins at address of pSMBr->NumberOfReferrals */
3622 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3623
3624 /* BB Fix below so can return more than one referral */
3625 if(*number_of_UNC_in_array > 1)
3626 *number_of_UNC_in_array = 1;
3627
3628 /* get the length of the strings describing refs */
3629 name_len = 0;
3630 for(i=0;i<*number_of_UNC_in_array;i++) {
3631 /* make sure that DfsPathOffset not past end */
3632 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3633 if (offset > data_count) {
3634 /* if invalid referral, stop here and do
3635 not try to copy any more */
3636 *number_of_UNC_in_array = i;
3637 break;
3638 }
3639 temp = ((char *)referrals) + offset;
3640
3641 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3642 name_len += UniStrnlen((wchar_t *)temp,data_count);
3643 } else {
3644 name_len += strnlen(temp,data_count);
3645 }
3646 referrals++;
3647 /* BB add check that referral pointer does not fall off end PDU */
3648
3649 }
3650 /* BB add check for name_len bigger than bcc */
3651 *targetUNCs =
3652 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3653 if(*targetUNCs == NULL) {
3654 rc = -ENOMEM;
3655 goto GetDFSRefExit;
3656 }
3657 /* copy the ref strings */
3658 referrals =
3659 (struct dfs_referral_level_3 *)
3660 (8 /* sizeof data hdr */ +
3661 data_offset +
3662 (char *) &pSMBr->hdr.Protocol);
3663
3664 for(i=0;i<*number_of_UNC_in_array;i++) {
3665 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3666 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3667 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003668 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 } else {
3670 strncpy(*targetUNCs,temp,name_len);
3671 }
3672 /* BB update target_uncs pointers */
3673 referrals++;
3674 }
3675 temp = *targetUNCs;
3676 temp[name_len] = 0;
3677 }
3678
3679 }
3680GetDFSRefExit:
3681 if (pSMB)
3682 cifs_buf_release(pSMB);
3683
3684 if (rc == -EAGAIN)
3685 goto getDFSRetry;
3686
3687 return rc;
3688}
3689
Steve French20962432005-09-21 22:05:57 -07003690/* Query File System Info such as free space to old servers such as Win 9x */
3691int
3692SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3693{
3694/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3695 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3696 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3697 FILE_SYSTEM_ALLOC_INFO *response_data;
3698 int rc = 0;
3699 int bytes_returned = 0;
3700 __u16 params, byte_count;
3701
3702 cFYI(1, ("OldQFSInfo"));
3703oldQFSInfoRetry:
3704 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3705 (void **) &pSMBr);
3706 if (rc)
3707 return rc;
3708 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3709 (void **) &pSMBr);
3710 if (rc)
3711 return rc;
3712
3713 params = 2; /* level */
3714 pSMB->TotalDataCount = 0;
3715 pSMB->MaxParameterCount = cpu_to_le16(2);
3716 pSMB->MaxDataCount = cpu_to_le16(1000);
3717 pSMB->MaxSetupCount = 0;
3718 pSMB->Reserved = 0;
3719 pSMB->Flags = 0;
3720 pSMB->Timeout = 0;
3721 pSMB->Reserved2 = 0;
3722 byte_count = params + 1 /* pad */ ;
3723 pSMB->TotalParameterCount = cpu_to_le16(params);
3724 pSMB->ParameterCount = pSMB->TotalParameterCount;
3725 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3726 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3727 pSMB->DataCount = 0;
3728 pSMB->DataOffset = 0;
3729 pSMB->SetupCount = 1;
3730 pSMB->Reserved3 = 0;
3731 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3732 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3733 pSMB->hdr.smb_buf_length += byte_count;
3734 pSMB->ByteCount = cpu_to_le16(byte_count);
3735
3736 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3737 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3738 if (rc) {
3739 cFYI(1, ("Send error in QFSInfo = %d", rc));
3740 } else { /* decode response */
3741 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3742
3743 if (rc || (pSMBr->ByteCount < 18))
3744 rc = -EIO; /* bad smb */
3745 else {
3746 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3747 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3748 pSMBr->ByteCount, data_offset));
3749
3750 response_data =
3751 (FILE_SYSTEM_ALLOC_INFO *)
3752 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3753 FSData->f_bsize =
3754 le16_to_cpu(response_data->BytesPerSector) *
3755 le32_to_cpu(response_data->
3756 SectorsPerAllocationUnit);
3757 FSData->f_blocks =
3758 le32_to_cpu(response_data->TotalAllocationUnits);
3759 FSData->f_bfree = FSData->f_bavail =
3760 le32_to_cpu(response_data->FreeAllocationUnits);
3761 cFYI(1,
3762 ("Blocks: %lld Free: %lld Block size %ld",
3763 (unsigned long long)FSData->f_blocks,
3764 (unsigned long long)FSData->f_bfree,
3765 FSData->f_bsize));
3766 }
3767 }
3768 cifs_buf_release(pSMB);
3769
3770 if (rc == -EAGAIN)
3771 goto oldQFSInfoRetry;
3772
3773 return rc;
3774}
3775
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776int
Steve French737b7582005-04-28 22:41:06 -07003777CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778{
3779/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3780 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3781 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3782 FILE_SYSTEM_INFO *response_data;
3783 int rc = 0;
3784 int bytes_returned = 0;
3785 __u16 params, byte_count;
3786
3787 cFYI(1, ("In QFSInfo"));
3788QFSInfoRetry:
3789 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3790 (void **) &pSMBr);
3791 if (rc)
3792 return rc;
3793
3794 params = 2; /* level */
3795 pSMB->TotalDataCount = 0;
3796 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003797 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 pSMB->MaxSetupCount = 0;
3799 pSMB->Reserved = 0;
3800 pSMB->Flags = 0;
3801 pSMB->Timeout = 0;
3802 pSMB->Reserved2 = 0;
3803 byte_count = params + 1 /* pad */ ;
3804 pSMB->TotalParameterCount = cpu_to_le16(params);
3805 pSMB->ParameterCount = pSMB->TotalParameterCount;
3806 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3807 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3808 pSMB->DataCount = 0;
3809 pSMB->DataOffset = 0;
3810 pSMB->SetupCount = 1;
3811 pSMB->Reserved3 = 0;
3812 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3813 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3814 pSMB->hdr.smb_buf_length += byte_count;
3815 pSMB->ByteCount = cpu_to_le16(byte_count);
3816
3817 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3818 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3819 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003820 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 } else { /* decode response */
3822 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3823
Steve French20962432005-09-21 22:05:57 -07003824 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 rc = -EIO; /* bad smb */
3826 else {
3827 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
3829 response_data =
3830 (FILE_SYSTEM_INFO
3831 *) (((char *) &pSMBr->hdr.Protocol) +
3832 data_offset);
3833 FSData->f_bsize =
3834 le32_to_cpu(response_data->BytesPerSector) *
3835 le32_to_cpu(response_data->
3836 SectorsPerAllocationUnit);
3837 FSData->f_blocks =
3838 le64_to_cpu(response_data->TotalAllocationUnits);
3839 FSData->f_bfree = FSData->f_bavail =
3840 le64_to_cpu(response_data->FreeAllocationUnits);
3841 cFYI(1,
3842 ("Blocks: %lld Free: %lld Block size %ld",
3843 (unsigned long long)FSData->f_blocks,
3844 (unsigned long long)FSData->f_bfree,
3845 FSData->f_bsize));
3846 }
3847 }
3848 cifs_buf_release(pSMB);
3849
3850 if (rc == -EAGAIN)
3851 goto QFSInfoRetry;
3852
3853 return rc;
3854}
3855
3856int
Steve French737b7582005-04-28 22:41:06 -07003857CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858{
3859/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3860 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3861 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3862 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3863 int rc = 0;
3864 int bytes_returned = 0;
3865 __u16 params, byte_count;
3866
3867 cFYI(1, ("In QFSAttributeInfo"));
3868QFSAttributeRetry:
3869 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3870 (void **) &pSMBr);
3871 if (rc)
3872 return rc;
3873
3874 params = 2; /* level */
3875 pSMB->TotalDataCount = 0;
3876 pSMB->MaxParameterCount = cpu_to_le16(2);
3877 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3878 pSMB->MaxSetupCount = 0;
3879 pSMB->Reserved = 0;
3880 pSMB->Flags = 0;
3881 pSMB->Timeout = 0;
3882 pSMB->Reserved2 = 0;
3883 byte_count = params + 1 /* pad */ ;
3884 pSMB->TotalParameterCount = cpu_to_le16(params);
3885 pSMB->ParameterCount = pSMB->TotalParameterCount;
3886 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3887 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3888 pSMB->DataCount = 0;
3889 pSMB->DataOffset = 0;
3890 pSMB->SetupCount = 1;
3891 pSMB->Reserved3 = 0;
3892 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3893 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3894 pSMB->hdr.smb_buf_length += byte_count;
3895 pSMB->ByteCount = cpu_to_le16(byte_count);
3896
3897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3899 if (rc) {
3900 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3901 } else { /* decode response */
3902 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3903
3904 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3905 rc = -EIO; /* bad smb */
3906 } else {
3907 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3908 response_data =
3909 (FILE_SYSTEM_ATTRIBUTE_INFO
3910 *) (((char *) &pSMBr->hdr.Protocol) +
3911 data_offset);
3912 memcpy(&tcon->fsAttrInfo, response_data,
3913 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3914 }
3915 }
3916 cifs_buf_release(pSMB);
3917
3918 if (rc == -EAGAIN)
3919 goto QFSAttributeRetry;
3920
3921 return rc;
3922}
3923
3924int
Steve French737b7582005-04-28 22:41:06 -07003925CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926{
3927/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3928 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3929 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3930 FILE_SYSTEM_DEVICE_INFO *response_data;
3931 int rc = 0;
3932 int bytes_returned = 0;
3933 __u16 params, byte_count;
3934
3935 cFYI(1, ("In QFSDeviceInfo"));
3936QFSDeviceRetry:
3937 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3938 (void **) &pSMBr);
3939 if (rc)
3940 return rc;
3941
3942 params = 2; /* level */
3943 pSMB->TotalDataCount = 0;
3944 pSMB->MaxParameterCount = cpu_to_le16(2);
3945 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3946 pSMB->MaxSetupCount = 0;
3947 pSMB->Reserved = 0;
3948 pSMB->Flags = 0;
3949 pSMB->Timeout = 0;
3950 pSMB->Reserved2 = 0;
3951 byte_count = params + 1 /* pad */ ;
3952 pSMB->TotalParameterCount = cpu_to_le16(params);
3953 pSMB->ParameterCount = pSMB->TotalParameterCount;
3954 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3955 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3956
3957 pSMB->DataCount = 0;
3958 pSMB->DataOffset = 0;
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_FS_DEVICE_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 QFSDeviceInfo = %d", rc));
3970 } else { /* decode response */
3971 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3972
3973 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3974 rc = -EIO; /* bad smb */
3975 else {
3976 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3977 response_data =
Steve French737b7582005-04-28 22:41:06 -07003978 (FILE_SYSTEM_DEVICE_INFO *)
3979 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 data_offset);
3981 memcpy(&tcon->fsDevInfo, response_data,
3982 sizeof (FILE_SYSTEM_DEVICE_INFO));
3983 }
3984 }
3985 cifs_buf_release(pSMB);
3986
3987 if (rc == -EAGAIN)
3988 goto QFSDeviceRetry;
3989
3990 return rc;
3991}
3992
3993int
Steve French737b7582005-04-28 22:41:06 -07003994CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995{
3996/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3997 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3998 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3999 FILE_SYSTEM_UNIX_INFO *response_data;
4000 int rc = 0;
4001 int bytes_returned = 0;
4002 __u16 params, byte_count;
4003
4004 cFYI(1, ("In QFSUnixInfo"));
4005QFSUnixRetry:
4006 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4007 (void **) &pSMBr);
4008 if (rc)
4009 return rc;
4010
4011 params = 2; /* level */
4012 pSMB->TotalDataCount = 0;
4013 pSMB->DataCount = 0;
4014 pSMB->DataOffset = 0;
4015 pSMB->MaxParameterCount = cpu_to_le16(2);
4016 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4017 pSMB->MaxSetupCount = 0;
4018 pSMB->Reserved = 0;
4019 pSMB->Flags = 0;
4020 pSMB->Timeout = 0;
4021 pSMB->Reserved2 = 0;
4022 byte_count = params + 1 /* pad */ ;
4023 pSMB->ParameterCount = cpu_to_le16(params);
4024 pSMB->TotalParameterCount = pSMB->ParameterCount;
4025 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4026 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4027 pSMB->SetupCount = 1;
4028 pSMB->Reserved3 = 0;
4029 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4030 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4031 pSMB->hdr.smb_buf_length += byte_count;
4032 pSMB->ByteCount = cpu_to_le16(byte_count);
4033
4034 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4035 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4036 if (rc) {
4037 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4038 } else { /* decode response */
4039 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4040
4041 if (rc || (pSMBr->ByteCount < 13)) {
4042 rc = -EIO; /* bad smb */
4043 } else {
4044 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4045 response_data =
4046 (FILE_SYSTEM_UNIX_INFO
4047 *) (((char *) &pSMBr->hdr.Protocol) +
4048 data_offset);
4049 memcpy(&tcon->fsUnixInfo, response_data,
4050 sizeof (FILE_SYSTEM_UNIX_INFO));
4051 }
4052 }
4053 cifs_buf_release(pSMB);
4054
4055 if (rc == -EAGAIN)
4056 goto QFSUnixRetry;
4057
4058
4059 return rc;
4060}
4061
Jeremy Allisonac670552005-06-22 17:26:35 -07004062int
Steve French45abc6e2005-06-23 13:42:03 -05004063CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004064{
4065/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4066 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4067 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4068 int rc = 0;
4069 int bytes_returned = 0;
4070 __u16 params, param_offset, offset, byte_count;
4071
4072 cFYI(1, ("In SETFSUnixInfo"));
4073SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004074 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004075 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4076 (void **) &pSMBr);
4077 if (rc)
4078 return rc;
4079
4080 params = 4; /* 2 bytes zero followed by info level. */
4081 pSMB->MaxSetupCount = 0;
4082 pSMB->Reserved = 0;
4083 pSMB->Flags = 0;
4084 pSMB->Timeout = 0;
4085 pSMB->Reserved2 = 0;
4086 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4087 offset = param_offset + params;
4088
4089 pSMB->MaxParameterCount = cpu_to_le16(4);
4090 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4091 pSMB->SetupCount = 1;
4092 pSMB->Reserved3 = 0;
4093 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4094 byte_count = 1 /* pad */ + params + 12;
4095
4096 pSMB->DataCount = cpu_to_le16(12);
4097 pSMB->ParameterCount = cpu_to_le16(params);
4098 pSMB->TotalDataCount = pSMB->DataCount;
4099 pSMB->TotalParameterCount = pSMB->ParameterCount;
4100 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4101 pSMB->DataOffset = cpu_to_le16(offset);
4102
4103 /* Params. */
4104 pSMB->FileNum = 0;
4105 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4106
4107 /* Data. */
4108 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4109 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4110 pSMB->ClientUnixCap = cpu_to_le64(cap);
4111
4112 pSMB->hdr.smb_buf_length += byte_count;
4113 pSMB->ByteCount = cpu_to_le16(byte_count);
4114
4115 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4116 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4117 if (rc) {
4118 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4119 } else { /* decode response */
4120 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4121 if (rc) {
4122 rc = -EIO; /* bad smb */
4123 }
4124 }
4125 cifs_buf_release(pSMB);
4126
4127 if (rc == -EAGAIN)
4128 goto SETFSUnixRetry;
4129
4130 return rc;
4131}
4132
4133
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134
4135int
4136CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004137 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138{
4139/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4140 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4141 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4142 FILE_SYSTEM_POSIX_INFO *response_data;
4143 int rc = 0;
4144 int bytes_returned = 0;
4145 __u16 params, byte_count;
4146
4147 cFYI(1, ("In QFSPosixInfo"));
4148QFSPosixRetry:
4149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150 (void **) &pSMBr);
4151 if (rc)
4152 return rc;
4153
4154 params = 2; /* level */
4155 pSMB->TotalDataCount = 0;
4156 pSMB->DataCount = 0;
4157 pSMB->DataOffset = 0;
4158 pSMB->MaxParameterCount = cpu_to_le16(2);
4159 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4160 pSMB->MaxSetupCount = 0;
4161 pSMB->Reserved = 0;
4162 pSMB->Flags = 0;
4163 pSMB->Timeout = 0;
4164 pSMB->Reserved2 = 0;
4165 byte_count = params + 1 /* pad */ ;
4166 pSMB->ParameterCount = cpu_to_le16(params);
4167 pSMB->TotalParameterCount = pSMB->ParameterCount;
4168 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4169 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4170 pSMB->SetupCount = 1;
4171 pSMB->Reserved3 = 0;
4172 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4173 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4174 pSMB->hdr.smb_buf_length += byte_count;
4175 pSMB->ByteCount = cpu_to_le16(byte_count);
4176
4177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4179 if (rc) {
4180 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4181 } else { /* decode response */
4182 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4183
4184 if (rc || (pSMBr->ByteCount < 13)) {
4185 rc = -EIO; /* bad smb */
4186 } else {
4187 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4188 response_data =
4189 (FILE_SYSTEM_POSIX_INFO
4190 *) (((char *) &pSMBr->hdr.Protocol) +
4191 data_offset);
4192 FSData->f_bsize =
4193 le32_to_cpu(response_data->BlockSize);
4194 FSData->f_blocks =
4195 le64_to_cpu(response_data->TotalBlocks);
4196 FSData->f_bfree =
4197 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004198 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 FSData->f_bavail = FSData->f_bfree;
4200 } else {
4201 FSData->f_bavail =
4202 le64_to_cpu(response_data->UserBlocksAvail);
4203 }
Steve French70ca7342005-09-22 16:32:06 -07004204 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 FSData->f_files =
4206 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004207 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 FSData->f_ffree =
4209 le64_to_cpu(response_data->FreeFileNodes);
4210 }
4211 }
4212 cifs_buf_release(pSMB);
4213
4214 if (rc == -EAGAIN)
4215 goto QFSPosixRetry;
4216
4217 return rc;
4218}
4219
4220
4221/* We can not use write of zero bytes trick to
4222 set file size due to need for large file support. Also note that
4223 this SetPathInfo is preferred to SetFileInfo based method in next
4224 routine which is only needed to work around a sharing violation bug
4225 in Samba which this routine can run into */
4226
4227int
4228CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004229 __u64 size, int SetAllocation,
4230 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231{
4232 struct smb_com_transaction2_spi_req *pSMB = NULL;
4233 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4234 struct file_end_of_file_info *parm_data;
4235 int name_len;
4236 int rc = 0;
4237 int bytes_returned = 0;
4238 __u16 params, byte_count, data_count, param_offset, offset;
4239
4240 cFYI(1, ("In SetEOF"));
4241SetEOFRetry:
4242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4243 (void **) &pSMBr);
4244 if (rc)
4245 return rc;
4246
4247 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4248 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004249 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004250 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 name_len++; /* trailing null */
4252 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004253 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 name_len = strnlen(fileName, PATH_MAX);
4255 name_len++; /* trailing null */
4256 strncpy(pSMB->FileName, fileName, name_len);
4257 }
4258 params = 6 + name_len;
4259 data_count = sizeof (struct file_end_of_file_info);
4260 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004261 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 pSMB->MaxSetupCount = 0;
4263 pSMB->Reserved = 0;
4264 pSMB->Flags = 0;
4265 pSMB->Timeout = 0;
4266 pSMB->Reserved2 = 0;
4267 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4268 InformationLevel) - 4;
4269 offset = param_offset + params;
4270 if(SetAllocation) {
4271 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4272 pSMB->InformationLevel =
4273 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4274 else
4275 pSMB->InformationLevel =
4276 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4277 } else /* Set File Size */ {
4278 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4279 pSMB->InformationLevel =
4280 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4281 else
4282 pSMB->InformationLevel =
4283 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4284 }
4285
4286 parm_data =
4287 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4288 offset);
4289 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4290 pSMB->DataOffset = cpu_to_le16(offset);
4291 pSMB->SetupCount = 1;
4292 pSMB->Reserved3 = 0;
4293 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4294 byte_count = 3 /* pad */ + params + data_count;
4295 pSMB->DataCount = cpu_to_le16(data_count);
4296 pSMB->TotalDataCount = pSMB->DataCount;
4297 pSMB->ParameterCount = cpu_to_le16(params);
4298 pSMB->TotalParameterCount = pSMB->ParameterCount;
4299 pSMB->Reserved4 = 0;
4300 pSMB->hdr.smb_buf_length += byte_count;
4301 parm_data->FileSize = cpu_to_le64(size);
4302 pSMB->ByteCount = cpu_to_le16(byte_count);
4303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4305 if (rc) {
4306 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4307 }
4308
4309 cifs_buf_release(pSMB);
4310
4311 if (rc == -EAGAIN)
4312 goto SetEOFRetry;
4313
4314 return rc;
4315}
4316
4317int
4318CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4319 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4320{
4321 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4322 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4323 char *data_offset;
4324 struct file_end_of_file_info *parm_data;
4325 int rc = 0;
4326 int bytes_returned = 0;
4327 __u16 params, param_offset, offset, byte_count, count;
4328
4329 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4330 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004331 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4332
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 if (rc)
4334 return rc;
4335
Steve Frenchcd634992005-04-28 22:41:10 -07004336 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4337
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4339 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4340
4341 params = 6;
4342 pSMB->MaxSetupCount = 0;
4343 pSMB->Reserved = 0;
4344 pSMB->Flags = 0;
4345 pSMB->Timeout = 0;
4346 pSMB->Reserved2 = 0;
4347 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4348 offset = param_offset + params;
4349
4350 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4351
4352 count = sizeof(struct file_end_of_file_info);
4353 pSMB->MaxParameterCount = cpu_to_le16(2);
4354 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4355 pSMB->SetupCount = 1;
4356 pSMB->Reserved3 = 0;
4357 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4358 byte_count = 3 /* pad */ + params + count;
4359 pSMB->DataCount = cpu_to_le16(count);
4360 pSMB->ParameterCount = cpu_to_le16(params);
4361 pSMB->TotalDataCount = pSMB->DataCount;
4362 pSMB->TotalParameterCount = pSMB->ParameterCount;
4363 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4364 parm_data =
4365 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4366 offset);
4367 pSMB->DataOffset = cpu_to_le16(offset);
4368 parm_data->FileSize = cpu_to_le64(size);
4369 pSMB->Fid = fid;
4370 if(SetAllocation) {
4371 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4372 pSMB->InformationLevel =
4373 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4374 else
4375 pSMB->InformationLevel =
4376 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4377 } else /* Set File Size */ {
4378 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4379 pSMB->InformationLevel =
4380 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4381 else
4382 pSMB->InformationLevel =
4383 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4384 }
4385 pSMB->Reserved4 = 0;
4386 pSMB->hdr.smb_buf_length += byte_count;
4387 pSMB->ByteCount = cpu_to_le16(byte_count);
4388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4389 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4390 if (rc) {
4391 cFYI(1,
4392 ("Send error in SetFileInfo (SetFileSize) = %d",
4393 rc));
4394 }
4395
4396 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004397 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398
4399 /* Note: On -EAGAIN error only caller can retry on handle based calls
4400 since file handle passed in no longer valid */
4401
4402 return rc;
4403}
4404
4405/* Some legacy servers such as NT4 require that the file times be set on
4406 an open handle, rather than by pathname - this is awkward due to
4407 potential access conflicts on the open, but it is unavoidable for these
4408 old servers since the only other choice is to go from 100 nanosecond DCE
4409 time and resort to the original setpathinfo level which takes the ancient
4410 DOS time format with 2 second granularity */
4411int
4412CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4413 __u16 fid)
4414{
4415 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4416 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4417 char *data_offset;
4418 int rc = 0;
4419 int bytes_returned = 0;
4420 __u16 params, param_offset, offset, byte_count, count;
4421
4422 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004423 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4424
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 if (rc)
4426 return rc;
4427
Steve Frenchcd634992005-04-28 22:41:10 -07004428 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4429
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 /* At this point there is no need to override the current pid
4431 with the pid of the opener, but that could change if we someday
4432 use an existing handle (rather than opening one on the fly) */
4433 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4434 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4435
4436 params = 6;
4437 pSMB->MaxSetupCount = 0;
4438 pSMB->Reserved = 0;
4439 pSMB->Flags = 0;
4440 pSMB->Timeout = 0;
4441 pSMB->Reserved2 = 0;
4442 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4443 offset = param_offset + params;
4444
4445 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4446
4447 count = sizeof (FILE_BASIC_INFO);
4448 pSMB->MaxParameterCount = cpu_to_le16(2);
4449 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4450 pSMB->SetupCount = 1;
4451 pSMB->Reserved3 = 0;
4452 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4453 byte_count = 3 /* pad */ + params + count;
4454 pSMB->DataCount = cpu_to_le16(count);
4455 pSMB->ParameterCount = cpu_to_le16(params);
4456 pSMB->TotalDataCount = pSMB->DataCount;
4457 pSMB->TotalParameterCount = pSMB->ParameterCount;
4458 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4459 pSMB->DataOffset = cpu_to_le16(offset);
4460 pSMB->Fid = fid;
4461 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4462 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4463 else
4464 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4465 pSMB->Reserved4 = 0;
4466 pSMB->hdr.smb_buf_length += byte_count;
4467 pSMB->ByteCount = cpu_to_le16(byte_count);
4468 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4469 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4470 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4471 if (rc) {
4472 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4473 }
4474
Steve Frenchcd634992005-04-28 22:41:10 -07004475 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476
4477 /* Note: On -EAGAIN error only caller can retry on handle based calls
4478 since file handle passed in no longer valid */
4479
4480 return rc;
4481}
4482
4483
4484int
4485CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4486 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004487 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488{
4489 TRANSACTION2_SPI_REQ *pSMB = NULL;
4490 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4491 int name_len;
4492 int rc = 0;
4493 int bytes_returned = 0;
4494 char *data_offset;
4495 __u16 params, param_offset, offset, byte_count, count;
4496
4497 cFYI(1, ("In SetTimes"));
4498
4499SetTimesRetry:
4500 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4501 (void **) &pSMBr);
4502 if (rc)
4503 return rc;
4504
4505 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4506 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004507 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004508 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 name_len++; /* trailing null */
4510 name_len *= 2;
4511 } else { /* BB improve the check for buffer overruns BB */
4512 name_len = strnlen(fileName, PATH_MAX);
4513 name_len++; /* trailing null */
4514 strncpy(pSMB->FileName, fileName, name_len);
4515 }
4516
4517 params = 6 + name_len;
4518 count = sizeof (FILE_BASIC_INFO);
4519 pSMB->MaxParameterCount = cpu_to_le16(2);
4520 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4521 pSMB->MaxSetupCount = 0;
4522 pSMB->Reserved = 0;
4523 pSMB->Flags = 0;
4524 pSMB->Timeout = 0;
4525 pSMB->Reserved2 = 0;
4526 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4527 InformationLevel) - 4;
4528 offset = param_offset + params;
4529 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4530 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4531 pSMB->DataOffset = cpu_to_le16(offset);
4532 pSMB->SetupCount = 1;
4533 pSMB->Reserved3 = 0;
4534 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4535 byte_count = 3 /* pad */ + params + count;
4536
4537 pSMB->DataCount = cpu_to_le16(count);
4538 pSMB->ParameterCount = cpu_to_le16(params);
4539 pSMB->TotalDataCount = pSMB->DataCount;
4540 pSMB->TotalParameterCount = pSMB->ParameterCount;
4541 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4542 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4543 else
4544 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4545 pSMB->Reserved4 = 0;
4546 pSMB->hdr.smb_buf_length += byte_count;
4547 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4548 pSMB->ByteCount = cpu_to_le16(byte_count);
4549 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4550 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4551 if (rc) {
4552 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4553 }
4554
4555 cifs_buf_release(pSMB);
4556
4557 if (rc == -EAGAIN)
4558 goto SetTimesRetry;
4559
4560 return rc;
4561}
4562
4563/* Can not be used to set time stamps yet (due to old DOS time format) */
4564/* Can be used to set attributes */
4565#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4566 handling it anyway and NT4 was what we thought it would be needed for
4567 Do not delete it until we prove whether needed for Win9x though */
4568int
4569CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4570 __u16 dos_attrs, const struct nls_table *nls_codepage)
4571{
4572 SETATTR_REQ *pSMB = NULL;
4573 SETATTR_RSP *pSMBr = NULL;
4574 int rc = 0;
4575 int bytes_returned;
4576 int name_len;
4577
4578 cFYI(1, ("In SetAttrLegacy"));
4579
4580SetAttrLgcyRetry:
4581 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4582 (void **) &pSMBr);
4583 if (rc)
4584 return rc;
4585
4586 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4587 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004588 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 PATH_MAX, nls_codepage);
4590 name_len++; /* trailing null */
4591 name_len *= 2;
4592 } else { /* BB improve the check for buffer overruns BB */
4593 name_len = strnlen(fileName, PATH_MAX);
4594 name_len++; /* trailing null */
4595 strncpy(pSMB->fileName, fileName, name_len);
4596 }
4597 pSMB->attr = cpu_to_le16(dos_attrs);
4598 pSMB->BufferFormat = 0x04;
4599 pSMB->hdr.smb_buf_length += name_len + 1;
4600 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4601 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4602 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4603 if (rc) {
4604 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4605 }
4606
4607 cifs_buf_release(pSMB);
4608
4609 if (rc == -EAGAIN)
4610 goto SetAttrLgcyRetry;
4611
4612 return rc;
4613}
4614#endif /* temporarily unneeded SetAttr legacy function */
4615
4616int
4617CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004618 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4619 dev_t device, const struct nls_table *nls_codepage,
4620 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621{
4622 TRANSACTION2_SPI_REQ *pSMB = NULL;
4623 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4624 int name_len;
4625 int rc = 0;
4626 int bytes_returned = 0;
4627 FILE_UNIX_BASIC_INFO *data_offset;
4628 __u16 params, param_offset, offset, count, byte_count;
4629
4630 cFYI(1, ("In SetUID/GID/Mode"));
4631setPermsRetry:
4632 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4633 (void **) &pSMBr);
4634 if (rc)
4635 return rc;
4636
4637 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4638 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004639 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004640 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 name_len++; /* trailing null */
4642 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004643 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 name_len = strnlen(fileName, PATH_MAX);
4645 name_len++; /* trailing null */
4646 strncpy(pSMB->FileName, fileName, name_len);
4647 }
4648
4649 params = 6 + name_len;
4650 count = sizeof (FILE_UNIX_BASIC_INFO);
4651 pSMB->MaxParameterCount = cpu_to_le16(2);
4652 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4653 pSMB->MaxSetupCount = 0;
4654 pSMB->Reserved = 0;
4655 pSMB->Flags = 0;
4656 pSMB->Timeout = 0;
4657 pSMB->Reserved2 = 0;
4658 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4659 InformationLevel) - 4;
4660 offset = param_offset + params;
4661 data_offset =
4662 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4663 offset);
4664 memset(data_offset, 0, count);
4665 pSMB->DataOffset = cpu_to_le16(offset);
4666 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4667 pSMB->SetupCount = 1;
4668 pSMB->Reserved3 = 0;
4669 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4670 byte_count = 3 /* pad */ + params + count;
4671 pSMB->ParameterCount = cpu_to_le16(params);
4672 pSMB->DataCount = cpu_to_le16(count);
4673 pSMB->TotalParameterCount = pSMB->ParameterCount;
4674 pSMB->TotalDataCount = pSMB->DataCount;
4675 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4676 pSMB->Reserved4 = 0;
4677 pSMB->hdr.smb_buf_length += byte_count;
4678 data_offset->Uid = cpu_to_le64(uid);
4679 data_offset->Gid = cpu_to_le64(gid);
4680 /* better to leave device as zero when it is */
4681 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4682 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4683 data_offset->Permissions = cpu_to_le64(mode);
4684
4685 if(S_ISREG(mode))
4686 data_offset->Type = cpu_to_le32(UNIX_FILE);
4687 else if(S_ISDIR(mode))
4688 data_offset->Type = cpu_to_le32(UNIX_DIR);
4689 else if(S_ISLNK(mode))
4690 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4691 else if(S_ISCHR(mode))
4692 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4693 else if(S_ISBLK(mode))
4694 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4695 else if(S_ISFIFO(mode))
4696 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4697 else if(S_ISSOCK(mode))
4698 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4699
4700
4701 pSMB->ByteCount = cpu_to_le16(byte_count);
4702 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4703 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4704 if (rc) {
4705 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4706 }
4707
4708 if (pSMB)
4709 cifs_buf_release(pSMB);
4710 if (rc == -EAGAIN)
4711 goto setPermsRetry;
4712 return rc;
4713}
4714
4715int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004716 const int notify_subdirs, const __u16 netfid,
4717 __u32 filter, struct file * pfile, int multishot,
4718 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719{
4720 int rc = 0;
4721 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004722 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004723 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 int bytes_returned;
4725
4726 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4727 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4728 (void **) &pSMBr);
4729 if (rc)
4730 return rc;
4731
4732 pSMB->TotalParameterCount = 0 ;
4733 pSMB->TotalDataCount = 0;
4734 pSMB->MaxParameterCount = cpu_to_le32(2);
4735 /* BB find exact data count max from sess structure BB */
4736 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004737/* BB VERIFY verify which is correct for above BB */
4738 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4739 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4740
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 pSMB->MaxSetupCount = 4;
4742 pSMB->Reserved = 0;
4743 pSMB->ParameterOffset = 0;
4744 pSMB->DataCount = 0;
4745 pSMB->DataOffset = 0;
4746 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4747 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4748 pSMB->ParameterCount = pSMB->TotalParameterCount;
4749 if(notify_subdirs)
4750 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4751 pSMB->Reserved2 = 0;
4752 pSMB->CompletionFilter = cpu_to_le32(filter);
4753 pSMB->Fid = netfid; /* file handle always le */
4754 pSMB->ByteCount = 0;
4755
4756 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4757 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4758 if (rc) {
4759 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004760 } else {
4761 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004762 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004763 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004764 sizeof(struct dir_notify_req),
4765 GFP_KERNEL);
4766 if(dnotify_req) {
4767 dnotify_req->Pid = pSMB->hdr.Pid;
4768 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4769 dnotify_req->Mid = pSMB->hdr.Mid;
4770 dnotify_req->Tid = pSMB->hdr.Tid;
4771 dnotify_req->Uid = pSMB->hdr.Uid;
4772 dnotify_req->netfid = netfid;
4773 dnotify_req->pfile = pfile;
4774 dnotify_req->filter = filter;
4775 dnotify_req->multishot = multishot;
4776 spin_lock(&GlobalMid_Lock);
4777 list_add_tail(&dnotify_req->lhead,
4778 &GlobalDnotifyReqList);
4779 spin_unlock(&GlobalMid_Lock);
4780 } else
4781 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 }
4783 cifs_buf_release(pSMB);
4784 return rc;
4785}
4786#ifdef CONFIG_CIFS_XATTR
4787ssize_t
4788CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4789 const unsigned char *searchName,
4790 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004791 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792{
4793 /* BB assumes one setup word */
4794 TRANSACTION2_QPI_REQ *pSMB = NULL;
4795 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4796 int rc = 0;
4797 int bytes_returned;
4798 int name_len;
4799 struct fea * temp_fea;
4800 char * temp_ptr;
4801 __u16 params, byte_count;
4802
4803 cFYI(1, ("In Query All EAs path %s", searchName));
4804QAllEAsRetry:
4805 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4806 (void **) &pSMBr);
4807 if (rc)
4808 return rc;
4809
4810 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4811 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004812 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004813 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 name_len++; /* trailing null */
4815 name_len *= 2;
4816 } else { /* BB improve the check for buffer overruns BB */
4817 name_len = strnlen(searchName, PATH_MAX);
4818 name_len++; /* trailing null */
4819 strncpy(pSMB->FileName, searchName, name_len);
4820 }
4821
4822 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4823 pSMB->TotalDataCount = 0;
4824 pSMB->MaxParameterCount = cpu_to_le16(2);
4825 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4826 pSMB->MaxSetupCount = 0;
4827 pSMB->Reserved = 0;
4828 pSMB->Flags = 0;
4829 pSMB->Timeout = 0;
4830 pSMB->Reserved2 = 0;
4831 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4832 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4833 pSMB->DataCount = 0;
4834 pSMB->DataOffset = 0;
4835 pSMB->SetupCount = 1;
4836 pSMB->Reserved3 = 0;
4837 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4838 byte_count = params + 1 /* pad */ ;
4839 pSMB->TotalParameterCount = cpu_to_le16(params);
4840 pSMB->ParameterCount = pSMB->TotalParameterCount;
4841 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4842 pSMB->Reserved4 = 0;
4843 pSMB->hdr.smb_buf_length += byte_count;
4844 pSMB->ByteCount = cpu_to_le16(byte_count);
4845
4846 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4847 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4848 if (rc) {
4849 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4850 } else { /* decode response */
4851 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4852
4853 /* BB also check enough total bytes returned */
4854 /* BB we need to improve the validity checking
4855 of these trans2 responses */
4856 if (rc || (pSMBr->ByteCount < 4))
4857 rc = -EIO; /* bad smb */
4858 /* else if (pFindData){
4859 memcpy((char *) pFindData,
4860 (char *) &pSMBr->hdr.Protocol +
4861 data_offset, kl);
4862 }*/ else {
4863 /* check that length of list is not more than bcc */
4864 /* check that each entry does not go beyond length
4865 of list */
4866 /* check that each element of each entry does not
4867 go beyond end of list */
4868 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4869 struct fealist * ea_response_data;
4870 rc = 0;
4871 /* validate_trans2_offsets() */
4872 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4873 ea_response_data = (struct fealist *)
4874 (((char *) &pSMBr->hdr.Protocol) +
4875 data_offset);
4876 name_len = le32_to_cpu(ea_response_data->list_len);
4877 cFYI(1,("ea length %d", name_len));
4878 if(name_len <= 8) {
4879 /* returned EA size zeroed at top of function */
4880 cFYI(1,("empty EA list returned from server"));
4881 } else {
4882 /* account for ea list len */
4883 name_len -= 4;
4884 temp_fea = ea_response_data->list;
4885 temp_ptr = (char *)temp_fea;
4886 while(name_len > 0) {
4887 __u16 value_len;
4888 name_len -= 4;
4889 temp_ptr += 4;
4890 rc += temp_fea->name_len;
4891 /* account for prefix user. and trailing null */
4892 rc = rc + 5 + 1;
4893 if(rc<(int)buf_size) {
4894 memcpy(EAData,"user.",5);
4895 EAData+=5;
4896 memcpy(EAData,temp_ptr,temp_fea->name_len);
4897 EAData+=temp_fea->name_len;
4898 /* null terminate name */
4899 *EAData = 0;
4900 EAData = EAData + 1;
4901 } else if(buf_size == 0) {
4902 /* skip copy - calc size only */
4903 } else {
4904 /* stop before overrun buffer */
4905 rc = -ERANGE;
4906 break;
4907 }
4908 name_len -= temp_fea->name_len;
4909 temp_ptr += temp_fea->name_len;
4910 /* account for trailing null */
4911 name_len--;
4912 temp_ptr++;
4913 value_len = le16_to_cpu(temp_fea->value_len);
4914 name_len -= value_len;
4915 temp_ptr += value_len;
4916 /* BB check that temp_ptr is still within smb BB*/
4917 /* no trailing null to account for in value len */
4918 /* go on to next EA */
4919 temp_fea = (struct fea *)temp_ptr;
4920 }
4921 }
4922 }
4923 }
4924 if (pSMB)
4925 cifs_buf_release(pSMB);
4926 if (rc == -EAGAIN)
4927 goto QAllEAsRetry;
4928
4929 return (ssize_t)rc;
4930}
4931
4932ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4933 const unsigned char * searchName,const unsigned char * ea_name,
4934 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004935 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936{
4937 TRANSACTION2_QPI_REQ *pSMB = NULL;
4938 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4939 int rc = 0;
4940 int bytes_returned;
4941 int name_len;
4942 struct fea * temp_fea;
4943 char * temp_ptr;
4944 __u16 params, byte_count;
4945
4946 cFYI(1, ("In Query EA path %s", searchName));
4947QEARetry:
4948 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4949 (void **) &pSMBr);
4950 if (rc)
4951 return rc;
4952
4953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4954 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004955 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004956 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 name_len++; /* trailing null */
4958 name_len *= 2;
4959 } else { /* BB improve the check for buffer overruns BB */
4960 name_len = strnlen(searchName, PATH_MAX);
4961 name_len++; /* trailing null */
4962 strncpy(pSMB->FileName, searchName, name_len);
4963 }
4964
4965 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4966 pSMB->TotalDataCount = 0;
4967 pSMB->MaxParameterCount = cpu_to_le16(2);
4968 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4969 pSMB->MaxSetupCount = 0;
4970 pSMB->Reserved = 0;
4971 pSMB->Flags = 0;
4972 pSMB->Timeout = 0;
4973 pSMB->Reserved2 = 0;
4974 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4975 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4976 pSMB->DataCount = 0;
4977 pSMB->DataOffset = 0;
4978 pSMB->SetupCount = 1;
4979 pSMB->Reserved3 = 0;
4980 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4981 byte_count = params + 1 /* pad */ ;
4982 pSMB->TotalParameterCount = cpu_to_le16(params);
4983 pSMB->ParameterCount = pSMB->TotalParameterCount;
4984 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4985 pSMB->Reserved4 = 0;
4986 pSMB->hdr.smb_buf_length += byte_count;
4987 pSMB->ByteCount = cpu_to_le16(byte_count);
4988
4989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4991 if (rc) {
4992 cFYI(1, ("Send error in Query EA = %d", rc));
4993 } else { /* decode response */
4994 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4995
4996 /* BB also check enough total bytes returned */
4997 /* BB we need to improve the validity checking
4998 of these trans2 responses */
4999 if (rc || (pSMBr->ByteCount < 4))
5000 rc = -EIO; /* bad smb */
5001 /* else if (pFindData){
5002 memcpy((char *) pFindData,
5003 (char *) &pSMBr->hdr.Protocol +
5004 data_offset, kl);
5005 }*/ else {
5006 /* check that length of list is not more than bcc */
5007 /* check that each entry does not go beyond length
5008 of list */
5009 /* check that each element of each entry does not
5010 go beyond end of list */
5011 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5012 struct fealist * ea_response_data;
5013 rc = -ENODATA;
5014 /* validate_trans2_offsets() */
5015 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5016 ea_response_data = (struct fealist *)
5017 (((char *) &pSMBr->hdr.Protocol) +
5018 data_offset);
5019 name_len = le32_to_cpu(ea_response_data->list_len);
5020 cFYI(1,("ea length %d", name_len));
5021 if(name_len <= 8) {
5022 /* returned EA size zeroed at top of function */
5023 cFYI(1,("empty EA list returned from server"));
5024 } else {
5025 /* account for ea list len */
5026 name_len -= 4;
5027 temp_fea = ea_response_data->list;
5028 temp_ptr = (char *)temp_fea;
5029 /* loop through checking if we have a matching
5030 name and then return the associated value */
5031 while(name_len > 0) {
5032 __u16 value_len;
5033 name_len -= 4;
5034 temp_ptr += 4;
5035 value_len = le16_to_cpu(temp_fea->value_len);
5036 /* BB validate that value_len falls within SMB,
5037 even though maximum for name_len is 255 */
5038 if(memcmp(temp_fea->name,ea_name,
5039 temp_fea->name_len) == 0) {
5040 /* found a match */
5041 rc = value_len;
5042 /* account for prefix user. and trailing null */
5043 if(rc<=(int)buf_size) {
5044 memcpy(ea_value,
5045 temp_fea->name+temp_fea->name_len+1,
5046 rc);
5047 /* ea values, unlike ea names,
5048 are not null terminated */
5049 } else if(buf_size == 0) {
5050 /* skip copy - calc size only */
5051 } else {
5052 /* stop before overrun buffer */
5053 rc = -ERANGE;
5054 }
5055 break;
5056 }
5057 name_len -= temp_fea->name_len;
5058 temp_ptr += temp_fea->name_len;
5059 /* account for trailing null */
5060 name_len--;
5061 temp_ptr++;
5062 name_len -= value_len;
5063 temp_ptr += value_len;
5064 /* no trailing null to account for in value len */
5065 /* go on to next EA */
5066 temp_fea = (struct fea *)temp_ptr;
5067 }
5068 }
5069 }
5070 }
5071 if (pSMB)
5072 cifs_buf_release(pSMB);
5073 if (rc == -EAGAIN)
5074 goto QEARetry;
5075
5076 return (ssize_t)rc;
5077}
5078
5079int
5080CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5081 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005082 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5083 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084{
5085 struct smb_com_transaction2_spi_req *pSMB = NULL;
5086 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5087 struct fealist *parm_data;
5088 int name_len;
5089 int rc = 0;
5090 int bytes_returned = 0;
5091 __u16 params, param_offset, byte_count, offset, count;
5092
5093 cFYI(1, ("In SetEA"));
5094SetEARetry:
5095 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5096 (void **) &pSMBr);
5097 if (rc)
5098 return rc;
5099
5100 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5101 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005102 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005103 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 name_len++; /* trailing null */
5105 name_len *= 2;
5106 } else { /* BB improve the check for buffer overruns BB */
5107 name_len = strnlen(fileName, PATH_MAX);
5108 name_len++; /* trailing null */
5109 strncpy(pSMB->FileName, fileName, name_len);
5110 }
5111
5112 params = 6 + name_len;
5113
5114 /* done calculating parms using name_len of file name,
5115 now use name_len to calculate length of ea name
5116 we are going to create in the inode xattrs */
5117 if(ea_name == NULL)
5118 name_len = 0;
5119 else
5120 name_len = strnlen(ea_name,255);
5121
5122 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5123 pSMB->MaxParameterCount = cpu_to_le16(2);
5124 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5125 pSMB->MaxSetupCount = 0;
5126 pSMB->Reserved = 0;
5127 pSMB->Flags = 0;
5128 pSMB->Timeout = 0;
5129 pSMB->Reserved2 = 0;
5130 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5131 InformationLevel) - 4;
5132 offset = param_offset + params;
5133 pSMB->InformationLevel =
5134 cpu_to_le16(SMB_SET_FILE_EA);
5135
5136 parm_data =
5137 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5138 offset);
5139 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5140 pSMB->DataOffset = cpu_to_le16(offset);
5141 pSMB->SetupCount = 1;
5142 pSMB->Reserved3 = 0;
5143 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5144 byte_count = 3 /* pad */ + params + count;
5145 pSMB->DataCount = cpu_to_le16(count);
5146 parm_data->list_len = cpu_to_le32(count);
5147 parm_data->list[0].EA_flags = 0;
5148 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005149 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 /* EA names are always ASCII */
5151 if(ea_name)
5152 strncpy(parm_data->list[0].name,ea_name,name_len);
5153 parm_data->list[0].name[name_len] = 0;
5154 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5155 /* caller ensures that ea_value_len is less than 64K but
5156 we need to ensure that it fits within the smb */
5157
5158 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5159 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5160 if(ea_value_len)
5161 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5162
5163 pSMB->TotalDataCount = pSMB->DataCount;
5164 pSMB->ParameterCount = cpu_to_le16(params);
5165 pSMB->TotalParameterCount = pSMB->ParameterCount;
5166 pSMB->Reserved4 = 0;
5167 pSMB->hdr.smb_buf_length += byte_count;
5168 pSMB->ByteCount = cpu_to_le16(byte_count);
5169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5171 if (rc) {
5172 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5173 }
5174
5175 cifs_buf_release(pSMB);
5176
5177 if (rc == -EAGAIN)
5178 goto SetEARetry;
5179
5180 return rc;
5181}
5182
5183#endif