blob: 6b5be6d59f07d86bd7043fb60724fb09d9602ab4 [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;
439 } else if((pSMBr->hdr.WordCount == 13) &&
440 (pSMBr->DialectIndex == LANMAN_PROT)) {
Steve French7c7b25b2006-06-01 19:20:10 +0000441#ifdef CONFIG_CIFS_WEAK_PW_HASH
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 */
480 cERROR(1,("mount failed, cifs module not built with "
481 "CIFS_WEAK_PW_HASH support"));
482 rc = -EOPNOTSUPP;
483#endif /* WEAK_PW_HASH */
Steve French39798772006-05-31 22:40:51 +0000484 goto neg_err_exit;
485 } else if(pSMBr->hdr.WordCount != 17) {
486 /* unknown wct */
487 rc = -EOPNOTSUPP;
488 goto neg_err_exit;
489 }
490
Steve Frencheeac8042006-01-13 21:34:58 -0800491 server->secMode = pSMBr->SecurityMode;
492 if((server->secMode & SECMODE_USER) == 0)
493 cFYI(1,("share mode security"));
Steve French7c7b25b2006-06-01 19:20:10 +0000494
495 if(extended_security & CIFSSEC_MUST_NTLMV2)
496 server->secType = NTLMv2;
497 else
498 server->secType = NTLM;
499 /* else krb5 ... */
500
Steve French09d1db52005-04-28 22:41:08 -0700501 /* one byte - no need to convert this or EncryptionKeyLen
502 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
504 /* probably no need to store and check maxvcs */
505 server->maxBuf =
506 min(le32_to_cpu(pSMBr->MaxBufferSize),
507 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
508 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve Frencheeac8042006-01-13 21:34:58 -0800509 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
511 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
512 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
513 /* BB with UTC do we ever need to be using srvr timezone? */
514 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
515 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
516 CIFS_CRYPTO_KEY_SIZE);
517 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
518 && (pSMBr->EncryptionKeyLength == 0)) {
519 /* decode security blob */
520 } else
521 rc = -EIO;
522
523 /* BB might be helpful to save off the domain of server here */
524
525 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
526 (server->capabilities & CAP_EXTENDED_SECURITY)) {
527 count = pSMBr->ByteCount;
528 if (count < 16)
529 rc = -EIO;
530 else if (count == 16) {
531 server->secType = RawNTLMSSP;
532 if (server->socketUseCount.counter > 1) {
533 if (memcmp
534 (server->server_GUID,
535 pSMBr->u.extended_response.
536 GUID, 16) != 0) {
Steve Frencheeac8042006-01-13 21:34:58 -0800537 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 memcpy(server->
539 server_GUID,
540 pSMBr->u.
541 extended_response.
542 GUID, 16);
543 }
544 } else
545 memcpy(server->server_GUID,
546 pSMBr->u.extended_response.
547 GUID, 16);
548 } else {
549 rc = decode_negTokenInit(pSMBr->u.
550 extended_response.
551 SecurityBlob,
552 count - 16,
553 &server->secType);
554 if(rc == 1) {
555 /* BB Need to fill struct for sessetup here */
556 rc = -EOPNOTSUPP;
557 } else {
558 rc = -EINVAL;
559 }
560 }
561 } else
562 server->capabilities &= ~CAP_EXTENDED_SECURITY;
563 if(sign_CIFS_PDUs == FALSE) {
564 if(server->secMode & SECMODE_SIGN_REQUIRED)
565 cERROR(1,
566 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700567 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 } else if(sign_CIFS_PDUs == 1) {
569 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700570 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 }
572
573 }
Steve French39798772006-05-31 22:40:51 +0000574neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700575 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return rc;
577}
578
579int
580CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
581{
582 struct smb_hdr *smb_buffer;
583 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
584 int rc = 0;
585 int length;
586
587 cFYI(1, ("In tree disconnect"));
588 /*
589 * If last user of the connection and
590 * connection alive - disconnect it
591 * If this is the last connection on the server session disconnect it
592 * (and inside session disconnect we should check if tcp socket needs
593 * to be freed and kernel thread woken up).
594 */
595 if (tcon)
596 down(&tcon->tconSem);
597 else
598 return -EIO;
599
600 atomic_dec(&tcon->useCount);
601 if (atomic_read(&tcon->useCount) > 0) {
602 up(&tcon->tconSem);
603 return -EBUSY;
604 }
605
606 /* No need to return error on this operation if tid invalidated and
607 closed on server already e.g. due to tcp session crashing */
608 if(tcon->tidStatus == CifsNeedReconnect) {
609 up(&tcon->tconSem);
610 return 0;
611 }
612
613 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
614 up(&tcon->tconSem);
615 return -EIO;
616 }
Steve French09d1db52005-04-28 22:41:08 -0700617 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
618 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if (rc) {
620 up(&tcon->tconSem);
621 return rc;
622 } else {
623 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
626 &length, 0);
627 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700628 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 if (smb_buffer)
631 cifs_small_buf_release(smb_buffer);
632 up(&tcon->tconSem);
633
634 /* No need to return error on this operation if tid invalidated and
635 closed on server already e.g. due to tcp session crashing */
636 if (rc == -EAGAIN)
637 rc = 0;
638
639 return rc;
640}
641
642int
643CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
644{
645 struct smb_hdr *smb_buffer_response;
646 LOGOFF_ANDX_REQ *pSMB;
647 int rc = 0;
648 int length;
649
650 cFYI(1, ("In SMBLogoff for session disconnect"));
651 if (ses)
652 down(&ses->sesSem);
653 else
654 return -EIO;
655
656 atomic_dec(&ses->inUse);
657 if (atomic_read(&ses->inUse) > 0) {
658 up(&ses->sesSem);
659 return -EBUSY;
660 }
661 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
662 if (rc) {
663 up(&ses->sesSem);
664 return rc;
665 }
666
667 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
668
669 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700670 pSMB->hdr.Mid = GetNextMid(ses->server);
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if(ses->server->secMode &
673 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
674 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
675 }
676
677 pSMB->hdr.Uid = ses->Suid;
678
679 pSMB->AndXCommand = 0xFF;
680 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
681 smb_buffer_response, &length, 0);
682 if (ses->server) {
683 atomic_dec(&ses->server->socketUseCount);
684 if (atomic_read(&ses->server->socketUseCount) == 0) {
685 spin_lock(&GlobalMid_Lock);
686 ses->server->tcpStatus = CifsExiting;
687 spin_unlock(&GlobalMid_Lock);
688 rc = -ESHUTDOWN;
689 }
690 }
Steve Frencha59c6582005-08-17 12:12:19 -0700691 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700692 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 /* if session dead then we do not need to do ulogoff,
695 since server closed smb session, no sense reporting
696 error */
697 if (rc == -EAGAIN)
698 rc = 0;
699 return rc;
700}
701
702int
Steve French737b7582005-04-28 22:41:06 -0700703CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
704 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
706 DELETE_FILE_REQ *pSMB = NULL;
707 DELETE_FILE_RSP *pSMBr = NULL;
708 int rc = 0;
709 int bytes_returned;
710 int name_len;
711
712DelFileRetry:
713 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
714 (void **) &pSMBr);
715 if (rc)
716 return rc;
717
718 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
719 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500720 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700721 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 name_len++; /* trailing null */
723 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700724 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 name_len = strnlen(fileName, PATH_MAX);
726 name_len++; /* trailing null */
727 strncpy(pSMB->fileName, fileName, name_len);
728 }
729 pSMB->SearchAttributes =
730 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
731 pSMB->BufferFormat = 0x04;
732 pSMB->hdr.smb_buf_length += name_len + 1;
733 pSMB->ByteCount = cpu_to_le16(name_len + 1);
734 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
735 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700736 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 if (rc) {
738 cFYI(1, ("Error in RMFile = %d", rc));
739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 cifs_buf_release(pSMB);
742 if (rc == -EAGAIN)
743 goto DelFileRetry;
744
745 return rc;
746}
747
748int
Steve French737b7582005-04-28 22:41:06 -0700749CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
750 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
752 DELETE_DIRECTORY_REQ *pSMB = NULL;
753 DELETE_DIRECTORY_RSP *pSMBr = NULL;
754 int rc = 0;
755 int bytes_returned;
756 int name_len;
757
758 cFYI(1, ("In CIFSSMBRmDir"));
759RmDirRetry:
760 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
761 (void **) &pSMBr);
762 if (rc)
763 return rc;
764
765 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700766 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
767 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 name_len++; /* trailing null */
769 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700770 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 name_len = strnlen(dirName, PATH_MAX);
772 name_len++; /* trailing null */
773 strncpy(pSMB->DirName, dirName, name_len);
774 }
775
776 pSMB->BufferFormat = 0x04;
777 pSMB->hdr.smb_buf_length += name_len + 1;
778 pSMB->ByteCount = cpu_to_le16(name_len + 1);
779 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
780 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700781 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (rc) {
783 cFYI(1, ("Error in RMDir = %d", rc));
784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
786 cifs_buf_release(pSMB);
787 if (rc == -EAGAIN)
788 goto RmDirRetry;
789 return rc;
790}
791
792int
793CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700794 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
796 int rc = 0;
797 CREATE_DIRECTORY_REQ *pSMB = NULL;
798 CREATE_DIRECTORY_RSP *pSMBr = NULL;
799 int bytes_returned;
800 int name_len;
801
802 cFYI(1, ("In CIFSSMBMkDir"));
803MkDirRetry:
804 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
805 (void **) &pSMBr);
806 if (rc)
807 return rc;
808
809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500810 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700811 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 name_len++; /* trailing null */
813 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700814 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 name_len = strnlen(name, PATH_MAX);
816 name_len++; /* trailing null */
817 strncpy(pSMB->DirName, name, name_len);
818 }
819
820 pSMB->BufferFormat = 0x04;
821 pSMB->hdr.smb_buf_length += name_len + 1;
822 pSMB->ByteCount = cpu_to_le16(name_len + 1);
823 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
824 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700825 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (rc) {
827 cFYI(1, ("Error in Mkdir = %d", rc));
828 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 cifs_buf_release(pSMB);
831 if (rc == -EAGAIN)
832 goto MkDirRetry;
833 return rc;
834}
835
Steve Frencha9d02ad2005-08-24 23:06:05 -0700836static __u16 convert_disposition(int disposition)
837{
838 __u16 ofun = 0;
839
840 switch (disposition) {
841 case FILE_SUPERSEDE:
842 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
843 break;
844 case FILE_OPEN:
845 ofun = SMBOPEN_OAPPEND;
846 break;
847 case FILE_CREATE:
848 ofun = SMBOPEN_OCREATE;
849 break;
850 case FILE_OPEN_IF:
851 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
852 break;
853 case FILE_OVERWRITE:
854 ofun = SMBOPEN_OTRUNC;
855 break;
856 case FILE_OVERWRITE_IF:
857 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
858 break;
859 default:
860 cFYI(1,("unknown disposition %d",disposition));
861 ofun = SMBOPEN_OAPPEND; /* regular open */
862 }
863 return ofun;
864}
865
866int
867SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
868 const char *fileName, const int openDisposition,
869 const int access_flags, const int create_options, __u16 * netfid,
870 int *pOplock, FILE_ALL_INFO * pfile_info,
871 const struct nls_table *nls_codepage, int remap)
872{
873 int rc = -EACCES;
874 OPENX_REQ *pSMB = NULL;
875 OPENX_RSP *pSMBr = NULL;
876 int bytes_returned;
877 int name_len;
878 __u16 count;
879
880OldOpenRetry:
881 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
882 (void **) &pSMBr);
883 if (rc)
884 return rc;
885
886 pSMB->AndXCommand = 0xFF; /* none */
887
888 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
889 count = 1; /* account for one byte pad to word boundary */
890 name_len =
891 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
892 fileName, PATH_MAX, nls_codepage, remap);
893 name_len++; /* trailing null */
894 name_len *= 2;
895 } else { /* BB improve check for buffer overruns BB */
896 count = 0; /* no pad */
897 name_len = strnlen(fileName, PATH_MAX);
898 name_len++; /* trailing null */
899 strncpy(pSMB->fileName, fileName, name_len);
900 }
901 if (*pOplock & REQ_OPLOCK)
902 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
903 else if (*pOplock & REQ_BATCHOPLOCK) {
904 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
905 }
906 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
907 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
908 /* 0 = read
909 1 = write
910 2 = rw
911 3 = execute
912 */
913 pSMB->Mode = cpu_to_le16(2);
914 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
915 /* set file as system file if special file such
916 as fifo and server expecting SFU style and
917 no Unix extensions */
918
919 if(create_options & CREATE_OPTION_SPECIAL)
920 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
921 else
Steve French3e87d802005-09-18 20:49:21 -0700922 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700923
924 /* if ((omode & S_IWUGO) == 0)
925 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
926 /* Above line causes problems due to vfs splitting create into two
927 pieces - need to set mode after file created not while it is
928 being created */
929
930 /* BB FIXME BB */
931/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
932 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700933
934 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700935 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700936 count += name_len;
937 pSMB->hdr.smb_buf_length += count;
938
939 pSMB->ByteCount = cpu_to_le16(count);
940 /* long_op set to 1 to allow for oplock break timeouts */
941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
942 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
943 cifs_stats_inc(&tcon->num_opens);
944 if (rc) {
945 cFYI(1, ("Error in Open = %d", rc));
946 } else {
947 /* BB verify if wct == 15 */
948
949/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
950
951 *netfid = pSMBr->Fid; /* cifs fid stays in le */
952 /* Let caller know file was created so we can set the mode. */
953 /* Do we care about the CreateAction in any other cases? */
954 /* BB FIXME BB */
955/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
956 *pOplock |= CIFS_CREATE_ACTION; */
957 /* BB FIXME END */
958
959 if(pfile_info) {
960 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
961 pfile_info->LastAccessTime = 0; /* BB fixme */
962 pfile_info->LastWriteTime = 0; /* BB fixme */
963 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700964 pfile_info->Attributes =
965 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700966 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700967 pfile_info->AllocationSize =
968 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
969 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700970 pfile_info->NumberOfLinks = cpu_to_le32(1);
971 }
972 }
973
974 cifs_buf_release(pSMB);
975 if (rc == -EAGAIN)
976 goto OldOpenRetry;
977 return rc;
978}
979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980int
981CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
982 const char *fileName, const int openDisposition,
983 const int access_flags, const int create_options, __u16 * netfid,
984 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700985 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
987 int rc = -EACCES;
988 OPEN_REQ *pSMB = NULL;
989 OPEN_RSP *pSMBr = NULL;
990 int bytes_returned;
991 int name_len;
992 __u16 count;
993
994openRetry:
995 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
996 (void **) &pSMBr);
997 if (rc)
998 return rc;
999
1000 pSMB->AndXCommand = 0xFF; /* none */
1001
1002 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1003 count = 1; /* account for one byte pad to word boundary */
1004 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001005 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001006 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 name_len++; /* trailing null */
1008 name_len *= 2;
1009 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001010 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 count = 0; /* no pad */
1012 name_len = strnlen(fileName, PATH_MAX);
1013 name_len++; /* trailing null */
1014 pSMB->NameLength = cpu_to_le16(name_len);
1015 strncpy(pSMB->fileName, fileName, name_len);
1016 }
1017 if (*pOplock & REQ_OPLOCK)
1018 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1019 else if (*pOplock & REQ_BATCHOPLOCK) {
1020 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1021 }
1022 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1023 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001024 /* set file as system file if special file such
1025 as fifo and server expecting SFU style and
1026 no Unix extensions */
1027 if(create_options & CREATE_OPTION_SPECIAL)
1028 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1029 else
1030 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 /* XP does not handle ATTR_POSIX_SEMANTICS */
1032 /* but it helps speed up case sensitive checks for other
1033 servers such as Samba */
1034 if (tcon->ses->capabilities & CAP_UNIX)
1035 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1036
1037 /* if ((omode & S_IWUGO) == 0)
1038 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1039 /* Above line causes problems due to vfs splitting create into two
1040 pieces - need to set mode after file created not while it is
1041 being created */
1042 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1043 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001044 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001045 /* BB Expirement with various impersonation levels and verify */
1046 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 pSMB->SecurityFlags =
1048 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1049
1050 count += name_len;
1051 pSMB->hdr.smb_buf_length += count;
1052
1053 pSMB->ByteCount = cpu_to_le16(count);
1054 /* long_op set to 1 to allow for oplock break timeouts */
1055 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1056 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001057 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 if (rc) {
1059 cFYI(1, ("Error in Open = %d", rc));
1060 } else {
Steve French09d1db52005-04-28 22:41:08 -07001061 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1063 /* Let caller know file was created so we can set the mode. */
1064 /* Do we care about the CreateAction in any other cases? */
1065 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1066 *pOplock |= CIFS_CREATE_ACTION;
1067 if(pfile_info) {
1068 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1069 36 /* CreationTime to Attributes */);
1070 /* the file_info buf is endian converted by caller */
1071 pfile_info->AllocationSize = pSMBr->AllocationSize;
1072 pfile_info->EndOfFile = pSMBr->EndOfFile;
1073 pfile_info->NumberOfLinks = cpu_to_le32(1);
1074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 cifs_buf_release(pSMB);
1078 if (rc == -EAGAIN)
1079 goto openRetry;
1080 return rc;
1081}
1082
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083int
1084CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001085 const int netfid, const unsigned int count,
1086 const __u64 lseek, unsigned int *nbytes, char **buf,
1087 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
1089 int rc = -EACCES;
1090 READ_REQ *pSMB = NULL;
1091 READ_RSP *pSMBr = NULL;
1092 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001093 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001094 int resp_buf_type = 0;
1095 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001098 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1099 wct = 12;
1100 else
1101 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001104 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 if (rc)
1106 return rc;
1107
1108 /* tcon and ses pointer are checked in smb_init */
1109 if (tcon->ses->server == NULL)
1110 return -ECONNABORTED;
1111
Steve Frenchec637e32005-12-12 20:53:18 -08001112 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 pSMB->Fid = netfid;
1114 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001115 if(wct == 12)
1116 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001117 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1118 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 pSMB->Remaining = 0;
1121 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1122 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001123 if(wct == 12)
1124 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1125 else {
1126 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001127 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001128 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001129 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001130 }
Steve Frenchec637e32005-12-12 20:53:18 -08001131
1132 iov[0].iov_base = (char *)pSMB;
1133 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1134 rc = SendReceive2(xid, tcon->ses, iov,
1135 1 /* num iovecs */,
1136 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001137 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001138 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 if (rc) {
1140 cERROR(1, ("Send error in read = %d", rc));
1141 } else {
1142 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1143 data_length = data_length << 16;
1144 data_length += le16_to_cpu(pSMBr->DataLength);
1145 *nbytes = data_length;
1146
1147 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001148 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 || (data_length > count)) {
1150 cFYI(1,("bad length %d for count %d",data_length,count));
1151 rc = -EIO;
1152 *nbytes = 0;
1153 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001154 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001156/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1157 cERROR(1,("Faulting on read rc = %d",rc));
1158 rc = -EFAULT;
1159 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001161 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
Steve French4b8f9302006-02-26 16:41:18 +00001165/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001166 if(*buf) {
1167 if(resp_buf_type == CIFS_SMALL_BUFFER)
1168 cifs_small_buf_release(iov[0].iov_base);
1169 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1170 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001171 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1172 /* return buffer to caller to free */
1173 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001174 if(resp_buf_type == CIFS_SMALL_BUFFER)
1175 *pbuf_type = CIFS_SMALL_BUFFER;
1176 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1177 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001178 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001179
1180 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 since file handle passed in no longer valid */
1182 return rc;
1183}
1184
Steve Frenchec637e32005-12-12 20:53:18 -08001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186int
1187CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1188 const int netfid, const unsigned int count,
1189 const __u64 offset, unsigned int *nbytes, const char *buf,
1190 const char __user * ubuf, const int long_op)
1191{
1192 int rc = -EACCES;
1193 WRITE_REQ *pSMB = NULL;
1194 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001195 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 __u32 bytes_sent;
1197 __u16 byte_count;
1198
1199 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001200 if(tcon->ses == NULL)
1201 return -ECONNABORTED;
1202
1203 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1204 wct = 14;
1205 else
1206 wct = 12;
1207
1208 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 (void **) &pSMBr);
1210 if (rc)
1211 return rc;
1212 /* tcon and ses pointer are checked in smb_init */
1213 if (tcon->ses->server == NULL)
1214 return -ECONNABORTED;
1215
1216 pSMB->AndXCommand = 0xFF; /* none */
1217 pSMB->Fid = netfid;
1218 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001219 if(wct == 14)
1220 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1221 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1222 return -EIO;
1223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 pSMB->Reserved = 0xFFFFFFFF;
1225 pSMB->WriteMode = 0;
1226 pSMB->Remaining = 0;
1227
1228 /* Can increase buffer size if buffer is big enough in some cases - ie we
1229 can send more if LARGE_WRITE_X capability returned by the server and if
1230 our buffer is big enough or if we convert to iovecs on socket writes
1231 and eliminate the copy to the CIFS buffer */
1232 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1233 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1234 } else {
1235 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1236 & ~0xFF;
1237 }
1238
1239 if (bytes_sent > count)
1240 bytes_sent = count;
1241 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001242 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if(buf)
1244 memcpy(pSMB->Data,buf,bytes_sent);
1245 else if(ubuf) {
1246 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1247 cifs_buf_release(pSMB);
1248 return -EFAULT;
1249 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001250 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 /* No buffer */
1252 cifs_buf_release(pSMB);
1253 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001254 } /* else setting file size with write of zero bytes */
1255 if(wct == 14)
1256 byte_count = bytes_sent + 1; /* pad */
1257 else /* wct == 12 */ {
1258 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1261 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001262 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001263
1264 if(wct == 14)
1265 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001266 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001267 struct smb_com_writex_req * pSMBW =
1268 (struct smb_com_writex_req *)pSMB;
1269 pSMBW->ByteCount = cpu_to_le16(byte_count);
1270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
1272 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1273 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001274 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 if (rc) {
1276 cFYI(1, ("Send error in write = %d", rc));
1277 *nbytes = 0;
1278 } else {
1279 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1280 *nbytes = (*nbytes) << 16;
1281 *nbytes += le16_to_cpu(pSMBr->Count);
1282 }
1283
1284 cifs_buf_release(pSMB);
1285
1286 /* Note: On -EAGAIN error only caller can retry on handle based calls
1287 since file handle passed in no longer valid */
1288
1289 return rc;
1290}
1291
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001292int
1293CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001295 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1296 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297{
1298 int rc = -EACCES;
1299 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001300 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001301 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001302 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
Steve Frenchff7feac2005-11-15 16:45:16 -08001304 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1305
Steve French8cc64c62005-10-03 13:49:43 -07001306 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1307 wct = 14;
1308 else
1309 wct = 12;
1310 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (rc)
1312 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 /* tcon and ses pointer are checked in smb_init */
1314 if (tcon->ses->server == NULL)
1315 return -ECONNABORTED;
1316
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001317 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 pSMB->Fid = netfid;
1319 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001320 if(wct == 14)
1321 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1322 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1323 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 pSMB->Reserved = 0xFFFFFFFF;
1325 pSMB->WriteMode = 0;
1326 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 pSMB->DataOffset =
1329 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1330
Steve French3e844692005-10-03 13:37:24 -07001331 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1332 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001333 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001334 if(wct == 14)
1335 pSMB->hdr.smb_buf_length += count+1;
1336 else /* wct == 12 */
1337 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1338 if(wct == 14)
1339 pSMB->ByteCount = cpu_to_le16(count + 1);
1340 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1341 struct smb_com_writex_req * pSMBW =
1342 (struct smb_com_writex_req *)pSMB;
1343 pSMBW->ByteCount = cpu_to_le16(count + 5);
1344 }
Steve French3e844692005-10-03 13:37:24 -07001345 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001346 if(wct == 14)
1347 iov[0].iov_len = smb_hdr_len + 4;
1348 else /* wct == 12 pad bigger by four bytes */
1349 iov[0].iov_len = smb_hdr_len + 8;
1350
Steve French3e844692005-10-03 13:37:24 -07001351
Steve Frenchec637e32005-12-12 20:53:18 -08001352 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001353 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001354 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001356 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001358 } else if(resp_buf_type == 0) {
1359 /* presumably this can not happen, but best to be safe */
1360 rc = -EIO;
1361 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001362 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001363 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001364 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1365 *nbytes = (*nbytes) << 16;
1366 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
Steve French4b8f9302006-02-26 16:41:18 +00001369/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001370 if(resp_buf_type == CIFS_SMALL_BUFFER)
1371 cifs_small_buf_release(iov[0].iov_base);
1372 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1373 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
1375 /* Note: On -EAGAIN error only caller can retry on handle based calls
1376 since file handle passed in no longer valid */
1377
1378 return rc;
1379}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001380
1381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382int
1383CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1384 const __u16 smb_file_id, const __u64 len,
1385 const __u64 offset, const __u32 numUnlock,
1386 const __u32 numLock, const __u8 lockType, const int waitFlag)
1387{
1388 int rc = 0;
1389 LOCK_REQ *pSMB = NULL;
1390 LOCK_RSP *pSMBr = NULL;
1391 int bytes_returned;
1392 int timeout = 0;
1393 __u16 count;
1394
1395 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001396 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1397
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 if (rc)
1399 return rc;
1400
Steve French46810cb2005-04-28 22:41:09 -07001401 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1402
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1404 timeout = -1; /* no response expected */
1405 pSMB->Timeout = 0;
1406 } else if (waitFlag == TRUE) {
1407 timeout = 3; /* blocking operation, no timeout */
1408 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1409 } else {
1410 pSMB->Timeout = 0;
1411 }
1412
1413 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1414 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1415 pSMB->LockType = lockType;
1416 pSMB->AndXCommand = 0xFF; /* none */
1417 pSMB->Fid = smb_file_id; /* netfid stays le */
1418
1419 if((numLock != 0) || (numUnlock != 0)) {
1420 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1421 /* BB where to store pid high? */
1422 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1423 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1424 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1425 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1426 count = sizeof(LOCKING_ANDX_RANGE);
1427 } else {
1428 /* oplock break */
1429 count = 0;
1430 }
1431 pSMB->hdr.smb_buf_length += count;
1432 pSMB->ByteCount = cpu_to_le16(count);
1433
1434 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1435 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001436 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 if (rc) {
1438 cFYI(1, ("Send error in Lock = %d", rc));
1439 }
Steve French46810cb2005-04-28 22:41:09 -07001440 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
1442 /* Note: On -EAGAIN error only caller can retry on handle based calls
1443 since file handle passed in no longer valid */
1444 return rc;
1445}
1446
1447int
Steve French08547b02006-02-28 22:39:25 +00001448CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1449 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001450 struct file_lock *pLockData, const __u16 lock_type,
1451 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001452{
1453 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1454 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1455 char *data_offset;
1456 struct cifs_posix_lock *parm_data;
1457 int rc = 0;
1458 int bytes_returned = 0;
1459 __u16 params, param_offset, offset, byte_count, count;
1460
1461 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001462
1463 if(pLockData == NULL)
1464 return EINVAL;
1465
Steve French08547b02006-02-28 22:39:25 +00001466 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1467
1468 if (rc)
1469 return rc;
1470
1471 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1472
1473 params = 6;
1474 pSMB->MaxSetupCount = 0;
1475 pSMB->Reserved = 0;
1476 pSMB->Flags = 0;
1477 pSMB->Timeout = 0;
1478 pSMB->Reserved2 = 0;
1479 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1480 offset = param_offset + params;
1481
1482 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1483
1484 count = sizeof(struct cifs_posix_lock);
1485 pSMB->MaxParameterCount = cpu_to_le16(2);
1486 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1487 pSMB->SetupCount = 1;
1488 pSMB->Reserved3 = 0;
1489 if(get_flag)
1490 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1491 else
1492 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1493 byte_count = 3 /* pad */ + params + count;
1494 pSMB->DataCount = cpu_to_le16(count);
1495 pSMB->ParameterCount = cpu_to_le16(params);
1496 pSMB->TotalDataCount = pSMB->DataCount;
1497 pSMB->TotalParameterCount = pSMB->ParameterCount;
1498 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1499 parm_data = (struct cifs_posix_lock *)
1500 (((char *) &pSMB->hdr.Protocol) + offset);
1501
1502 parm_data->lock_type = cpu_to_le16(lock_type);
1503 if(waitFlag)
Steve Frenchcec6815a2006-05-30 18:07:17 +00001504 parm_data->lock_flags = cpu_to_le16(1);
Steve French08547b02006-02-28 22:39:25 +00001505 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001506 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001507 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001508
1509 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001510 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001511 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1512 pSMB->Reserved4 = 0;
1513 pSMB->hdr.smb_buf_length += byte_count;
1514 pSMB->ByteCount = cpu_to_le16(byte_count);
1515 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1516 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1517 if (rc) {
1518 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001519 } else if (get_flag) {
1520 /* lock structure can be returned on get */
1521 __u16 data_offset;
1522 __u16 data_count;
1523 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001524
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001525 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1526 rc = -EIO; /* bad smb */
1527 goto plk_err_exit;
1528 }
1529 if(pLockData == NULL) {
1530 rc = -EINVAL;
1531 goto plk_err_exit;
1532 }
1533 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1534 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1535 if(data_count < sizeof(struct cifs_posix_lock)) {
1536 rc = -EIO;
1537 goto plk_err_exit;
1538 }
1539 parm_data = (struct cifs_posix_lock *)
1540 ((char *)&pSMBr->hdr.Protocol + data_offset);
1541 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1542 pLockData->fl_type = F_UNLCK;
1543 }
1544
1545plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001546 if (pSMB)
1547 cifs_small_buf_release(pSMB);
1548
1549 /* Note: On -EAGAIN error only caller can retry on handle based calls
1550 since file handle passed in no longer valid */
1551
1552 return rc;
1553}
1554
1555
1556int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1558{
1559 int rc = 0;
1560 CLOSE_REQ *pSMB = NULL;
1561 CLOSE_RSP *pSMBr = NULL;
1562 int bytes_returned;
1563 cFYI(1, ("In CIFSSMBClose"));
1564
1565/* do not retry on dead session on close */
1566 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1567 if(rc == -EAGAIN)
1568 return 0;
1569 if (rc)
1570 return rc;
1571
1572 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1573
1574 pSMB->FileID = (__u16) smb_file_id;
1575 pSMB->LastWriteTime = 0;
1576 pSMB->ByteCount = 0;
1577 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1578 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001579 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 if (rc) {
1581 if(rc!=-EINTR) {
1582 /* EINTR is expected when user ctl-c to kill app */
1583 cERROR(1, ("Send error in Close = %d", rc));
1584 }
1585 }
1586
1587 cifs_small_buf_release(pSMB);
1588
1589 /* Since session is dead, file will be closed on server already */
1590 if(rc == -EAGAIN)
1591 rc = 0;
1592
1593 return rc;
1594}
1595
1596int
1597CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1598 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001599 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600{
1601 int rc = 0;
1602 RENAME_REQ *pSMB = NULL;
1603 RENAME_RSP *pSMBr = NULL;
1604 int bytes_returned;
1605 int name_len, name_len2;
1606 __u16 count;
1607
1608 cFYI(1, ("In CIFSSMBRename"));
1609renameRetry:
1610 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1611 (void **) &pSMBr);
1612 if (rc)
1613 return rc;
1614
1615 pSMB->BufferFormat = 0x04;
1616 pSMB->SearchAttributes =
1617 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1618 ATTR_DIRECTORY);
1619
1620 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1621 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001622 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001623 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 name_len++; /* trailing null */
1625 name_len *= 2;
1626 pSMB->OldFileName[name_len] = 0x04; /* pad */
1627 /* protocol requires ASCII signature byte on Unicode string */
1628 pSMB->OldFileName[name_len + 1] = 0x00;
1629 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001630 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001631 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1633 name_len2 *= 2; /* convert to bytes */
1634 } else { /* BB improve the check for buffer overruns BB */
1635 name_len = strnlen(fromName, PATH_MAX);
1636 name_len++; /* trailing null */
1637 strncpy(pSMB->OldFileName, fromName, name_len);
1638 name_len2 = strnlen(toName, PATH_MAX);
1639 name_len2++; /* trailing null */
1640 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1641 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1642 name_len2++; /* trailing null */
1643 name_len2++; /* signature byte */
1644 }
1645
1646 count = 1 /* 1st signature byte */ + name_len + name_len2;
1647 pSMB->hdr.smb_buf_length += count;
1648 pSMB->ByteCount = cpu_to_le16(count);
1649
1650 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1651 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001652 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 if (rc) {
1654 cFYI(1, ("Send error in rename = %d", rc));
1655 }
1656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 cifs_buf_release(pSMB);
1658
1659 if (rc == -EAGAIN)
1660 goto renameRetry;
1661
1662 return rc;
1663}
1664
1665int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001666 int netfid, char * target_name,
1667 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668{
1669 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1670 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1671 struct set_file_rename * rename_info;
1672 char *data_offset;
1673 char dummy_string[30];
1674 int rc = 0;
1675 int bytes_returned = 0;
1676 int len_of_str;
1677 __u16 params, param_offset, offset, count, byte_count;
1678
1679 cFYI(1, ("Rename to File by handle"));
1680 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1681 (void **) &pSMBr);
1682 if (rc)
1683 return rc;
1684
1685 params = 6;
1686 pSMB->MaxSetupCount = 0;
1687 pSMB->Reserved = 0;
1688 pSMB->Flags = 0;
1689 pSMB->Timeout = 0;
1690 pSMB->Reserved2 = 0;
1691 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1692 offset = param_offset + params;
1693
1694 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1695 rename_info = (struct set_file_rename *) data_offset;
1696 pSMB->MaxParameterCount = cpu_to_le16(2);
1697 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1698 pSMB->SetupCount = 1;
1699 pSMB->Reserved3 = 0;
1700 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1701 byte_count = 3 /* pad */ + params;
1702 pSMB->ParameterCount = cpu_to_le16(params);
1703 pSMB->TotalParameterCount = pSMB->ParameterCount;
1704 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1705 pSMB->DataOffset = cpu_to_le16(offset);
1706 /* construct random name ".cifs_tmp<inodenum><mid>" */
1707 rename_info->overwrite = cpu_to_le32(1);
1708 rename_info->root_fid = 0;
1709 /* unicode only call */
1710 if(target_name == NULL) {
1711 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001712 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001713 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001715 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001716 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 }
1718 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1719 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1720 byte_count += count;
1721 pSMB->DataCount = cpu_to_le16(count);
1722 pSMB->TotalDataCount = pSMB->DataCount;
1723 pSMB->Fid = netfid;
1724 pSMB->InformationLevel =
1725 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1726 pSMB->Reserved4 = 0;
1727 pSMB->hdr.smb_buf_length += byte_count;
1728 pSMB->ByteCount = cpu_to_le16(byte_count);
1729 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001731 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 if (rc) {
1733 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1734 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001735
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 cifs_buf_release(pSMB);
1737
1738 /* Note: On -EAGAIN error only caller can retry on handle based calls
1739 since file handle passed in no longer valid */
1740
1741 return rc;
1742}
1743
1744int
1745CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1746 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001747 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748{
1749 int rc = 0;
1750 COPY_REQ *pSMB = NULL;
1751 COPY_RSP *pSMBr = NULL;
1752 int bytes_returned;
1753 int name_len, name_len2;
1754 __u16 count;
1755
1756 cFYI(1, ("In CIFSSMBCopy"));
1757copyRetry:
1758 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1759 (void **) &pSMBr);
1760 if (rc)
1761 return rc;
1762
1763 pSMB->BufferFormat = 0x04;
1764 pSMB->Tid2 = target_tid;
1765
1766 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1767
1768 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001769 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001770 fromName, PATH_MAX, nls_codepage,
1771 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 name_len++; /* trailing null */
1773 name_len *= 2;
1774 pSMB->OldFileName[name_len] = 0x04; /* pad */
1775 /* protocol requires ASCII signature byte on Unicode string */
1776 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001777 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001778 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1780 name_len2 *= 2; /* convert to bytes */
1781 } else { /* BB improve the check for buffer overruns BB */
1782 name_len = strnlen(fromName, PATH_MAX);
1783 name_len++; /* trailing null */
1784 strncpy(pSMB->OldFileName, fromName, name_len);
1785 name_len2 = strnlen(toName, PATH_MAX);
1786 name_len2++; /* trailing null */
1787 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1788 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1789 name_len2++; /* trailing null */
1790 name_len2++; /* signature byte */
1791 }
1792
1793 count = 1 /* 1st signature byte */ + name_len + name_len2;
1794 pSMB->hdr.smb_buf_length += count;
1795 pSMB->ByteCount = cpu_to_le16(count);
1796
1797 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1798 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1799 if (rc) {
1800 cFYI(1, ("Send error in copy = %d with %d files copied",
1801 rc, le16_to_cpu(pSMBr->CopyCount)));
1802 }
1803 if (pSMB)
1804 cifs_buf_release(pSMB);
1805
1806 if (rc == -EAGAIN)
1807 goto copyRetry;
1808
1809 return rc;
1810}
1811
1812int
1813CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1814 const char *fromName, const char *toName,
1815 const struct nls_table *nls_codepage)
1816{
1817 TRANSACTION2_SPI_REQ *pSMB = NULL;
1818 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1819 char *data_offset;
1820 int name_len;
1821 int name_len_target;
1822 int rc = 0;
1823 int bytes_returned = 0;
1824 __u16 params, param_offset, offset, byte_count;
1825
1826 cFYI(1, ("In Symlink Unix style"));
1827createSymLinkRetry:
1828 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1829 (void **) &pSMBr);
1830 if (rc)
1831 return rc;
1832
1833 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1834 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001835 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 /* find define for this maxpathcomponent */
1837 , nls_codepage);
1838 name_len++; /* trailing null */
1839 name_len *= 2;
1840
1841 } else { /* BB improve the check for buffer overruns BB */
1842 name_len = strnlen(fromName, PATH_MAX);
1843 name_len++; /* trailing null */
1844 strncpy(pSMB->FileName, fromName, name_len);
1845 }
1846 params = 6 + name_len;
1847 pSMB->MaxSetupCount = 0;
1848 pSMB->Reserved = 0;
1849 pSMB->Flags = 0;
1850 pSMB->Timeout = 0;
1851 pSMB->Reserved2 = 0;
1852 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1853 InformationLevel) - 4;
1854 offset = param_offset + params;
1855
1856 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1857 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1858 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001859 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 /* find define for this maxpathcomponent */
1861 , nls_codepage);
1862 name_len_target++; /* trailing null */
1863 name_len_target *= 2;
1864 } else { /* BB improve the check for buffer overruns BB */
1865 name_len_target = strnlen(toName, PATH_MAX);
1866 name_len_target++; /* trailing null */
1867 strncpy(data_offset, toName, name_len_target);
1868 }
1869
1870 pSMB->MaxParameterCount = cpu_to_le16(2);
1871 /* BB find exact max on data count below from sess */
1872 pSMB->MaxDataCount = cpu_to_le16(1000);
1873 pSMB->SetupCount = 1;
1874 pSMB->Reserved3 = 0;
1875 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1876 byte_count = 3 /* pad */ + params + name_len_target;
1877 pSMB->DataCount = cpu_to_le16(name_len_target);
1878 pSMB->ParameterCount = cpu_to_le16(params);
1879 pSMB->TotalDataCount = pSMB->DataCount;
1880 pSMB->TotalParameterCount = pSMB->ParameterCount;
1881 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1882 pSMB->DataOffset = cpu_to_le16(offset);
1883 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1884 pSMB->Reserved4 = 0;
1885 pSMB->hdr.smb_buf_length += byte_count;
1886 pSMB->ByteCount = cpu_to_le16(byte_count);
1887 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1888 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001889 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (rc) {
1891 cFYI(1,
1892 ("Send error in SetPathInfo (create symlink) = %d",
1893 rc));
1894 }
1895
1896 if (pSMB)
1897 cifs_buf_release(pSMB);
1898
1899 if (rc == -EAGAIN)
1900 goto createSymLinkRetry;
1901
1902 return rc;
1903}
1904
1905int
1906CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1907 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001908 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909{
1910 TRANSACTION2_SPI_REQ *pSMB = NULL;
1911 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1912 char *data_offset;
1913 int name_len;
1914 int name_len_target;
1915 int rc = 0;
1916 int bytes_returned = 0;
1917 __u16 params, param_offset, offset, byte_count;
1918
1919 cFYI(1, ("In Create Hard link Unix style"));
1920createHardLinkRetry:
1921 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1922 (void **) &pSMBr);
1923 if (rc)
1924 return rc;
1925
1926 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001927 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001928 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 name_len++; /* trailing null */
1930 name_len *= 2;
1931
1932 } else { /* BB improve the check for buffer overruns BB */
1933 name_len = strnlen(toName, PATH_MAX);
1934 name_len++; /* trailing null */
1935 strncpy(pSMB->FileName, toName, name_len);
1936 }
1937 params = 6 + name_len;
1938 pSMB->MaxSetupCount = 0;
1939 pSMB->Reserved = 0;
1940 pSMB->Flags = 0;
1941 pSMB->Timeout = 0;
1942 pSMB->Reserved2 = 0;
1943 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1944 InformationLevel) - 4;
1945 offset = param_offset + params;
1946
1947 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1949 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001950 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001951 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 name_len_target++; /* trailing null */
1953 name_len_target *= 2;
1954 } else { /* BB improve the check for buffer overruns BB */
1955 name_len_target = strnlen(fromName, PATH_MAX);
1956 name_len_target++; /* trailing null */
1957 strncpy(data_offset, fromName, name_len_target);
1958 }
1959
1960 pSMB->MaxParameterCount = cpu_to_le16(2);
1961 /* BB find exact max on data count below from sess*/
1962 pSMB->MaxDataCount = cpu_to_le16(1000);
1963 pSMB->SetupCount = 1;
1964 pSMB->Reserved3 = 0;
1965 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1966 byte_count = 3 /* pad */ + params + name_len_target;
1967 pSMB->ParameterCount = cpu_to_le16(params);
1968 pSMB->TotalParameterCount = pSMB->ParameterCount;
1969 pSMB->DataCount = cpu_to_le16(name_len_target);
1970 pSMB->TotalDataCount = pSMB->DataCount;
1971 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1972 pSMB->DataOffset = cpu_to_le16(offset);
1973 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1974 pSMB->Reserved4 = 0;
1975 pSMB->hdr.smb_buf_length += byte_count;
1976 pSMB->ByteCount = cpu_to_le16(byte_count);
1977 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1978 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001979 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 if (rc) {
1981 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1982 }
1983
1984 cifs_buf_release(pSMB);
1985 if (rc == -EAGAIN)
1986 goto createHardLinkRetry;
1987
1988 return rc;
1989}
1990
1991int
1992CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1993 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001994 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995{
1996 int rc = 0;
1997 NT_RENAME_REQ *pSMB = NULL;
1998 RENAME_RSP *pSMBr = NULL;
1999 int bytes_returned;
2000 int name_len, name_len2;
2001 __u16 count;
2002
2003 cFYI(1, ("In CIFSCreateHardLink"));
2004winCreateHardLinkRetry:
2005
2006 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2007 (void **) &pSMBr);
2008 if (rc)
2009 return rc;
2010
2011 pSMB->SearchAttributes =
2012 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2013 ATTR_DIRECTORY);
2014 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2015 pSMB->ClusterCount = 0;
2016
2017 pSMB->BufferFormat = 0x04;
2018
2019 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2020 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002021 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002022 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 name_len++; /* trailing null */
2024 name_len *= 2;
2025 pSMB->OldFileName[name_len] = 0; /* pad */
2026 pSMB->OldFileName[name_len + 1] = 0x04;
2027 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002028 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002029 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2031 name_len2 *= 2; /* convert to bytes */
2032 } else { /* BB improve the check for buffer overruns BB */
2033 name_len = strnlen(fromName, PATH_MAX);
2034 name_len++; /* trailing null */
2035 strncpy(pSMB->OldFileName, fromName, name_len);
2036 name_len2 = strnlen(toName, PATH_MAX);
2037 name_len2++; /* trailing null */
2038 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2039 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2040 name_len2++; /* trailing null */
2041 name_len2++; /* signature byte */
2042 }
2043
2044 count = 1 /* string type byte */ + name_len + name_len2;
2045 pSMB->hdr.smb_buf_length += count;
2046 pSMB->ByteCount = cpu_to_le16(count);
2047
2048 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2049 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002050 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 if (rc) {
2052 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2053 }
2054 cifs_buf_release(pSMB);
2055 if (rc == -EAGAIN)
2056 goto winCreateHardLinkRetry;
2057
2058 return rc;
2059}
2060
2061int
2062CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2063 const unsigned char *searchName,
2064 char *symlinkinfo, const int buflen,
2065 const struct nls_table *nls_codepage)
2066{
2067/* SMB_QUERY_FILE_UNIX_LINK */
2068 TRANSACTION2_QPI_REQ *pSMB = NULL;
2069 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2070 int rc = 0;
2071 int bytes_returned;
2072 int name_len;
2073 __u16 params, byte_count;
2074
2075 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2076
2077querySymLinkRetry:
2078 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2079 (void **) &pSMBr);
2080 if (rc)
2081 return rc;
2082
2083 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2084 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002085 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 /* find define for this maxpathcomponent */
2087 , nls_codepage);
2088 name_len++; /* trailing null */
2089 name_len *= 2;
2090 } else { /* BB improve the check for buffer overruns BB */
2091 name_len = strnlen(searchName, PATH_MAX);
2092 name_len++; /* trailing null */
2093 strncpy(pSMB->FileName, searchName, name_len);
2094 }
2095
2096 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2097 pSMB->TotalDataCount = 0;
2098 pSMB->MaxParameterCount = cpu_to_le16(2);
2099 /* BB find exact max data count below from sess structure BB */
2100 pSMB->MaxDataCount = cpu_to_le16(4000);
2101 pSMB->MaxSetupCount = 0;
2102 pSMB->Reserved = 0;
2103 pSMB->Flags = 0;
2104 pSMB->Timeout = 0;
2105 pSMB->Reserved2 = 0;
2106 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2107 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2108 pSMB->DataCount = 0;
2109 pSMB->DataOffset = 0;
2110 pSMB->SetupCount = 1;
2111 pSMB->Reserved3 = 0;
2112 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2113 byte_count = params + 1 /* pad */ ;
2114 pSMB->TotalParameterCount = cpu_to_le16(params);
2115 pSMB->ParameterCount = pSMB->TotalParameterCount;
2116 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2117 pSMB->Reserved4 = 0;
2118 pSMB->hdr.smb_buf_length += byte_count;
2119 pSMB->ByteCount = cpu_to_le16(byte_count);
2120
2121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2123 if (rc) {
2124 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2125 } else {
2126 /* decode response */
2127
2128 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2129 if (rc || (pSMBr->ByteCount < 2))
2130 /* BB also check enough total bytes returned */
2131 rc = -EIO; /* bad smb */
2132 else {
2133 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2134 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2135
2136 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2137 name_len = UniStrnlen((wchar_t *) ((char *)
2138 &pSMBr->hdr.Protocol +data_offset),
2139 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002140 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002142 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 data_offset),
2144 name_len, nls_codepage);
2145 } else {
2146 strncpy(symlinkinfo,
2147 (char *) &pSMBr->hdr.Protocol +
2148 data_offset,
2149 min_t(const int, buflen, count));
2150 }
2151 symlinkinfo[buflen] = 0;
2152 /* just in case so calling code does not go off the end of buffer */
2153 }
2154 }
2155 cifs_buf_release(pSMB);
2156 if (rc == -EAGAIN)
2157 goto querySymLinkRetry;
2158 return rc;
2159}
2160
Steve French0a4b92c2006-01-12 15:44:21 -08002161/* Initialize NT TRANSACT SMB into small smb request buffer.
2162 This assumes that all NT TRANSACTS that we init here have
2163 total parm and data under about 400 bytes (to fit in small cifs
2164 buffer size), which is the case so far, it easily fits. NB:
2165 Setup words themselves and ByteCount
2166 MaxSetupCount (size of returned setup area) and
2167 MaxParameterCount (returned parms size) must be set by caller */
2168static int
2169smb_init_ntransact(const __u16 sub_command, const int setup_count,
2170 const int parm_len, struct cifsTconInfo *tcon,
2171 void ** ret_buf)
2172{
2173 int rc;
2174 __u32 temp_offset;
2175 struct smb_com_ntransact_req * pSMB;
2176
2177 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2178 (void **)&pSMB);
2179 if (rc)
2180 return rc;
2181 *ret_buf = (void *)pSMB;
2182 pSMB->Reserved = 0;
2183 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2184 pSMB->TotalDataCount = 0;
2185 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2186 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2187 pSMB->ParameterCount = pSMB->TotalParameterCount;
2188 pSMB->DataCount = pSMB->TotalDataCount;
2189 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2190 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2191 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2192 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2193 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2194 pSMB->SubCommand = cpu_to_le16(sub_command);
2195 return 0;
2196}
2197
2198static int
2199validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2200 int * pdatalen, int * pparmlen)
2201{
2202 char * end_of_smb;
2203 __u32 data_count, data_offset, parm_count, parm_offset;
2204 struct smb_com_ntransact_rsp * pSMBr;
2205
2206 if(buf == NULL)
2207 return -EINVAL;
2208
2209 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2210
2211 /* ByteCount was converted from little endian in SendReceive */
2212 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2213 (char *)&pSMBr->ByteCount;
2214
2215
2216 data_offset = le32_to_cpu(pSMBr->DataOffset);
2217 data_count = le32_to_cpu(pSMBr->DataCount);
2218 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2219 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2220
2221 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2222 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2223
2224 /* should we also check that parm and data areas do not overlap? */
2225 if(*ppparm > end_of_smb) {
2226 cFYI(1,("parms start after end of smb"));
2227 return -EINVAL;
2228 } else if(parm_count + *ppparm > end_of_smb) {
2229 cFYI(1,("parm end after end of smb"));
2230 return -EINVAL;
2231 } else if(*ppdata > end_of_smb) {
2232 cFYI(1,("data starts after end of smb"));
2233 return -EINVAL;
2234 } else if(data_count + *ppdata > end_of_smb) {
2235 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2236 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2237 return -EINVAL;
2238 } else if(parm_count + data_count > pSMBr->ByteCount) {
2239 cFYI(1,("parm count and data count larger than SMB"));
2240 return -EINVAL;
2241 }
2242 return 0;
2243}
2244
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245int
2246CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2247 const unsigned char *searchName,
2248 char *symlinkinfo, const int buflen,__u16 fid,
2249 const struct nls_table *nls_codepage)
2250{
2251 int rc = 0;
2252 int bytes_returned;
2253 int name_len;
2254 struct smb_com_transaction_ioctl_req * pSMB;
2255 struct smb_com_transaction_ioctl_rsp * pSMBr;
2256
2257 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2258 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2259 (void **) &pSMBr);
2260 if (rc)
2261 return rc;
2262
2263 pSMB->TotalParameterCount = 0 ;
2264 pSMB->TotalDataCount = 0;
2265 pSMB->MaxParameterCount = cpu_to_le32(2);
2266 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002267 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2268 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 pSMB->MaxSetupCount = 4;
2270 pSMB->Reserved = 0;
2271 pSMB->ParameterOffset = 0;
2272 pSMB->DataCount = 0;
2273 pSMB->DataOffset = 0;
2274 pSMB->SetupCount = 4;
2275 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2276 pSMB->ParameterCount = pSMB->TotalParameterCount;
2277 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2278 pSMB->IsFsctl = 1; /* FSCTL */
2279 pSMB->IsRootFlag = 0;
2280 pSMB->Fid = fid; /* file handle always le */
2281 pSMB->ByteCount = 0;
2282
2283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2284 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2285 if (rc) {
2286 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2287 } else { /* decode response */
2288 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2289 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2290 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2291 /* BB also check enough total bytes returned */
2292 rc = -EIO; /* bad smb */
2293 else {
2294 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002295 char * end_of_smb = 2 /* sizeof byte count */ +
2296 pSMBr->ByteCount +
2297 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299 struct reparse_data * reparse_buf = (struct reparse_data *)
2300 ((char *)&pSMBr->hdr.Protocol + data_offset);
2301 if((char*)reparse_buf >= end_of_smb) {
2302 rc = -EIO;
2303 goto qreparse_out;
2304 }
2305 if((reparse_buf->LinkNamesBuf +
2306 reparse_buf->TargetNameOffset +
2307 reparse_buf->TargetNameLen) >
2308 end_of_smb) {
2309 cFYI(1,("reparse buf extended beyond SMB"));
2310 rc = -EIO;
2311 goto qreparse_out;
2312 }
2313
2314 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2315 name_len = UniStrnlen((wchar_t *)
2316 (reparse_buf->LinkNamesBuf +
2317 reparse_buf->TargetNameOffset),
2318 min(buflen/2, reparse_buf->TargetNameLen / 2));
2319 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002320 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 reparse_buf->TargetNameOffset),
2322 name_len, nls_codepage);
2323 } else { /* ASCII names */
2324 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2325 reparse_buf->TargetNameOffset,
2326 min_t(const int, buflen, reparse_buf->TargetNameLen));
2327 }
2328 } else {
2329 rc = -EIO;
2330 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2331 }
2332 symlinkinfo[buflen] = 0; /* just in case so the caller
2333 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002334 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
2336 }
2337qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002338 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339
2340 /* Note: On -EAGAIN error only caller can retry on handle based calls
2341 since file handle passed in no longer valid */
2342
2343 return rc;
2344}
2345
2346#ifdef CONFIG_CIFS_POSIX
2347
2348/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2349static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2350{
2351 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002352 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2353 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2354 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2356
2357 return;
2358}
2359
2360/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002361static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2362 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363{
2364 int size = 0;
2365 int i;
2366 __u16 count;
2367 struct cifs_posix_ace * pACE;
2368 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2369 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2370
2371 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2372 return -EOPNOTSUPP;
2373
2374 if(acl_type & ACL_TYPE_ACCESS) {
2375 count = le16_to_cpu(cifs_acl->access_entry_count);
2376 pACE = &cifs_acl->ace_array[0];
2377 size = sizeof(struct cifs_posix_acl);
2378 size += sizeof(struct cifs_posix_ace) * count;
2379 /* check if we would go beyond end of SMB */
2380 if(size_of_data_area < size) {
2381 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2382 return -EINVAL;
2383 }
2384 } else if(acl_type & ACL_TYPE_DEFAULT) {
2385 count = le16_to_cpu(cifs_acl->access_entry_count);
2386 size = sizeof(struct cifs_posix_acl);
2387 size += sizeof(struct cifs_posix_ace) * count;
2388/* skip past access ACEs to get to default ACEs */
2389 pACE = &cifs_acl->ace_array[count];
2390 count = le16_to_cpu(cifs_acl->default_entry_count);
2391 size += sizeof(struct cifs_posix_ace) * count;
2392 /* check if we would go beyond end of SMB */
2393 if(size_of_data_area < size)
2394 return -EINVAL;
2395 } else {
2396 /* illegal type */
2397 return -EINVAL;
2398 }
2399
2400 size = posix_acl_xattr_size(count);
2401 if((buflen == 0) || (local_acl == NULL)) {
2402 /* used to query ACL EA size */
2403 } else if(size > buflen) {
2404 return -ERANGE;
2405 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002406 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 for(i = 0;i < count ;i++) {
2408 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2409 pACE ++;
2410 }
2411 }
2412 return size;
2413}
2414
2415static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2416 const posix_acl_xattr_entry * local_ace)
2417{
2418 __u16 rc = 0; /* 0 = ACL converted ok */
2419
Steve Frenchff7feac2005-11-15 16:45:16 -08002420 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2421 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002423 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 /* Probably no need to le convert -1 on any arch but can not hurt */
2425 cifs_ace->cifs_uid = cpu_to_le64(-1);
2426 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002427 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2429 return rc;
2430}
2431
2432/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2433static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2434 const int acl_type)
2435{
2436 __u16 rc = 0;
2437 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2438 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2439 int count;
2440 int i;
2441
2442 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2443 return 0;
2444
2445 count = posix_acl_xattr_count((size_t)buflen);
2446 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002447 count, buflen, le32_to_cpu(local_acl->a_version)));
2448 if(le32_to_cpu(local_acl->a_version) != 2) {
2449 cFYI(1,("unknown POSIX ACL version %d",
2450 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 return 0;
2452 }
2453 cifs_acl->version = cpu_to_le16(1);
2454 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002455 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002457 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 else {
2459 cFYI(1,("unknown ACL type %d",acl_type));
2460 return 0;
2461 }
2462 for(i=0;i<count;i++) {
2463 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2464 &local_acl->a_entries[i]);
2465 if(rc != 0) {
2466 /* ACE not converted */
2467 break;
2468 }
2469 }
2470 if(rc == 0) {
2471 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2472 rc += sizeof(struct cifs_posix_acl);
2473 /* BB add check to make sure ACL does not overflow SMB */
2474 }
2475 return rc;
2476}
2477
2478int
2479CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2480 const unsigned char *searchName,
2481 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002482 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483{
2484/* SMB_QUERY_POSIX_ACL */
2485 TRANSACTION2_QPI_REQ *pSMB = NULL;
2486 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2487 int rc = 0;
2488 int bytes_returned;
2489 int name_len;
2490 __u16 params, byte_count;
2491
2492 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2493
2494queryAclRetry:
2495 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2496 (void **) &pSMBr);
2497 if (rc)
2498 return rc;
2499
2500 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2501 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002502 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002503 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 name_len++; /* trailing null */
2505 name_len *= 2;
2506 pSMB->FileName[name_len] = 0;
2507 pSMB->FileName[name_len+1] = 0;
2508 } else { /* BB improve the check for buffer overruns BB */
2509 name_len = strnlen(searchName, PATH_MAX);
2510 name_len++; /* trailing null */
2511 strncpy(pSMB->FileName, searchName, name_len);
2512 }
2513
2514 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2515 pSMB->TotalDataCount = 0;
2516 pSMB->MaxParameterCount = cpu_to_le16(2);
2517 /* BB find exact max data count below from sess structure BB */
2518 pSMB->MaxDataCount = cpu_to_le16(4000);
2519 pSMB->MaxSetupCount = 0;
2520 pSMB->Reserved = 0;
2521 pSMB->Flags = 0;
2522 pSMB->Timeout = 0;
2523 pSMB->Reserved2 = 0;
2524 pSMB->ParameterOffset = cpu_to_le16(
2525 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2526 pSMB->DataCount = 0;
2527 pSMB->DataOffset = 0;
2528 pSMB->SetupCount = 1;
2529 pSMB->Reserved3 = 0;
2530 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2531 byte_count = params + 1 /* pad */ ;
2532 pSMB->TotalParameterCount = cpu_to_le16(params);
2533 pSMB->ParameterCount = pSMB->TotalParameterCount;
2534 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2535 pSMB->Reserved4 = 0;
2536 pSMB->hdr.smb_buf_length += byte_count;
2537 pSMB->ByteCount = cpu_to_le16(byte_count);
2538
2539 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2540 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002541 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 if (rc) {
2543 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2544 } else {
2545 /* decode response */
2546
2547 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2548 if (rc || (pSMBr->ByteCount < 2))
2549 /* BB also check enough total bytes returned */
2550 rc = -EIO; /* bad smb */
2551 else {
2552 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2553 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2554 rc = cifs_copy_posix_acl(acl_inf,
2555 (char *)&pSMBr->hdr.Protocol+data_offset,
2556 buflen,acl_type,count);
2557 }
2558 }
2559 cifs_buf_release(pSMB);
2560 if (rc == -EAGAIN)
2561 goto queryAclRetry;
2562 return rc;
2563}
2564
2565int
2566CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2567 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002568 const char *local_acl, const int buflen,
2569 const int acl_type,
2570 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571{
2572 struct smb_com_transaction2_spi_req *pSMB = NULL;
2573 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2574 char *parm_data;
2575 int name_len;
2576 int rc = 0;
2577 int bytes_returned = 0;
2578 __u16 params, byte_count, data_count, param_offset, offset;
2579
2580 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2581setAclRetry:
2582 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2583 (void **) &pSMBr);
2584 if (rc)
2585 return rc;
2586 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2587 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002588 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002589 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 name_len++; /* trailing null */
2591 name_len *= 2;
2592 } else { /* BB improve the check for buffer overruns BB */
2593 name_len = strnlen(fileName, PATH_MAX);
2594 name_len++; /* trailing null */
2595 strncpy(pSMB->FileName, fileName, name_len);
2596 }
2597 params = 6 + name_len;
2598 pSMB->MaxParameterCount = cpu_to_le16(2);
2599 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2600 pSMB->MaxSetupCount = 0;
2601 pSMB->Reserved = 0;
2602 pSMB->Flags = 0;
2603 pSMB->Timeout = 0;
2604 pSMB->Reserved2 = 0;
2605 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2606 InformationLevel) - 4;
2607 offset = param_offset + params;
2608 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2609 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2610
2611 /* convert to on the wire format for POSIX ACL */
2612 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2613
2614 if(data_count == 0) {
2615 rc = -EOPNOTSUPP;
2616 goto setACLerrorExit;
2617 }
2618 pSMB->DataOffset = cpu_to_le16(offset);
2619 pSMB->SetupCount = 1;
2620 pSMB->Reserved3 = 0;
2621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2622 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2623 byte_count = 3 /* pad */ + params + data_count;
2624 pSMB->DataCount = cpu_to_le16(data_count);
2625 pSMB->TotalDataCount = pSMB->DataCount;
2626 pSMB->ParameterCount = cpu_to_le16(params);
2627 pSMB->TotalParameterCount = pSMB->ParameterCount;
2628 pSMB->Reserved4 = 0;
2629 pSMB->hdr.smb_buf_length += byte_count;
2630 pSMB->ByteCount = cpu_to_le16(byte_count);
2631 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2632 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2633 if (rc) {
2634 cFYI(1, ("Set POSIX ACL returned %d", rc));
2635 }
2636
2637setACLerrorExit:
2638 cifs_buf_release(pSMB);
2639 if (rc == -EAGAIN)
2640 goto setAclRetry;
2641 return rc;
2642}
2643
Steve Frenchf654bac2005-04-28 22:41:04 -07002644/* BB fix tabs in this function FIXME BB */
2645int
2646CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2647 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2648{
2649 int rc = 0;
2650 struct smb_t2_qfi_req *pSMB = NULL;
2651 struct smb_t2_qfi_rsp *pSMBr = NULL;
2652 int bytes_returned;
2653 __u16 params, byte_count;
2654
2655 cFYI(1,("In GetExtAttr"));
2656 if(tcon == NULL)
2657 return -ENODEV;
2658
2659GetExtAttrRetry:
2660 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2661 (void **) &pSMBr);
2662 if (rc)
2663 return rc;
2664
Steve Frenchc67593a2005-04-28 22:41:04 -07002665 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002666 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002667 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002668 /* BB find exact max data count below from sess structure BB */
2669 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2670 pSMB->t2.MaxSetupCount = 0;
2671 pSMB->t2.Reserved = 0;
2672 pSMB->t2.Flags = 0;
2673 pSMB->t2.Timeout = 0;
2674 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002675 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2676 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002677 pSMB->t2.DataCount = 0;
2678 pSMB->t2.DataOffset = 0;
2679 pSMB->t2.SetupCount = 1;
2680 pSMB->t2.Reserved3 = 0;
2681 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002682 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002683 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2684 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2685 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002686 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002687 pSMB->Fid = netfid;
2688 pSMB->hdr.smb_buf_length += byte_count;
2689 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2690
2691 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2692 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2693 if (rc) {
2694 cFYI(1, ("error %d in GetExtAttr", rc));
2695 } else {
2696 /* decode response */
2697 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2698 if (rc || (pSMBr->ByteCount < 2))
2699 /* BB also check enough total bytes returned */
2700 /* If rc should we check for EOPNOSUPP and
2701 disable the srvino flag? or in caller? */
2702 rc = -EIO; /* bad smb */
2703 else {
2704 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2705 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2706 struct file_chattr_info * pfinfo;
2707 /* BB Do we need a cast or hash here ? */
2708 if(count != 16) {
2709 cFYI(1, ("Illegal size ret in GetExtAttr"));
2710 rc = -EIO;
2711 goto GetExtAttrOut;
2712 }
2713 pfinfo = (struct file_chattr_info *)
2714 (data_offset + (char *) &pSMBr->hdr.Protocol);
2715 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2716 *pMask = le64_to_cpu(pfinfo->mask);
2717 }
2718 }
2719GetExtAttrOut:
2720 cifs_buf_release(pSMB);
2721 if (rc == -EAGAIN)
2722 goto GetExtAttrRetry;
2723 return rc;
2724}
2725
2726
2727#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
Steve Frencheeac8042006-01-13 21:34:58 -08002729
2730/* security id for everyone */
2731const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2732/* group users */
2733const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2734
Steve French0a4b92c2006-01-12 15:44:21 -08002735/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002736static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002737{
Steve French0a4b92c2006-01-12 15:44:21 -08002738 return 0;
2739}
2740
2741/* Get Security Descriptor (by handle) from remote server for a file or dir */
2742int
2743CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2744 /* BB fix up return info */ char *acl_inf, const int buflen,
2745 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2746{
2747 int rc = 0;
2748 int buf_type = 0;
2749 QUERY_SEC_DESC_REQ * pSMB;
2750 struct kvec iov[1];
2751
2752 cFYI(1, ("GetCifsACL"));
2753
2754 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2755 8 /* parm len */, tcon, (void **) &pSMB);
2756 if (rc)
2757 return rc;
2758
2759 pSMB->MaxParameterCount = cpu_to_le32(4);
2760 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2761 pSMB->MaxSetupCount = 0;
2762 pSMB->Fid = fid; /* file handle always le */
2763 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2764 CIFS_ACL_DACL);
2765 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2766 pSMB->hdr.smb_buf_length += 11;
2767 iov[0].iov_base = (char *)pSMB;
2768 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2769
2770 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2771 cifs_stats_inc(&tcon->num_acl_get);
2772 if (rc) {
2773 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2774 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002775 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002776 __le32 * parm;
2777 int parm_len;
2778 int data_len;
2779 int acl_len;
2780 struct smb_com_ntransact_rsp * pSMBr;
2781
2782/* validate_nttransact */
2783 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2784 (char **)&psec_desc,
2785 &parm_len, &data_len);
2786
2787 if(rc)
2788 goto qsec_out;
2789 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2790
2791 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2792
2793 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2794 rc = -EIO; /* bad smb */
2795 goto qsec_out;
2796 }
2797
2798/* BB check that data area is minimum length and as big as acl_len */
2799
2800 acl_len = le32_to_cpu(*(__le32 *)parm);
2801 /* BB check if(acl_len > bufsize) */
2802
2803 parse_sec_desc(psec_desc, acl_len);
2804 }
2805qsec_out:
2806 if(buf_type == CIFS_SMALL_BUFFER)
2807 cifs_small_buf_release(iov[0].iov_base);
2808 else if(buf_type == CIFS_LARGE_BUFFER)
2809 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002810/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002811 return rc;
2812}
2813
2814
Steve French6b8edfe2005-08-23 20:26:03 -07002815/* Legacy Query Path Information call for lookup to old servers such
2816 as Win9x/WinME */
2817int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2818 const unsigned char *searchName,
2819 FILE_ALL_INFO * pFinfo,
2820 const struct nls_table *nls_codepage, int remap)
2821{
2822 QUERY_INFORMATION_REQ * pSMB;
2823 QUERY_INFORMATION_RSP * pSMBr;
2824 int rc = 0;
2825 int bytes_returned;
2826 int name_len;
2827
2828 cFYI(1, ("In SMBQPath path %s", searchName));
2829QInfRetry:
2830 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2831 (void **) &pSMBr);
2832 if (rc)
2833 return rc;
2834
2835 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2836 name_len =
2837 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2838 PATH_MAX, nls_codepage, remap);
2839 name_len++; /* trailing null */
2840 name_len *= 2;
2841 } else {
2842 name_len = strnlen(searchName, PATH_MAX);
2843 name_len++; /* trailing null */
2844 strncpy(pSMB->FileName, searchName, name_len);
2845 }
2846 pSMB->BufferFormat = 0x04;
2847 name_len++; /* account for buffer type byte */
2848 pSMB->hdr.smb_buf_length += (__u16) name_len;
2849 pSMB->ByteCount = cpu_to_le16(name_len);
2850
2851 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2852 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2853 if (rc) {
2854 cFYI(1, ("Send error in QueryInfo = %d", rc));
2855 } else if (pFinfo) { /* decode response */
2856 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002857 pFinfo->AllocationSize =
2858 cpu_to_le64(le32_to_cpu(pSMBr->size));
2859 pFinfo->EndOfFile = pFinfo->AllocationSize;
2860 pFinfo->Attributes =
2861 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002862 } else
2863 rc = -EIO; /* bad buffer passed in */
2864
2865 cifs_buf_release(pSMB);
2866
2867 if (rc == -EAGAIN)
2868 goto QInfRetry;
2869
2870 return rc;
2871}
2872
2873
2874
2875
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876int
2877CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2878 const unsigned char *searchName,
2879 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002880 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881{
2882/* level 263 SMB_QUERY_FILE_ALL_INFO */
2883 TRANSACTION2_QPI_REQ *pSMB = NULL;
2884 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2885 int rc = 0;
2886 int bytes_returned;
2887 int name_len;
2888 __u16 params, byte_count;
2889
2890/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2891QPathInfoRetry:
2892 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2893 (void **) &pSMBr);
2894 if (rc)
2895 return rc;
2896
2897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2898 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002899 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002900 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 name_len++; /* trailing null */
2902 name_len *= 2;
2903 } else { /* BB improve the check for buffer overruns BB */
2904 name_len = strnlen(searchName, PATH_MAX);
2905 name_len++; /* trailing null */
2906 strncpy(pSMB->FileName, searchName, name_len);
2907 }
2908
2909 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2910 pSMB->TotalDataCount = 0;
2911 pSMB->MaxParameterCount = cpu_to_le16(2);
2912 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2913 pSMB->MaxSetupCount = 0;
2914 pSMB->Reserved = 0;
2915 pSMB->Flags = 0;
2916 pSMB->Timeout = 0;
2917 pSMB->Reserved2 = 0;
2918 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2919 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2920 pSMB->DataCount = 0;
2921 pSMB->DataOffset = 0;
2922 pSMB->SetupCount = 1;
2923 pSMB->Reserved3 = 0;
2924 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2925 byte_count = params + 1 /* pad */ ;
2926 pSMB->TotalParameterCount = cpu_to_le16(params);
2927 pSMB->ParameterCount = pSMB->TotalParameterCount;
2928 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2929 pSMB->Reserved4 = 0;
2930 pSMB->hdr.smb_buf_length += byte_count;
2931 pSMB->ByteCount = cpu_to_le16(byte_count);
2932
2933 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2934 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2935 if (rc) {
2936 cFYI(1, ("Send error in QPathInfo = %d", rc));
2937 } else { /* decode response */
2938 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2939
2940 if (rc || (pSMBr->ByteCount < 40))
2941 rc = -EIO; /* bad smb */
2942 else if (pFindData){
2943 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2944 memcpy((char *) pFindData,
2945 (char *) &pSMBr->hdr.Protocol +
2946 data_offset, sizeof (FILE_ALL_INFO));
2947 } else
2948 rc = -ENOMEM;
2949 }
2950 cifs_buf_release(pSMB);
2951 if (rc == -EAGAIN)
2952 goto QPathInfoRetry;
2953
2954 return rc;
2955}
2956
2957int
2958CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2959 const unsigned char *searchName,
2960 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002961 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962{
2963/* SMB_QUERY_FILE_UNIX_BASIC */
2964 TRANSACTION2_QPI_REQ *pSMB = NULL;
2965 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2966 int rc = 0;
2967 int bytes_returned = 0;
2968 int name_len;
2969 __u16 params, byte_count;
2970
2971 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2972UnixQPathInfoRetry:
2973 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2974 (void **) &pSMBr);
2975 if (rc)
2976 return rc;
2977
2978 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2979 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002980 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002981 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 name_len++; /* trailing null */
2983 name_len *= 2;
2984 } else { /* BB improve the check for buffer overruns BB */
2985 name_len = strnlen(searchName, PATH_MAX);
2986 name_len++; /* trailing null */
2987 strncpy(pSMB->FileName, searchName, name_len);
2988 }
2989
2990 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2991 pSMB->TotalDataCount = 0;
2992 pSMB->MaxParameterCount = cpu_to_le16(2);
2993 /* BB find exact max SMB PDU from sess structure BB */
2994 pSMB->MaxDataCount = cpu_to_le16(4000);
2995 pSMB->MaxSetupCount = 0;
2996 pSMB->Reserved = 0;
2997 pSMB->Flags = 0;
2998 pSMB->Timeout = 0;
2999 pSMB->Reserved2 = 0;
3000 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3001 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3002 pSMB->DataCount = 0;
3003 pSMB->DataOffset = 0;
3004 pSMB->SetupCount = 1;
3005 pSMB->Reserved3 = 0;
3006 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3007 byte_count = params + 1 /* pad */ ;
3008 pSMB->TotalParameterCount = cpu_to_le16(params);
3009 pSMB->ParameterCount = pSMB->TotalParameterCount;
3010 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3011 pSMB->Reserved4 = 0;
3012 pSMB->hdr.smb_buf_length += byte_count;
3013 pSMB->ByteCount = cpu_to_le16(byte_count);
3014
3015 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3016 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3017 if (rc) {
3018 cFYI(1, ("Send error in QPathInfo = %d", rc));
3019 } else { /* decode response */
3020 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3021
3022 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3023 rc = -EIO; /* bad smb */
3024 } else {
3025 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3026 memcpy((char *) pFindData,
3027 (char *) &pSMBr->hdr.Protocol +
3028 data_offset,
3029 sizeof (FILE_UNIX_BASIC_INFO));
3030 }
3031 }
3032 cifs_buf_release(pSMB);
3033 if (rc == -EAGAIN)
3034 goto UnixQPathInfoRetry;
3035
3036 return rc;
3037}
3038
3039#if 0 /* function unused at present */
3040int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3041 const char *searchName, FILE_ALL_INFO * findData,
3042 const struct nls_table *nls_codepage)
3043{
3044/* level 257 SMB_ */
3045 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3046 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3047 int rc = 0;
3048 int bytes_returned;
3049 int name_len;
3050 __u16 params, byte_count;
3051
3052 cFYI(1, ("In FindUnique"));
3053findUniqueRetry:
3054 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3055 (void **) &pSMBr);
3056 if (rc)
3057 return rc;
3058
3059 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3060 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003061 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 /* find define for this maxpathcomponent */
3063 , nls_codepage);
3064 name_len++; /* trailing null */
3065 name_len *= 2;
3066 } else { /* BB improve the check for buffer overruns BB */
3067 name_len = strnlen(searchName, PATH_MAX);
3068 name_len++; /* trailing null */
3069 strncpy(pSMB->FileName, searchName, name_len);
3070 }
3071
3072 params = 12 + name_len /* includes null */ ;
3073 pSMB->TotalDataCount = 0; /* no EAs */
3074 pSMB->MaxParameterCount = cpu_to_le16(2);
3075 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3076 pSMB->MaxSetupCount = 0;
3077 pSMB->Reserved = 0;
3078 pSMB->Flags = 0;
3079 pSMB->Timeout = 0;
3080 pSMB->Reserved2 = 0;
3081 pSMB->ParameterOffset = cpu_to_le16(
3082 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3083 pSMB->DataCount = 0;
3084 pSMB->DataOffset = 0;
3085 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3086 pSMB->Reserved3 = 0;
3087 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3088 byte_count = params + 1 /* pad */ ;
3089 pSMB->TotalParameterCount = cpu_to_le16(params);
3090 pSMB->ParameterCount = pSMB->TotalParameterCount;
3091 pSMB->SearchAttributes =
3092 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3093 ATTR_DIRECTORY);
3094 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3095 pSMB->SearchFlags = cpu_to_le16(1);
3096 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3097 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3098 pSMB->hdr.smb_buf_length += byte_count;
3099 pSMB->ByteCount = cpu_to_le16(byte_count);
3100
3101 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3102 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3103
3104 if (rc) {
3105 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3106 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003107 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 /* BB fill in */
3109 }
3110
3111 cifs_buf_release(pSMB);
3112 if (rc == -EAGAIN)
3113 goto findUniqueRetry;
3114
3115 return rc;
3116}
3117#endif /* end unused (temporarily) function */
3118
3119/* xid, tcon, searchName and codepage are input parms, rest are returned */
3120int
3121CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3122 const char *searchName,
3123 const struct nls_table *nls_codepage,
3124 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003125 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126{
3127/* level 257 SMB_ */
3128 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3129 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3130 T2_FFIRST_RSP_PARMS * parms;
3131 int rc = 0;
3132 int bytes_returned = 0;
3133 int name_len;
3134 __u16 params, byte_count;
3135
Steve French737b7582005-04-28 22:41:06 -07003136 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137
3138findFirstRetry:
3139 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3140 (void **) &pSMBr);
3141 if (rc)
3142 return rc;
3143
3144 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3145 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003146 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003147 PATH_MAX, nls_codepage, remap);
3148 /* We can not add the asterik earlier in case
3149 it got remapped to 0xF03A as if it were part of the
3150 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003152 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003153 pSMB->FileName[name_len+1] = 0;
3154 pSMB->FileName[name_len+2] = '*';
3155 pSMB->FileName[name_len+3] = 0;
3156 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3158 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003159 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 } else { /* BB add check for overrun of SMB buf BB */
3161 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162/* BB fix here and in unicode clause above ie
3163 if(name_len > buffersize-header)
3164 free buffer exit; BB */
3165 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003166 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003167 pSMB->FileName[name_len+1] = '*';
3168 pSMB->FileName[name_len+2] = 0;
3169 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 }
3171
3172 params = 12 + name_len /* includes null */ ;
3173 pSMB->TotalDataCount = 0; /* no EAs */
3174 pSMB->MaxParameterCount = cpu_to_le16(10);
3175 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3176 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3177 pSMB->MaxSetupCount = 0;
3178 pSMB->Reserved = 0;
3179 pSMB->Flags = 0;
3180 pSMB->Timeout = 0;
3181 pSMB->Reserved2 = 0;
3182 byte_count = params + 1 /* pad */ ;
3183 pSMB->TotalParameterCount = cpu_to_le16(params);
3184 pSMB->ParameterCount = pSMB->TotalParameterCount;
3185 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003186 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3187 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 pSMB->DataCount = 0;
3189 pSMB->DataOffset = 0;
3190 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3191 pSMB->Reserved3 = 0;
3192 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3193 pSMB->SearchAttributes =
3194 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3195 ATTR_DIRECTORY);
3196 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3197 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3198 CIFS_SEARCH_RETURN_RESUME);
3199 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3200
3201 /* BB what should we set StorageType to? Does it matter? BB */
3202 pSMB->SearchStorageType = 0;
3203 pSMB->hdr.smb_buf_length += byte_count;
3204 pSMB->ByteCount = cpu_to_le16(byte_count);
3205
3206 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3207 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003208 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
Steve French88274812006-03-09 22:21:45 +00003210 if (rc) {/* BB add logic to retry regular search if Unix search
3211 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 /* BB Add code to handle unsupported level rc */
3213 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003214
Steve French88274812006-03-09 22:21:45 +00003215 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216
3217 /* BB eventually could optimize out free and realloc of buf */
3218 /* for this case */
3219 if (rc == -EAGAIN)
3220 goto findFirstRetry;
3221 } else { /* decode response */
3222 /* BB remember to free buffer if error BB */
3223 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3224 if(rc == 0) {
3225 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3226 psrch_inf->unicode = TRUE;
3227 else
3228 psrch_inf->unicode = FALSE;
3229
3230 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003231 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 psrch_inf->srch_entries_start =
3233 (char *) &pSMBr->hdr.Protocol +
3234 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3236 le16_to_cpu(pSMBr->t2.ParameterOffset));
3237
3238 if(parms->EndofSearch)
3239 psrch_inf->endOfSearch = TRUE;
3240 else
3241 psrch_inf->endOfSearch = FALSE;
3242
3243 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003244 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 *pnetfid = parms->SearchHandle;
3247 } else {
3248 cifs_buf_release(pSMB);
3249 }
3250 }
3251
3252 return rc;
3253}
3254
3255int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3256 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3257{
3258 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3259 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3260 T2_FNEXT_RSP_PARMS * parms;
3261 char *response_data;
3262 int rc = 0;
3263 int bytes_returned, name_len;
3264 __u16 params, byte_count;
3265
3266 cFYI(1, ("In FindNext"));
3267
3268 if(psrch_inf->endOfSearch == TRUE)
3269 return -ENOENT;
3270
3271 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3272 (void **) &pSMBr);
3273 if (rc)
3274 return rc;
3275
3276 params = 14; /* includes 2 bytes of null string, converted to LE below */
3277 byte_count = 0;
3278 pSMB->TotalDataCount = 0; /* no EAs */
3279 pSMB->MaxParameterCount = cpu_to_le16(8);
3280 pSMB->MaxDataCount =
3281 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3282 pSMB->MaxSetupCount = 0;
3283 pSMB->Reserved = 0;
3284 pSMB->Flags = 0;
3285 pSMB->Timeout = 0;
3286 pSMB->Reserved2 = 0;
3287 pSMB->ParameterOffset = cpu_to_le16(
3288 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3289 pSMB->DataCount = 0;
3290 pSMB->DataOffset = 0;
3291 pSMB->SetupCount = 1;
3292 pSMB->Reserved3 = 0;
3293 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3294 pSMB->SearchHandle = searchHandle; /* always kept as le */
3295 pSMB->SearchCount =
3296 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3297 /* test for Unix extensions */
3298/* if (tcon->ses->capabilities & CAP_UNIX) {
3299 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3300 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3301 } else {
3302 pSMB->InformationLevel =
3303 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3304 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3305 } */
3306 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3307 pSMB->ResumeKey = psrch_inf->resume_key;
3308 pSMB->SearchFlags =
3309 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3310
3311 name_len = psrch_inf->resume_name_len;
3312 params += name_len;
3313 if(name_len < PATH_MAX) {
3314 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3315 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003316 /* 14 byte parm len above enough for 2 byte null terminator */
3317 pSMB->ResumeFileName[name_len] = 0;
3318 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 } else {
3320 rc = -EINVAL;
3321 goto FNext2_err_exit;
3322 }
3323 byte_count = params + 1 /* pad */ ;
3324 pSMB->TotalParameterCount = cpu_to_le16(params);
3325 pSMB->ParameterCount = pSMB->TotalParameterCount;
3326 pSMB->hdr.smb_buf_length += byte_count;
3327 pSMB->ByteCount = cpu_to_le16(byte_count);
3328
3329 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3330 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003331 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 if (rc) {
3333 if (rc == -EBADF) {
3334 psrch_inf->endOfSearch = TRUE;
3335 rc = 0; /* search probably was closed at end of search above */
3336 } else
3337 cFYI(1, ("FindNext returned = %d", rc));
3338 } else { /* decode response */
3339 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3340
3341 if(rc == 0) {
3342 /* BB fixme add lock for file (srch_info) struct here */
3343 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3344 psrch_inf->unicode = TRUE;
3345 else
3346 psrch_inf->unicode = FALSE;
3347 response_data = (char *) &pSMBr->hdr.Protocol +
3348 le16_to_cpu(pSMBr->t2.ParameterOffset);
3349 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3350 response_data = (char *)&pSMBr->hdr.Protocol +
3351 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003352 if(psrch_inf->smallBuf)
3353 cifs_small_buf_release(
3354 psrch_inf->ntwrk_buf_start);
3355 else
3356 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 psrch_inf->srch_entries_start = response_data;
3358 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003359 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 if(parms->EndofSearch)
3361 psrch_inf->endOfSearch = TRUE;
3362 else
3363 psrch_inf->endOfSearch = FALSE;
3364
3365 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3366 psrch_inf->index_of_last_entry +=
3367 psrch_inf->entries_in_buffer;
3368/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3369
3370 /* BB fixme add unlock here */
3371 }
3372
3373 }
3374
3375 /* BB On error, should we leave previous search buf (and count and
3376 last entry fields) intact or free the previous one? */
3377
3378 /* Note: On -EAGAIN error only caller can retry on handle based calls
3379 since file handle passed in no longer valid */
3380FNext2_err_exit:
3381 if (rc != 0)
3382 cifs_buf_release(pSMB);
3383
3384 return rc;
3385}
3386
3387int
3388CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3389{
3390 int rc = 0;
3391 FINDCLOSE_REQ *pSMB = NULL;
3392 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3393 int bytes_returned;
3394
3395 cFYI(1, ("In CIFSSMBFindClose"));
3396 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3397
3398 /* no sense returning error if session restarted
3399 as file handle has been closed */
3400 if(rc == -EAGAIN)
3401 return 0;
3402 if (rc)
3403 return rc;
3404
3405 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3406 pSMB->FileID = searchHandle;
3407 pSMB->ByteCount = 0;
3408 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3409 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3410 if (rc) {
3411 cERROR(1, ("Send error in FindClose = %d", rc));
3412 }
Steve Frencha4544342005-08-24 13:59:35 -07003413 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 cifs_small_buf_release(pSMB);
3415
3416 /* Since session is dead, search handle closed on server already */
3417 if (rc == -EAGAIN)
3418 rc = 0;
3419
3420 return rc;
3421}
3422
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423int
3424CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3425 const unsigned char *searchName,
3426 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003427 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428{
3429 int rc = 0;
3430 TRANSACTION2_QPI_REQ *pSMB = NULL;
3431 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3432 int name_len, bytes_returned;
3433 __u16 params, byte_count;
3434
3435 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3436 if(tcon == NULL)
3437 return -ENODEV;
3438
3439GetInodeNumberRetry:
3440 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3441 (void **) &pSMBr);
3442 if (rc)
3443 return rc;
3444
3445
3446 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3447 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003448 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003449 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 name_len++; /* trailing null */
3451 name_len *= 2;
3452 } else { /* BB improve the check for buffer overruns BB */
3453 name_len = strnlen(searchName, PATH_MAX);
3454 name_len++; /* trailing null */
3455 strncpy(pSMB->FileName, searchName, name_len);
3456 }
3457
3458 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3459 pSMB->TotalDataCount = 0;
3460 pSMB->MaxParameterCount = cpu_to_le16(2);
3461 /* BB find exact max data count below from sess structure BB */
3462 pSMB->MaxDataCount = cpu_to_le16(4000);
3463 pSMB->MaxSetupCount = 0;
3464 pSMB->Reserved = 0;
3465 pSMB->Flags = 0;
3466 pSMB->Timeout = 0;
3467 pSMB->Reserved2 = 0;
3468 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3469 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3470 pSMB->DataCount = 0;
3471 pSMB->DataOffset = 0;
3472 pSMB->SetupCount = 1;
3473 pSMB->Reserved3 = 0;
3474 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3475 byte_count = params + 1 /* pad */ ;
3476 pSMB->TotalParameterCount = cpu_to_le16(params);
3477 pSMB->ParameterCount = pSMB->TotalParameterCount;
3478 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3479 pSMB->Reserved4 = 0;
3480 pSMB->hdr.smb_buf_length += byte_count;
3481 pSMB->ByteCount = cpu_to_le16(byte_count);
3482
3483 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3484 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3485 if (rc) {
3486 cFYI(1, ("error %d in QueryInternalInfo", rc));
3487 } else {
3488 /* decode response */
3489 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3490 if (rc || (pSMBr->ByteCount < 2))
3491 /* BB also check enough total bytes returned */
3492 /* If rc should we check for EOPNOSUPP and
3493 disable the srvino flag? or in caller? */
3494 rc = -EIO; /* bad smb */
3495 else {
3496 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3497 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3498 struct file_internal_info * pfinfo;
3499 /* BB Do we need a cast or hash here ? */
3500 if(count < 8) {
3501 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3502 rc = -EIO;
3503 goto GetInodeNumOut;
3504 }
3505 pfinfo = (struct file_internal_info *)
3506 (data_offset + (char *) &pSMBr->hdr.Protocol);
3507 *inode_number = pfinfo->UniqueId;
3508 }
3509 }
3510GetInodeNumOut:
3511 cifs_buf_release(pSMB);
3512 if (rc == -EAGAIN)
3513 goto GetInodeNumberRetry;
3514 return rc;
3515}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516
3517int
3518CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3519 const unsigned char *searchName,
3520 unsigned char **targetUNCs,
3521 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003522 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523{
3524/* TRANS2_GET_DFS_REFERRAL */
3525 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3526 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3527 struct dfs_referral_level_3 * referrals = NULL;
3528 int rc = 0;
3529 int bytes_returned;
3530 int name_len;
3531 unsigned int i;
3532 char * temp;
3533 __u16 params, byte_count;
3534 *number_of_UNC_in_array = 0;
3535 *targetUNCs = NULL;
3536
3537 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3538 if (ses == NULL)
3539 return -ENODEV;
3540getDFSRetry:
3541 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3542 (void **) &pSMBr);
3543 if (rc)
3544 return rc;
Steve French1982c342005-08-17 12:38:22 -07003545
3546 /* server pointer checked in called function,
3547 but should never be null here anyway */
3548 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 pSMB->hdr.Tid = ses->ipc_tid;
3550 pSMB->hdr.Uid = ses->Suid;
3551 if (ses->capabilities & CAP_STATUS32) {
3552 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3553 }
3554 if (ses->capabilities & CAP_DFS) {
3555 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3556 }
3557
3558 if (ses->capabilities & CAP_UNICODE) {
3559 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3560 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003561 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003562 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 name_len++; /* trailing null */
3564 name_len *= 2;
3565 } else { /* BB improve the check for buffer overruns BB */
3566 name_len = strnlen(searchName, PATH_MAX);
3567 name_len++; /* trailing null */
3568 strncpy(pSMB->RequestFileName, searchName, name_len);
3569 }
3570
3571 params = 2 /* level */ + name_len /*includes null */ ;
3572 pSMB->TotalDataCount = 0;
3573 pSMB->DataCount = 0;
3574 pSMB->DataOffset = 0;
3575 pSMB->MaxParameterCount = 0;
3576 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3577 pSMB->MaxSetupCount = 0;
3578 pSMB->Reserved = 0;
3579 pSMB->Flags = 0;
3580 pSMB->Timeout = 0;
3581 pSMB->Reserved2 = 0;
3582 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3583 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3584 pSMB->SetupCount = 1;
3585 pSMB->Reserved3 = 0;
3586 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3587 byte_count = params + 3 /* pad */ ;
3588 pSMB->ParameterCount = cpu_to_le16(params);
3589 pSMB->TotalParameterCount = pSMB->ParameterCount;
3590 pSMB->MaxReferralLevel = cpu_to_le16(3);
3591 pSMB->hdr.smb_buf_length += byte_count;
3592 pSMB->ByteCount = cpu_to_le16(byte_count);
3593
3594 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3595 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3596 if (rc) {
3597 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3598 } else { /* decode response */
3599/* BB Add logic to parse referrals here */
3600 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3601
3602 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3603 rc = -EIO; /* bad smb */
3604 else {
3605 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3606 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3607
3608 cFYI(1,
3609 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3610 pSMBr->ByteCount, data_offset));
3611 referrals =
3612 (struct dfs_referral_level_3 *)
3613 (8 /* sizeof start of data block */ +
3614 data_offset +
3615 (char *) &pSMBr->hdr.Protocol);
3616 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",
3617 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)));
3618 /* BB This field is actually two bytes in from start of
3619 data block so we could do safety check that DataBlock
3620 begins at address of pSMBr->NumberOfReferrals */
3621 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3622
3623 /* BB Fix below so can return more than one referral */
3624 if(*number_of_UNC_in_array > 1)
3625 *number_of_UNC_in_array = 1;
3626
3627 /* get the length of the strings describing refs */
3628 name_len = 0;
3629 for(i=0;i<*number_of_UNC_in_array;i++) {
3630 /* make sure that DfsPathOffset not past end */
3631 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3632 if (offset > data_count) {
3633 /* if invalid referral, stop here and do
3634 not try to copy any more */
3635 *number_of_UNC_in_array = i;
3636 break;
3637 }
3638 temp = ((char *)referrals) + offset;
3639
3640 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3641 name_len += UniStrnlen((wchar_t *)temp,data_count);
3642 } else {
3643 name_len += strnlen(temp,data_count);
3644 }
3645 referrals++;
3646 /* BB add check that referral pointer does not fall off end PDU */
3647
3648 }
3649 /* BB add check for name_len bigger than bcc */
3650 *targetUNCs =
3651 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3652 if(*targetUNCs == NULL) {
3653 rc = -ENOMEM;
3654 goto GetDFSRefExit;
3655 }
3656 /* copy the ref strings */
3657 referrals =
3658 (struct dfs_referral_level_3 *)
3659 (8 /* sizeof data hdr */ +
3660 data_offset +
3661 (char *) &pSMBr->hdr.Protocol);
3662
3663 for(i=0;i<*number_of_UNC_in_array;i++) {
3664 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3665 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3666 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003667 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 } else {
3669 strncpy(*targetUNCs,temp,name_len);
3670 }
3671 /* BB update target_uncs pointers */
3672 referrals++;
3673 }
3674 temp = *targetUNCs;
3675 temp[name_len] = 0;
3676 }
3677
3678 }
3679GetDFSRefExit:
3680 if (pSMB)
3681 cifs_buf_release(pSMB);
3682
3683 if (rc == -EAGAIN)
3684 goto getDFSRetry;
3685
3686 return rc;
3687}
3688
Steve French20962432005-09-21 22:05:57 -07003689/* Query File System Info such as free space to old servers such as Win 9x */
3690int
3691SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3692{
3693/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3694 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3695 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3696 FILE_SYSTEM_ALLOC_INFO *response_data;
3697 int rc = 0;
3698 int bytes_returned = 0;
3699 __u16 params, byte_count;
3700
3701 cFYI(1, ("OldQFSInfo"));
3702oldQFSInfoRetry:
3703 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3704 (void **) &pSMBr);
3705 if (rc)
3706 return rc;
3707 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3708 (void **) &pSMBr);
3709 if (rc)
3710 return rc;
3711
3712 params = 2; /* level */
3713 pSMB->TotalDataCount = 0;
3714 pSMB->MaxParameterCount = cpu_to_le16(2);
3715 pSMB->MaxDataCount = cpu_to_le16(1000);
3716 pSMB->MaxSetupCount = 0;
3717 pSMB->Reserved = 0;
3718 pSMB->Flags = 0;
3719 pSMB->Timeout = 0;
3720 pSMB->Reserved2 = 0;
3721 byte_count = params + 1 /* pad */ ;
3722 pSMB->TotalParameterCount = cpu_to_le16(params);
3723 pSMB->ParameterCount = pSMB->TotalParameterCount;
3724 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3725 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3726 pSMB->DataCount = 0;
3727 pSMB->DataOffset = 0;
3728 pSMB->SetupCount = 1;
3729 pSMB->Reserved3 = 0;
3730 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3731 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3732 pSMB->hdr.smb_buf_length += byte_count;
3733 pSMB->ByteCount = cpu_to_le16(byte_count);
3734
3735 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3736 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3737 if (rc) {
3738 cFYI(1, ("Send error in QFSInfo = %d", rc));
3739 } else { /* decode response */
3740 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3741
3742 if (rc || (pSMBr->ByteCount < 18))
3743 rc = -EIO; /* bad smb */
3744 else {
3745 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3746 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3747 pSMBr->ByteCount, data_offset));
3748
3749 response_data =
3750 (FILE_SYSTEM_ALLOC_INFO *)
3751 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3752 FSData->f_bsize =
3753 le16_to_cpu(response_data->BytesPerSector) *
3754 le32_to_cpu(response_data->
3755 SectorsPerAllocationUnit);
3756 FSData->f_blocks =
3757 le32_to_cpu(response_data->TotalAllocationUnits);
3758 FSData->f_bfree = FSData->f_bavail =
3759 le32_to_cpu(response_data->FreeAllocationUnits);
3760 cFYI(1,
3761 ("Blocks: %lld Free: %lld Block size %ld",
3762 (unsigned long long)FSData->f_blocks,
3763 (unsigned long long)FSData->f_bfree,
3764 FSData->f_bsize));
3765 }
3766 }
3767 cifs_buf_release(pSMB);
3768
3769 if (rc == -EAGAIN)
3770 goto oldQFSInfoRetry;
3771
3772 return rc;
3773}
3774
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775int
Steve French737b7582005-04-28 22:41:06 -07003776CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777{
3778/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3779 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3780 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3781 FILE_SYSTEM_INFO *response_data;
3782 int rc = 0;
3783 int bytes_returned = 0;
3784 __u16 params, byte_count;
3785
3786 cFYI(1, ("In QFSInfo"));
3787QFSInfoRetry:
3788 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3789 (void **) &pSMBr);
3790 if (rc)
3791 return rc;
3792
3793 params = 2; /* level */
3794 pSMB->TotalDataCount = 0;
3795 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003796 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 pSMB->MaxSetupCount = 0;
3798 pSMB->Reserved = 0;
3799 pSMB->Flags = 0;
3800 pSMB->Timeout = 0;
3801 pSMB->Reserved2 = 0;
3802 byte_count = params + 1 /* pad */ ;
3803 pSMB->TotalParameterCount = cpu_to_le16(params);
3804 pSMB->ParameterCount = pSMB->TotalParameterCount;
3805 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3806 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3807 pSMB->DataCount = 0;
3808 pSMB->DataOffset = 0;
3809 pSMB->SetupCount = 1;
3810 pSMB->Reserved3 = 0;
3811 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3812 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3813 pSMB->hdr.smb_buf_length += byte_count;
3814 pSMB->ByteCount = cpu_to_le16(byte_count);
3815
3816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3818 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003819 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 } else { /* decode response */
3821 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3822
Steve French20962432005-09-21 22:05:57 -07003823 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 rc = -EIO; /* bad smb */
3825 else {
3826 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827
3828 response_data =
3829 (FILE_SYSTEM_INFO
3830 *) (((char *) &pSMBr->hdr.Protocol) +
3831 data_offset);
3832 FSData->f_bsize =
3833 le32_to_cpu(response_data->BytesPerSector) *
3834 le32_to_cpu(response_data->
3835 SectorsPerAllocationUnit);
3836 FSData->f_blocks =
3837 le64_to_cpu(response_data->TotalAllocationUnits);
3838 FSData->f_bfree = FSData->f_bavail =
3839 le64_to_cpu(response_data->FreeAllocationUnits);
3840 cFYI(1,
3841 ("Blocks: %lld Free: %lld Block size %ld",
3842 (unsigned long long)FSData->f_blocks,
3843 (unsigned long long)FSData->f_bfree,
3844 FSData->f_bsize));
3845 }
3846 }
3847 cifs_buf_release(pSMB);
3848
3849 if (rc == -EAGAIN)
3850 goto QFSInfoRetry;
3851
3852 return rc;
3853}
3854
3855int
Steve French737b7582005-04-28 22:41:06 -07003856CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857{
3858/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3859 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3860 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3861 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3862 int rc = 0;
3863 int bytes_returned = 0;
3864 __u16 params, byte_count;
3865
3866 cFYI(1, ("In QFSAttributeInfo"));
3867QFSAttributeRetry:
3868 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3869 (void **) &pSMBr);
3870 if (rc)
3871 return rc;
3872
3873 params = 2; /* level */
3874 pSMB->TotalDataCount = 0;
3875 pSMB->MaxParameterCount = cpu_to_le16(2);
3876 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3877 pSMB->MaxSetupCount = 0;
3878 pSMB->Reserved = 0;
3879 pSMB->Flags = 0;
3880 pSMB->Timeout = 0;
3881 pSMB->Reserved2 = 0;
3882 byte_count = params + 1 /* pad */ ;
3883 pSMB->TotalParameterCount = cpu_to_le16(params);
3884 pSMB->ParameterCount = pSMB->TotalParameterCount;
3885 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3886 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3887 pSMB->DataCount = 0;
3888 pSMB->DataOffset = 0;
3889 pSMB->SetupCount = 1;
3890 pSMB->Reserved3 = 0;
3891 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3892 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3893 pSMB->hdr.smb_buf_length += byte_count;
3894 pSMB->ByteCount = cpu_to_le16(byte_count);
3895
3896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3898 if (rc) {
3899 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3900 } else { /* decode response */
3901 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3902
3903 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3904 rc = -EIO; /* bad smb */
3905 } else {
3906 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3907 response_data =
3908 (FILE_SYSTEM_ATTRIBUTE_INFO
3909 *) (((char *) &pSMBr->hdr.Protocol) +
3910 data_offset);
3911 memcpy(&tcon->fsAttrInfo, response_data,
3912 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3913 }
3914 }
3915 cifs_buf_release(pSMB);
3916
3917 if (rc == -EAGAIN)
3918 goto QFSAttributeRetry;
3919
3920 return rc;
3921}
3922
3923int
Steve French737b7582005-04-28 22:41:06 -07003924CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925{
3926/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3927 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3928 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3929 FILE_SYSTEM_DEVICE_INFO *response_data;
3930 int rc = 0;
3931 int bytes_returned = 0;
3932 __u16 params, byte_count;
3933
3934 cFYI(1, ("In QFSDeviceInfo"));
3935QFSDeviceRetry:
3936 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3937 (void **) &pSMBr);
3938 if (rc)
3939 return rc;
3940
3941 params = 2; /* level */
3942 pSMB->TotalDataCount = 0;
3943 pSMB->MaxParameterCount = cpu_to_le16(2);
3944 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3945 pSMB->MaxSetupCount = 0;
3946 pSMB->Reserved = 0;
3947 pSMB->Flags = 0;
3948 pSMB->Timeout = 0;
3949 pSMB->Reserved2 = 0;
3950 byte_count = params + 1 /* pad */ ;
3951 pSMB->TotalParameterCount = cpu_to_le16(params);
3952 pSMB->ParameterCount = pSMB->TotalParameterCount;
3953 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3954 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3955
3956 pSMB->DataCount = 0;
3957 pSMB->DataOffset = 0;
3958 pSMB->SetupCount = 1;
3959 pSMB->Reserved3 = 0;
3960 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3961 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3962 pSMB->hdr.smb_buf_length += byte_count;
3963 pSMB->ByteCount = cpu_to_le16(byte_count);
3964
3965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3967 if (rc) {
3968 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3969 } else { /* decode response */
3970 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3971
3972 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3973 rc = -EIO; /* bad smb */
3974 else {
3975 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3976 response_data =
Steve French737b7582005-04-28 22:41:06 -07003977 (FILE_SYSTEM_DEVICE_INFO *)
3978 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 data_offset);
3980 memcpy(&tcon->fsDevInfo, response_data,
3981 sizeof (FILE_SYSTEM_DEVICE_INFO));
3982 }
3983 }
3984 cifs_buf_release(pSMB);
3985
3986 if (rc == -EAGAIN)
3987 goto QFSDeviceRetry;
3988
3989 return rc;
3990}
3991
3992int
Steve French737b7582005-04-28 22:41:06 -07003993CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994{
3995/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3996 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3997 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3998 FILE_SYSTEM_UNIX_INFO *response_data;
3999 int rc = 0;
4000 int bytes_returned = 0;
4001 __u16 params, byte_count;
4002
4003 cFYI(1, ("In QFSUnixInfo"));
4004QFSUnixRetry:
4005 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4006 (void **) &pSMBr);
4007 if (rc)
4008 return rc;
4009
4010 params = 2; /* level */
4011 pSMB->TotalDataCount = 0;
4012 pSMB->DataCount = 0;
4013 pSMB->DataOffset = 0;
4014 pSMB->MaxParameterCount = cpu_to_le16(2);
4015 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4016 pSMB->MaxSetupCount = 0;
4017 pSMB->Reserved = 0;
4018 pSMB->Flags = 0;
4019 pSMB->Timeout = 0;
4020 pSMB->Reserved2 = 0;
4021 byte_count = params + 1 /* pad */ ;
4022 pSMB->ParameterCount = cpu_to_le16(params);
4023 pSMB->TotalParameterCount = pSMB->ParameterCount;
4024 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4025 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4026 pSMB->SetupCount = 1;
4027 pSMB->Reserved3 = 0;
4028 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4029 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4030 pSMB->hdr.smb_buf_length += byte_count;
4031 pSMB->ByteCount = cpu_to_le16(byte_count);
4032
4033 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4034 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4035 if (rc) {
4036 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4037 } else { /* decode response */
4038 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4039
4040 if (rc || (pSMBr->ByteCount < 13)) {
4041 rc = -EIO; /* bad smb */
4042 } else {
4043 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4044 response_data =
4045 (FILE_SYSTEM_UNIX_INFO
4046 *) (((char *) &pSMBr->hdr.Protocol) +
4047 data_offset);
4048 memcpy(&tcon->fsUnixInfo, response_data,
4049 sizeof (FILE_SYSTEM_UNIX_INFO));
4050 }
4051 }
4052 cifs_buf_release(pSMB);
4053
4054 if (rc == -EAGAIN)
4055 goto QFSUnixRetry;
4056
4057
4058 return rc;
4059}
4060
Jeremy Allisonac670552005-06-22 17:26:35 -07004061int
Steve French45abc6e2005-06-23 13:42:03 -05004062CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004063{
4064/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4065 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4066 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4067 int rc = 0;
4068 int bytes_returned = 0;
4069 __u16 params, param_offset, offset, byte_count;
4070
4071 cFYI(1, ("In SETFSUnixInfo"));
4072SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004073 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004074 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4075 (void **) &pSMBr);
4076 if (rc)
4077 return rc;
4078
4079 params = 4; /* 2 bytes zero followed by info level. */
4080 pSMB->MaxSetupCount = 0;
4081 pSMB->Reserved = 0;
4082 pSMB->Flags = 0;
4083 pSMB->Timeout = 0;
4084 pSMB->Reserved2 = 0;
4085 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4086 offset = param_offset + params;
4087
4088 pSMB->MaxParameterCount = cpu_to_le16(4);
4089 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4090 pSMB->SetupCount = 1;
4091 pSMB->Reserved3 = 0;
4092 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4093 byte_count = 1 /* pad */ + params + 12;
4094
4095 pSMB->DataCount = cpu_to_le16(12);
4096 pSMB->ParameterCount = cpu_to_le16(params);
4097 pSMB->TotalDataCount = pSMB->DataCount;
4098 pSMB->TotalParameterCount = pSMB->ParameterCount;
4099 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4100 pSMB->DataOffset = cpu_to_le16(offset);
4101
4102 /* Params. */
4103 pSMB->FileNum = 0;
4104 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4105
4106 /* Data. */
4107 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4108 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4109 pSMB->ClientUnixCap = cpu_to_le64(cap);
4110
4111 pSMB->hdr.smb_buf_length += byte_count;
4112 pSMB->ByteCount = cpu_to_le16(byte_count);
4113
4114 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4115 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4116 if (rc) {
4117 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4118 } else { /* decode response */
4119 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4120 if (rc) {
4121 rc = -EIO; /* bad smb */
4122 }
4123 }
4124 cifs_buf_release(pSMB);
4125
4126 if (rc == -EAGAIN)
4127 goto SETFSUnixRetry;
4128
4129 return rc;
4130}
4131
4132
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133
4134int
4135CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004136 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137{
4138/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4139 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4140 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4141 FILE_SYSTEM_POSIX_INFO *response_data;
4142 int rc = 0;
4143 int bytes_returned = 0;
4144 __u16 params, byte_count;
4145
4146 cFYI(1, ("In QFSPosixInfo"));
4147QFSPosixRetry:
4148 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4149 (void **) &pSMBr);
4150 if (rc)
4151 return rc;
4152
4153 params = 2; /* level */
4154 pSMB->TotalDataCount = 0;
4155 pSMB->DataCount = 0;
4156 pSMB->DataOffset = 0;
4157 pSMB->MaxParameterCount = cpu_to_le16(2);
4158 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4159 pSMB->MaxSetupCount = 0;
4160 pSMB->Reserved = 0;
4161 pSMB->Flags = 0;
4162 pSMB->Timeout = 0;
4163 pSMB->Reserved2 = 0;
4164 byte_count = params + 1 /* pad */ ;
4165 pSMB->ParameterCount = cpu_to_le16(params);
4166 pSMB->TotalParameterCount = pSMB->ParameterCount;
4167 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4168 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4169 pSMB->SetupCount = 1;
4170 pSMB->Reserved3 = 0;
4171 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4172 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4173 pSMB->hdr.smb_buf_length += byte_count;
4174 pSMB->ByteCount = cpu_to_le16(byte_count);
4175
4176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4178 if (rc) {
4179 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4180 } else { /* decode response */
4181 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4182
4183 if (rc || (pSMBr->ByteCount < 13)) {
4184 rc = -EIO; /* bad smb */
4185 } else {
4186 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4187 response_data =
4188 (FILE_SYSTEM_POSIX_INFO
4189 *) (((char *) &pSMBr->hdr.Protocol) +
4190 data_offset);
4191 FSData->f_bsize =
4192 le32_to_cpu(response_data->BlockSize);
4193 FSData->f_blocks =
4194 le64_to_cpu(response_data->TotalBlocks);
4195 FSData->f_bfree =
4196 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004197 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 FSData->f_bavail = FSData->f_bfree;
4199 } else {
4200 FSData->f_bavail =
4201 le64_to_cpu(response_data->UserBlocksAvail);
4202 }
Steve French70ca7342005-09-22 16:32:06 -07004203 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 FSData->f_files =
4205 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004206 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 FSData->f_ffree =
4208 le64_to_cpu(response_data->FreeFileNodes);
4209 }
4210 }
4211 cifs_buf_release(pSMB);
4212
4213 if (rc == -EAGAIN)
4214 goto QFSPosixRetry;
4215
4216 return rc;
4217}
4218
4219
4220/* We can not use write of zero bytes trick to
4221 set file size due to need for large file support. Also note that
4222 this SetPathInfo is preferred to SetFileInfo based method in next
4223 routine which is only needed to work around a sharing violation bug
4224 in Samba which this routine can run into */
4225
4226int
4227CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004228 __u64 size, int SetAllocation,
4229 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230{
4231 struct smb_com_transaction2_spi_req *pSMB = NULL;
4232 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4233 struct file_end_of_file_info *parm_data;
4234 int name_len;
4235 int rc = 0;
4236 int bytes_returned = 0;
4237 __u16 params, byte_count, data_count, param_offset, offset;
4238
4239 cFYI(1, ("In SetEOF"));
4240SetEOFRetry:
4241 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4242 (void **) &pSMBr);
4243 if (rc)
4244 return rc;
4245
4246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4247 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004248 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004249 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 name_len++; /* trailing null */
4251 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004252 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 name_len = strnlen(fileName, PATH_MAX);
4254 name_len++; /* trailing null */
4255 strncpy(pSMB->FileName, fileName, name_len);
4256 }
4257 params = 6 + name_len;
4258 data_count = sizeof (struct file_end_of_file_info);
4259 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004260 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 pSMB->MaxSetupCount = 0;
4262 pSMB->Reserved = 0;
4263 pSMB->Flags = 0;
4264 pSMB->Timeout = 0;
4265 pSMB->Reserved2 = 0;
4266 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4267 InformationLevel) - 4;
4268 offset = param_offset + params;
4269 if(SetAllocation) {
4270 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4271 pSMB->InformationLevel =
4272 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4273 else
4274 pSMB->InformationLevel =
4275 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4276 } else /* Set File Size */ {
4277 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4278 pSMB->InformationLevel =
4279 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4280 else
4281 pSMB->InformationLevel =
4282 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4283 }
4284
4285 parm_data =
4286 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4287 offset);
4288 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4289 pSMB->DataOffset = cpu_to_le16(offset);
4290 pSMB->SetupCount = 1;
4291 pSMB->Reserved3 = 0;
4292 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4293 byte_count = 3 /* pad */ + params + data_count;
4294 pSMB->DataCount = cpu_to_le16(data_count);
4295 pSMB->TotalDataCount = pSMB->DataCount;
4296 pSMB->ParameterCount = cpu_to_le16(params);
4297 pSMB->TotalParameterCount = pSMB->ParameterCount;
4298 pSMB->Reserved4 = 0;
4299 pSMB->hdr.smb_buf_length += byte_count;
4300 parm_data->FileSize = cpu_to_le64(size);
4301 pSMB->ByteCount = cpu_to_le16(byte_count);
4302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4304 if (rc) {
4305 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4306 }
4307
4308 cifs_buf_release(pSMB);
4309
4310 if (rc == -EAGAIN)
4311 goto SetEOFRetry;
4312
4313 return rc;
4314}
4315
4316int
4317CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4318 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4319{
4320 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4321 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4322 char *data_offset;
4323 struct file_end_of_file_info *parm_data;
4324 int rc = 0;
4325 int bytes_returned = 0;
4326 __u16 params, param_offset, offset, byte_count, count;
4327
4328 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4329 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004330 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4331
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 if (rc)
4333 return rc;
4334
Steve Frenchcd634992005-04-28 22:41:10 -07004335 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4336
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4338 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4339
4340 params = 6;
4341 pSMB->MaxSetupCount = 0;
4342 pSMB->Reserved = 0;
4343 pSMB->Flags = 0;
4344 pSMB->Timeout = 0;
4345 pSMB->Reserved2 = 0;
4346 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4347 offset = param_offset + params;
4348
4349 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4350
4351 count = sizeof(struct file_end_of_file_info);
4352 pSMB->MaxParameterCount = cpu_to_le16(2);
4353 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4354 pSMB->SetupCount = 1;
4355 pSMB->Reserved3 = 0;
4356 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4357 byte_count = 3 /* pad */ + params + count;
4358 pSMB->DataCount = cpu_to_le16(count);
4359 pSMB->ParameterCount = cpu_to_le16(params);
4360 pSMB->TotalDataCount = pSMB->DataCount;
4361 pSMB->TotalParameterCount = pSMB->ParameterCount;
4362 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4363 parm_data =
4364 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4365 offset);
4366 pSMB->DataOffset = cpu_to_le16(offset);
4367 parm_data->FileSize = cpu_to_le64(size);
4368 pSMB->Fid = fid;
4369 if(SetAllocation) {
4370 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4371 pSMB->InformationLevel =
4372 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4373 else
4374 pSMB->InformationLevel =
4375 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4376 } else /* Set File Size */ {
4377 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4378 pSMB->InformationLevel =
4379 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4380 else
4381 pSMB->InformationLevel =
4382 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4383 }
4384 pSMB->Reserved4 = 0;
4385 pSMB->hdr.smb_buf_length += byte_count;
4386 pSMB->ByteCount = cpu_to_le16(byte_count);
4387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4388 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4389 if (rc) {
4390 cFYI(1,
4391 ("Send error in SetFileInfo (SetFileSize) = %d",
4392 rc));
4393 }
4394
4395 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004396 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397
4398 /* Note: On -EAGAIN error only caller can retry on handle based calls
4399 since file handle passed in no longer valid */
4400
4401 return rc;
4402}
4403
4404/* Some legacy servers such as NT4 require that the file times be set on
4405 an open handle, rather than by pathname - this is awkward due to
4406 potential access conflicts on the open, but it is unavoidable for these
4407 old servers since the only other choice is to go from 100 nanosecond DCE
4408 time and resort to the original setpathinfo level which takes the ancient
4409 DOS time format with 2 second granularity */
4410int
4411CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4412 __u16 fid)
4413{
4414 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4415 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4416 char *data_offset;
4417 int rc = 0;
4418 int bytes_returned = 0;
4419 __u16 params, param_offset, offset, byte_count, count;
4420
4421 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004422 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4423
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 if (rc)
4425 return rc;
4426
Steve Frenchcd634992005-04-28 22:41:10 -07004427 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4428
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 /* At this point there is no need to override the current pid
4430 with the pid of the opener, but that could change if we someday
4431 use an existing handle (rather than opening one on the fly) */
4432 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4433 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4434
4435 params = 6;
4436 pSMB->MaxSetupCount = 0;
4437 pSMB->Reserved = 0;
4438 pSMB->Flags = 0;
4439 pSMB->Timeout = 0;
4440 pSMB->Reserved2 = 0;
4441 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4442 offset = param_offset + params;
4443
4444 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4445
4446 count = sizeof (FILE_BASIC_INFO);
4447 pSMB->MaxParameterCount = cpu_to_le16(2);
4448 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4449 pSMB->SetupCount = 1;
4450 pSMB->Reserved3 = 0;
4451 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4452 byte_count = 3 /* pad */ + params + count;
4453 pSMB->DataCount = cpu_to_le16(count);
4454 pSMB->ParameterCount = cpu_to_le16(params);
4455 pSMB->TotalDataCount = pSMB->DataCount;
4456 pSMB->TotalParameterCount = pSMB->ParameterCount;
4457 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4458 pSMB->DataOffset = cpu_to_le16(offset);
4459 pSMB->Fid = fid;
4460 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4461 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4462 else
4463 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4464 pSMB->Reserved4 = 0;
4465 pSMB->hdr.smb_buf_length += byte_count;
4466 pSMB->ByteCount = cpu_to_le16(byte_count);
4467 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4468 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4469 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4470 if (rc) {
4471 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4472 }
4473
Steve Frenchcd634992005-04-28 22:41:10 -07004474 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475
4476 /* Note: On -EAGAIN error only caller can retry on handle based calls
4477 since file handle passed in no longer valid */
4478
4479 return rc;
4480}
4481
4482
4483int
4484CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4485 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004486 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487{
4488 TRANSACTION2_SPI_REQ *pSMB = NULL;
4489 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4490 int name_len;
4491 int rc = 0;
4492 int bytes_returned = 0;
4493 char *data_offset;
4494 __u16 params, param_offset, offset, byte_count, count;
4495
4496 cFYI(1, ("In SetTimes"));
4497
4498SetTimesRetry:
4499 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4500 (void **) &pSMBr);
4501 if (rc)
4502 return rc;
4503
4504 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4505 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004506 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004507 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 name_len++; /* trailing null */
4509 name_len *= 2;
4510 } else { /* BB improve the check for buffer overruns BB */
4511 name_len = strnlen(fileName, PATH_MAX);
4512 name_len++; /* trailing null */
4513 strncpy(pSMB->FileName, fileName, name_len);
4514 }
4515
4516 params = 6 + name_len;
4517 count = sizeof (FILE_BASIC_INFO);
4518 pSMB->MaxParameterCount = cpu_to_le16(2);
4519 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4520 pSMB->MaxSetupCount = 0;
4521 pSMB->Reserved = 0;
4522 pSMB->Flags = 0;
4523 pSMB->Timeout = 0;
4524 pSMB->Reserved2 = 0;
4525 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4526 InformationLevel) - 4;
4527 offset = param_offset + params;
4528 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4529 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4530 pSMB->DataOffset = cpu_to_le16(offset);
4531 pSMB->SetupCount = 1;
4532 pSMB->Reserved3 = 0;
4533 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4534 byte_count = 3 /* pad */ + params + count;
4535
4536 pSMB->DataCount = cpu_to_le16(count);
4537 pSMB->ParameterCount = cpu_to_le16(params);
4538 pSMB->TotalDataCount = pSMB->DataCount;
4539 pSMB->TotalParameterCount = pSMB->ParameterCount;
4540 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4541 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4542 else
4543 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4544 pSMB->Reserved4 = 0;
4545 pSMB->hdr.smb_buf_length += byte_count;
4546 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4547 pSMB->ByteCount = cpu_to_le16(byte_count);
4548 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4549 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4550 if (rc) {
4551 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4552 }
4553
4554 cifs_buf_release(pSMB);
4555
4556 if (rc == -EAGAIN)
4557 goto SetTimesRetry;
4558
4559 return rc;
4560}
4561
4562/* Can not be used to set time stamps yet (due to old DOS time format) */
4563/* Can be used to set attributes */
4564#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4565 handling it anyway and NT4 was what we thought it would be needed for
4566 Do not delete it until we prove whether needed for Win9x though */
4567int
4568CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4569 __u16 dos_attrs, const struct nls_table *nls_codepage)
4570{
4571 SETATTR_REQ *pSMB = NULL;
4572 SETATTR_RSP *pSMBr = NULL;
4573 int rc = 0;
4574 int bytes_returned;
4575 int name_len;
4576
4577 cFYI(1, ("In SetAttrLegacy"));
4578
4579SetAttrLgcyRetry:
4580 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4581 (void **) &pSMBr);
4582 if (rc)
4583 return rc;
4584
4585 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4586 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004587 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 PATH_MAX, nls_codepage);
4589 name_len++; /* trailing null */
4590 name_len *= 2;
4591 } else { /* BB improve the check for buffer overruns BB */
4592 name_len = strnlen(fileName, PATH_MAX);
4593 name_len++; /* trailing null */
4594 strncpy(pSMB->fileName, fileName, name_len);
4595 }
4596 pSMB->attr = cpu_to_le16(dos_attrs);
4597 pSMB->BufferFormat = 0x04;
4598 pSMB->hdr.smb_buf_length += name_len + 1;
4599 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4600 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4602 if (rc) {
4603 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4604 }
4605
4606 cifs_buf_release(pSMB);
4607
4608 if (rc == -EAGAIN)
4609 goto SetAttrLgcyRetry;
4610
4611 return rc;
4612}
4613#endif /* temporarily unneeded SetAttr legacy function */
4614
4615int
4616CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004617 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4618 dev_t device, const struct nls_table *nls_codepage,
4619 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620{
4621 TRANSACTION2_SPI_REQ *pSMB = NULL;
4622 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4623 int name_len;
4624 int rc = 0;
4625 int bytes_returned = 0;
4626 FILE_UNIX_BASIC_INFO *data_offset;
4627 __u16 params, param_offset, offset, count, byte_count;
4628
4629 cFYI(1, ("In SetUID/GID/Mode"));
4630setPermsRetry:
4631 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4632 (void **) &pSMBr);
4633 if (rc)
4634 return rc;
4635
4636 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4637 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004638 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004639 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 name_len++; /* trailing null */
4641 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004642 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 name_len = strnlen(fileName, PATH_MAX);
4644 name_len++; /* trailing null */
4645 strncpy(pSMB->FileName, fileName, name_len);
4646 }
4647
4648 params = 6 + name_len;
4649 count = sizeof (FILE_UNIX_BASIC_INFO);
4650 pSMB->MaxParameterCount = cpu_to_le16(2);
4651 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4652 pSMB->MaxSetupCount = 0;
4653 pSMB->Reserved = 0;
4654 pSMB->Flags = 0;
4655 pSMB->Timeout = 0;
4656 pSMB->Reserved2 = 0;
4657 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4658 InformationLevel) - 4;
4659 offset = param_offset + params;
4660 data_offset =
4661 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4662 offset);
4663 memset(data_offset, 0, count);
4664 pSMB->DataOffset = cpu_to_le16(offset);
4665 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4666 pSMB->SetupCount = 1;
4667 pSMB->Reserved3 = 0;
4668 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4669 byte_count = 3 /* pad */ + params + count;
4670 pSMB->ParameterCount = cpu_to_le16(params);
4671 pSMB->DataCount = cpu_to_le16(count);
4672 pSMB->TotalParameterCount = pSMB->ParameterCount;
4673 pSMB->TotalDataCount = pSMB->DataCount;
4674 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4675 pSMB->Reserved4 = 0;
4676 pSMB->hdr.smb_buf_length += byte_count;
4677 data_offset->Uid = cpu_to_le64(uid);
4678 data_offset->Gid = cpu_to_le64(gid);
4679 /* better to leave device as zero when it is */
4680 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4681 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4682 data_offset->Permissions = cpu_to_le64(mode);
4683
4684 if(S_ISREG(mode))
4685 data_offset->Type = cpu_to_le32(UNIX_FILE);
4686 else if(S_ISDIR(mode))
4687 data_offset->Type = cpu_to_le32(UNIX_DIR);
4688 else if(S_ISLNK(mode))
4689 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4690 else if(S_ISCHR(mode))
4691 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4692 else if(S_ISBLK(mode))
4693 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4694 else if(S_ISFIFO(mode))
4695 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4696 else if(S_ISSOCK(mode))
4697 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4698
4699
4700 pSMB->ByteCount = cpu_to_le16(byte_count);
4701 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4703 if (rc) {
4704 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4705 }
4706
4707 if (pSMB)
4708 cifs_buf_release(pSMB);
4709 if (rc == -EAGAIN)
4710 goto setPermsRetry;
4711 return rc;
4712}
4713
4714int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004715 const int notify_subdirs, const __u16 netfid,
4716 __u32 filter, struct file * pfile, int multishot,
4717 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718{
4719 int rc = 0;
4720 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004721 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004722 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 int bytes_returned;
4724
4725 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4726 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4727 (void **) &pSMBr);
4728 if (rc)
4729 return rc;
4730
4731 pSMB->TotalParameterCount = 0 ;
4732 pSMB->TotalDataCount = 0;
4733 pSMB->MaxParameterCount = cpu_to_le32(2);
4734 /* BB find exact data count max from sess structure BB */
4735 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004736/* BB VERIFY verify which is correct for above BB */
4737 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4738 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4739
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 pSMB->MaxSetupCount = 4;
4741 pSMB->Reserved = 0;
4742 pSMB->ParameterOffset = 0;
4743 pSMB->DataCount = 0;
4744 pSMB->DataOffset = 0;
4745 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4746 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4747 pSMB->ParameterCount = pSMB->TotalParameterCount;
4748 if(notify_subdirs)
4749 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4750 pSMB->Reserved2 = 0;
4751 pSMB->CompletionFilter = cpu_to_le32(filter);
4752 pSMB->Fid = netfid; /* file handle always le */
4753 pSMB->ByteCount = 0;
4754
4755 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4756 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4757 if (rc) {
4758 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004759 } else {
4760 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004761 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004762 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004763 sizeof(struct dir_notify_req),
4764 GFP_KERNEL);
4765 if(dnotify_req) {
4766 dnotify_req->Pid = pSMB->hdr.Pid;
4767 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4768 dnotify_req->Mid = pSMB->hdr.Mid;
4769 dnotify_req->Tid = pSMB->hdr.Tid;
4770 dnotify_req->Uid = pSMB->hdr.Uid;
4771 dnotify_req->netfid = netfid;
4772 dnotify_req->pfile = pfile;
4773 dnotify_req->filter = filter;
4774 dnotify_req->multishot = multishot;
4775 spin_lock(&GlobalMid_Lock);
4776 list_add_tail(&dnotify_req->lhead,
4777 &GlobalDnotifyReqList);
4778 spin_unlock(&GlobalMid_Lock);
4779 } else
4780 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 }
4782 cifs_buf_release(pSMB);
4783 return rc;
4784}
4785#ifdef CONFIG_CIFS_XATTR
4786ssize_t
4787CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4788 const unsigned char *searchName,
4789 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004790 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791{
4792 /* BB assumes one setup word */
4793 TRANSACTION2_QPI_REQ *pSMB = NULL;
4794 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4795 int rc = 0;
4796 int bytes_returned;
4797 int name_len;
4798 struct fea * temp_fea;
4799 char * temp_ptr;
4800 __u16 params, byte_count;
4801
4802 cFYI(1, ("In Query All EAs path %s", searchName));
4803QAllEAsRetry:
4804 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4805 (void **) &pSMBr);
4806 if (rc)
4807 return rc;
4808
4809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4810 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004811 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004812 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 name_len++; /* trailing null */
4814 name_len *= 2;
4815 } else { /* BB improve the check for buffer overruns BB */
4816 name_len = strnlen(searchName, PATH_MAX);
4817 name_len++; /* trailing null */
4818 strncpy(pSMB->FileName, searchName, name_len);
4819 }
4820
4821 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4822 pSMB->TotalDataCount = 0;
4823 pSMB->MaxParameterCount = cpu_to_le16(2);
4824 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4825 pSMB->MaxSetupCount = 0;
4826 pSMB->Reserved = 0;
4827 pSMB->Flags = 0;
4828 pSMB->Timeout = 0;
4829 pSMB->Reserved2 = 0;
4830 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4831 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4832 pSMB->DataCount = 0;
4833 pSMB->DataOffset = 0;
4834 pSMB->SetupCount = 1;
4835 pSMB->Reserved3 = 0;
4836 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4837 byte_count = params + 1 /* pad */ ;
4838 pSMB->TotalParameterCount = cpu_to_le16(params);
4839 pSMB->ParameterCount = pSMB->TotalParameterCount;
4840 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4841 pSMB->Reserved4 = 0;
4842 pSMB->hdr.smb_buf_length += byte_count;
4843 pSMB->ByteCount = cpu_to_le16(byte_count);
4844
4845 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4846 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4847 if (rc) {
4848 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4849 } else { /* decode response */
4850 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4851
4852 /* BB also check enough total bytes returned */
4853 /* BB we need to improve the validity checking
4854 of these trans2 responses */
4855 if (rc || (pSMBr->ByteCount < 4))
4856 rc = -EIO; /* bad smb */
4857 /* else if (pFindData){
4858 memcpy((char *) pFindData,
4859 (char *) &pSMBr->hdr.Protocol +
4860 data_offset, kl);
4861 }*/ else {
4862 /* check that length of list is not more than bcc */
4863 /* check that each entry does not go beyond length
4864 of list */
4865 /* check that each element of each entry does not
4866 go beyond end of list */
4867 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4868 struct fealist * ea_response_data;
4869 rc = 0;
4870 /* validate_trans2_offsets() */
4871 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4872 ea_response_data = (struct fealist *)
4873 (((char *) &pSMBr->hdr.Protocol) +
4874 data_offset);
4875 name_len = le32_to_cpu(ea_response_data->list_len);
4876 cFYI(1,("ea length %d", name_len));
4877 if(name_len <= 8) {
4878 /* returned EA size zeroed at top of function */
4879 cFYI(1,("empty EA list returned from server"));
4880 } else {
4881 /* account for ea list len */
4882 name_len -= 4;
4883 temp_fea = ea_response_data->list;
4884 temp_ptr = (char *)temp_fea;
4885 while(name_len > 0) {
4886 __u16 value_len;
4887 name_len -= 4;
4888 temp_ptr += 4;
4889 rc += temp_fea->name_len;
4890 /* account for prefix user. and trailing null */
4891 rc = rc + 5 + 1;
4892 if(rc<(int)buf_size) {
4893 memcpy(EAData,"user.",5);
4894 EAData+=5;
4895 memcpy(EAData,temp_ptr,temp_fea->name_len);
4896 EAData+=temp_fea->name_len;
4897 /* null terminate name */
4898 *EAData = 0;
4899 EAData = EAData + 1;
4900 } else if(buf_size == 0) {
4901 /* skip copy - calc size only */
4902 } else {
4903 /* stop before overrun buffer */
4904 rc = -ERANGE;
4905 break;
4906 }
4907 name_len -= temp_fea->name_len;
4908 temp_ptr += temp_fea->name_len;
4909 /* account for trailing null */
4910 name_len--;
4911 temp_ptr++;
4912 value_len = le16_to_cpu(temp_fea->value_len);
4913 name_len -= value_len;
4914 temp_ptr += value_len;
4915 /* BB check that temp_ptr is still within smb BB*/
4916 /* no trailing null to account for in value len */
4917 /* go on to next EA */
4918 temp_fea = (struct fea *)temp_ptr;
4919 }
4920 }
4921 }
4922 }
4923 if (pSMB)
4924 cifs_buf_release(pSMB);
4925 if (rc == -EAGAIN)
4926 goto QAllEAsRetry;
4927
4928 return (ssize_t)rc;
4929}
4930
4931ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4932 const unsigned char * searchName,const unsigned char * ea_name,
4933 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004934 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935{
4936 TRANSACTION2_QPI_REQ *pSMB = NULL;
4937 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4938 int rc = 0;
4939 int bytes_returned;
4940 int name_len;
4941 struct fea * temp_fea;
4942 char * temp_ptr;
4943 __u16 params, byte_count;
4944
4945 cFYI(1, ("In Query EA path %s", searchName));
4946QEARetry:
4947 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4948 (void **) &pSMBr);
4949 if (rc)
4950 return rc;
4951
4952 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4953 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004954 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004955 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 name_len++; /* trailing null */
4957 name_len *= 2;
4958 } else { /* BB improve the check for buffer overruns BB */
4959 name_len = strnlen(searchName, PATH_MAX);
4960 name_len++; /* trailing null */
4961 strncpy(pSMB->FileName, searchName, name_len);
4962 }
4963
4964 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4965 pSMB->TotalDataCount = 0;
4966 pSMB->MaxParameterCount = cpu_to_le16(2);
4967 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4968 pSMB->MaxSetupCount = 0;
4969 pSMB->Reserved = 0;
4970 pSMB->Flags = 0;
4971 pSMB->Timeout = 0;
4972 pSMB->Reserved2 = 0;
4973 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4974 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4975 pSMB->DataCount = 0;
4976 pSMB->DataOffset = 0;
4977 pSMB->SetupCount = 1;
4978 pSMB->Reserved3 = 0;
4979 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4980 byte_count = params + 1 /* pad */ ;
4981 pSMB->TotalParameterCount = cpu_to_le16(params);
4982 pSMB->ParameterCount = pSMB->TotalParameterCount;
4983 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4984 pSMB->Reserved4 = 0;
4985 pSMB->hdr.smb_buf_length += byte_count;
4986 pSMB->ByteCount = cpu_to_le16(byte_count);
4987
4988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4990 if (rc) {
4991 cFYI(1, ("Send error in Query EA = %d", rc));
4992 } else { /* decode response */
4993 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4994
4995 /* BB also check enough total bytes returned */
4996 /* BB we need to improve the validity checking
4997 of these trans2 responses */
4998 if (rc || (pSMBr->ByteCount < 4))
4999 rc = -EIO; /* bad smb */
5000 /* else if (pFindData){
5001 memcpy((char *) pFindData,
5002 (char *) &pSMBr->hdr.Protocol +
5003 data_offset, kl);
5004 }*/ else {
5005 /* check that length of list is not more than bcc */
5006 /* check that each entry does not go beyond length
5007 of list */
5008 /* check that each element of each entry does not
5009 go beyond end of list */
5010 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5011 struct fealist * ea_response_data;
5012 rc = -ENODATA;
5013 /* validate_trans2_offsets() */
5014 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5015 ea_response_data = (struct fealist *)
5016 (((char *) &pSMBr->hdr.Protocol) +
5017 data_offset);
5018 name_len = le32_to_cpu(ea_response_data->list_len);
5019 cFYI(1,("ea length %d", name_len));
5020 if(name_len <= 8) {
5021 /* returned EA size zeroed at top of function */
5022 cFYI(1,("empty EA list returned from server"));
5023 } else {
5024 /* account for ea list len */
5025 name_len -= 4;
5026 temp_fea = ea_response_data->list;
5027 temp_ptr = (char *)temp_fea;
5028 /* loop through checking if we have a matching
5029 name and then return the associated value */
5030 while(name_len > 0) {
5031 __u16 value_len;
5032 name_len -= 4;
5033 temp_ptr += 4;
5034 value_len = le16_to_cpu(temp_fea->value_len);
5035 /* BB validate that value_len falls within SMB,
5036 even though maximum for name_len is 255 */
5037 if(memcmp(temp_fea->name,ea_name,
5038 temp_fea->name_len) == 0) {
5039 /* found a match */
5040 rc = value_len;
5041 /* account for prefix user. and trailing null */
5042 if(rc<=(int)buf_size) {
5043 memcpy(ea_value,
5044 temp_fea->name+temp_fea->name_len+1,
5045 rc);
5046 /* ea values, unlike ea names,
5047 are not null terminated */
5048 } else if(buf_size == 0) {
5049 /* skip copy - calc size only */
5050 } else {
5051 /* stop before overrun buffer */
5052 rc = -ERANGE;
5053 }
5054 break;
5055 }
5056 name_len -= temp_fea->name_len;
5057 temp_ptr += temp_fea->name_len;
5058 /* account for trailing null */
5059 name_len--;
5060 temp_ptr++;
5061 name_len -= value_len;
5062 temp_ptr += value_len;
5063 /* no trailing null to account for in value len */
5064 /* go on to next EA */
5065 temp_fea = (struct fea *)temp_ptr;
5066 }
5067 }
5068 }
5069 }
5070 if (pSMB)
5071 cifs_buf_release(pSMB);
5072 if (rc == -EAGAIN)
5073 goto QEARetry;
5074
5075 return (ssize_t)rc;
5076}
5077
5078int
5079CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5080 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005081 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5082 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083{
5084 struct smb_com_transaction2_spi_req *pSMB = NULL;
5085 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5086 struct fealist *parm_data;
5087 int name_len;
5088 int rc = 0;
5089 int bytes_returned = 0;
5090 __u16 params, param_offset, byte_count, offset, count;
5091
5092 cFYI(1, ("In SetEA"));
5093SetEARetry:
5094 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5095 (void **) &pSMBr);
5096 if (rc)
5097 return rc;
5098
5099 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5100 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005101 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005102 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 name_len++; /* trailing null */
5104 name_len *= 2;
5105 } else { /* BB improve the check for buffer overruns BB */
5106 name_len = strnlen(fileName, PATH_MAX);
5107 name_len++; /* trailing null */
5108 strncpy(pSMB->FileName, fileName, name_len);
5109 }
5110
5111 params = 6 + name_len;
5112
5113 /* done calculating parms using name_len of file name,
5114 now use name_len to calculate length of ea name
5115 we are going to create in the inode xattrs */
5116 if(ea_name == NULL)
5117 name_len = 0;
5118 else
5119 name_len = strnlen(ea_name,255);
5120
5121 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5122 pSMB->MaxParameterCount = cpu_to_le16(2);
5123 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5124 pSMB->MaxSetupCount = 0;
5125 pSMB->Reserved = 0;
5126 pSMB->Flags = 0;
5127 pSMB->Timeout = 0;
5128 pSMB->Reserved2 = 0;
5129 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5130 InformationLevel) - 4;
5131 offset = param_offset + params;
5132 pSMB->InformationLevel =
5133 cpu_to_le16(SMB_SET_FILE_EA);
5134
5135 parm_data =
5136 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5137 offset);
5138 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5139 pSMB->DataOffset = cpu_to_le16(offset);
5140 pSMB->SetupCount = 1;
5141 pSMB->Reserved3 = 0;
5142 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5143 byte_count = 3 /* pad */ + params + count;
5144 pSMB->DataCount = cpu_to_le16(count);
5145 parm_data->list_len = cpu_to_le32(count);
5146 parm_data->list[0].EA_flags = 0;
5147 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005148 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 /* EA names are always ASCII */
5150 if(ea_name)
5151 strncpy(parm_data->list[0].name,ea_name,name_len);
5152 parm_data->list[0].name[name_len] = 0;
5153 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5154 /* caller ensures that ea_value_len is less than 64K but
5155 we need to ensure that it fits within the smb */
5156
5157 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5158 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5159 if(ea_value_len)
5160 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5161
5162 pSMB->TotalDataCount = pSMB->DataCount;
5163 pSMB->ParameterCount = cpu_to_le16(params);
5164 pSMB->TotalParameterCount = pSMB->ParameterCount;
5165 pSMB->Reserved4 = 0;
5166 pSMB->hdr.smb_buf_length += byte_count;
5167 pSMB->ByteCount = cpu_to_le16(byte_count);
5168 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5169 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5170 if (rc) {
5171 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5172 }
5173
5174 cifs_buf_release(pSMB);
5175
5176 if (rc == -EAGAIN)
5177 goto SetEARetry;
5178
5179 return rc;
5180}
5181
5182#endif