blob: 77cca380946742a7fef62a42e7441576c064913f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French12b3b8f2006-02-09 21:12:47 +00004 * Copyright (C) International Business Machines Corp., 2002,2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly different for reconnection purposes since we never want */
28 /* to reuse a stale file handle and the caller knows the file handle */
29
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
Steve Frencheeac8042006-01-13 21:34:58 -080040#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000051 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 {BAD_PROT, "\2"}
53};
54#else
55static struct {
56 int index;
57 char *name;
58} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000059#ifdef CONFIG_CIFS_WEAK_PW_HASH
60 {LANMAN_PROT, "\2LM1.2X002"},
61#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 {CIFS_PROT, "\2NT LM 0.12"},
63 {BAD_PROT, "\2"}
64};
65#endif
66
Steve French39798772006-05-31 22:40:51 +000067/* define the number of elements in the cifs dialect array */
68#ifdef CONFIG_CIFS_POSIX
69#ifdef CONFIG_CIFS_WEAK_PW_HASH
70#define CIFS_NUM_PROT 3
71#else
72#define CIFS_NUM_PROT 2
73#endif /* CIFS_WEAK_PW_HASH */
74#else /* not posix */
75#ifdef CONFIG_CIFS_WEAK_PW_HASH
76#define CIFS_NUM_PROT 2
77#else
78#define CIFS_NUM_PROT 1
79#endif /* CONFIG_CIFS_WEAK_PW_HASH */
80#endif /* CIFS_POSIX */
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83/* Mark as invalid, all open files on tree connections since they
84 were closed when session to server was lost */
85static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
86{
87 struct cifsFileInfo *open_file = NULL;
88 struct list_head * tmp;
89 struct list_head * tmp1;
90
91/* list all files open on tree connection and mark them invalid */
92 write_lock(&GlobalSMBSeslock);
93 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
94 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
95 if(open_file) {
96 open_file->invalidHandle = TRUE;
97 }
98 }
99 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
104/* If the return code is zero, this function must fill in request_buf pointer */
105static int
106small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
107 void **request_buf /* returned */)
108{
109 int rc = 0;
110
111 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
112 check for tcp and smb session status done differently
113 for those three - in the calling routine */
114 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800115 if(tcon->tidStatus == CifsExiting) {
116 /* only tree disconnect, open, and write,
117 (and ulogoff which does not have tcon)
118 are allowed as we start force umount */
119 if((smb_command != SMB_COM_WRITE_ANDX) &&
120 (smb_command != SMB_COM_OPEN_ANDX) &&
121 (smb_command != SMB_COM_TREE_DISCONNECT)) {
122 cFYI(1,("can not send cmd %d while umounting",
123 smb_command));
124 return -ENODEV;
125 }
126 }
Steve French31ca3bc2005-04-28 22:41:11 -0700127 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
128 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 struct nls_table *nls_codepage;
130 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700131 reconnect, should be greater than cifs socket
132 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
134 wait_event_interruptible_timeout(tcon->ses->server->response_q,
135 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
136 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
137 /* on "soft" mounts we wait once */
138 if((tcon->retry == FALSE) ||
139 (tcon->ses->status == CifsExiting)) {
140 cFYI(1,("gave up waiting on reconnect in smb_init"));
141 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700142 } /* else "hard" mount - keep retrying
143 until process is killed or server
144 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 } else /* TCP session is reestablished now */
146 break;
147
148 }
149
150 nls_codepage = load_nls_default();
151 /* need to prevent multiple threads trying to
152 simultaneously reconnect the same SMB session */
153 down(&tcon->ses->sesSem);
154 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700155 rc = cifs_setup_session(0, tcon->ses,
156 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
158 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700159 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
160 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700162 /* BB FIXME add code to check if wsize needs
163 update due to negotiated smb buffer size
164 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 if(rc == 0)
166 atomic_inc(&tconInfoReconnectCount);
167
168 cFYI(1, ("reconnect tcon rc = %d", rc));
169 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700170 it is safer (and faster) to reopen files
171 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700174 know whether we can continue or not without
175 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 switch(smb_command) {
177 case SMB_COM_READ_ANDX:
178 case SMB_COM_WRITE_ANDX:
179 case SMB_COM_CLOSE:
180 case SMB_COM_FIND_CLOSE2:
181 case SMB_COM_LOCKING_ANDX: {
182 unload_nls(nls_codepage);
183 return -EAGAIN;
184 }
185 }
186 } else {
187 up(&tcon->ses->sesSem);
188 }
189 unload_nls(nls_codepage);
190
191 } else {
192 return -EIO;
193 }
194 }
195 if(rc)
196 return rc;
197
198 *request_buf = cifs_small_buf_get();
199 if (*request_buf == NULL) {
200 /* BB should we add a retry in here if not a writepage? */
201 return -ENOMEM;
202 }
203
204 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
205
Steve Frencha4544342005-08-24 13:59:35 -0700206 if(tcon != NULL)
207 cifs_stats_inc(&tcon->num_smbs_sent);
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000210}
211
212#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French12b3b8f2006-02-09 21:12:47 +0000213int
Steve French5815449d2006-02-14 01:36:20 +0000214small_smb_init_no_tc(const int smb_command, const int wct,
215 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000216{
217 int rc;
218 struct smb_hdr * buffer;
219
Steve French5815449d2006-02-14 01:36:20 +0000220 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000221 if(rc)
222 return rc;
223
Steve French04fdabe2006-02-10 05:52:50 +0000224 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000225 buffer->Mid = GetNextMid(ses->server);
226 if (ses->capabilities & CAP_UNICODE)
227 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000228 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000229 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
230
231 /* uid, tid can stay at zero as set in header assemble */
232
233 /* BB add support for turning on the signing when
234 this function is used after 1st of session setup requests */
235
236 return rc;
237}
Steve French5815449d2006-02-14 01:36:20 +0000238#endif /* CONFIG_CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240/* If the return code is zero, this function must fill in request_buf pointer */
241static int
242smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
243 void **request_buf /* returned */ ,
244 void **response_buf /* returned */ )
245{
246 int rc = 0;
247
248 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
249 check for tcp and smb session status done differently
250 for those three - in the calling routine */
251 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800252 if(tcon->tidStatus == CifsExiting) {
253 /* only tree disconnect, open, and write,
254 (and ulogoff which does not have tcon)
255 are allowed as we start force umount */
256 if((smb_command != SMB_COM_WRITE_ANDX) &&
257 (smb_command != SMB_COM_OPEN_ANDX) &&
258 (smb_command != SMB_COM_TREE_DISCONNECT)) {
259 cFYI(1,("can not send cmd %d while umounting",
260 smb_command));
261 return -ENODEV;
262 }
263 }
264
Steve French31ca3bc2005-04-28 22:41:11 -0700265 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
266 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700268 /* Give Demultiplex thread up to 10 seconds to
269 reconnect, should be greater than cifs socket
270 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
272 wait_event_interruptible_timeout(tcon->ses->server->response_q,
273 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700274 if(tcon->ses->server->tcpStatus ==
275 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* on "soft" mounts we wait once */
277 if((tcon->retry == FALSE) ||
278 (tcon->ses->status == CifsExiting)) {
279 cFYI(1,("gave up waiting on reconnect in smb_init"));
280 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700281 } /* else "hard" mount - keep retrying
282 until process is killed or server
283 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 } else /* TCP session is reestablished now */
285 break;
286
287 }
288
289 nls_codepage = load_nls_default();
290 /* need to prevent multiple threads trying to
291 simultaneously reconnect the same SMB session */
292 down(&tcon->ses->sesSem);
293 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700294 rc = cifs_setup_session(0, tcon->ses,
295 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
297 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700298 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
299 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700301 /* BB FIXME add code to check if wsize needs
302 update due to negotiated smb buffer size
303 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 if(rc == 0)
305 atomic_inc(&tconInfoReconnectCount);
306
307 cFYI(1, ("reconnect tcon rc = %d", rc));
308 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700309 it is safer (and faster) to reopen files
310 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700313 know whether we can continue or not without
314 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 switch(smb_command) {
316 case SMB_COM_READ_ANDX:
317 case SMB_COM_WRITE_ANDX:
318 case SMB_COM_CLOSE:
319 case SMB_COM_FIND_CLOSE2:
320 case SMB_COM_LOCKING_ANDX: {
321 unload_nls(nls_codepage);
322 return -EAGAIN;
323 }
324 }
325 } else {
326 up(&tcon->ses->sesSem);
327 }
328 unload_nls(nls_codepage);
329
330 } else {
331 return -EIO;
332 }
333 }
334 if(rc)
335 return rc;
336
337 *request_buf = cifs_buf_get();
338 if (*request_buf == NULL) {
339 /* BB should we add a retry in here if not a writepage? */
340 return -ENOMEM;
341 }
342 /* Although the original thought was we needed the response buf for */
343 /* potential retries of smb operations it turns out we can determine */
344 /* from the mid flags when the request buffer can be resent without */
345 /* having to use a second distinct buffer for the response */
Steve French39798772006-05-31 22:40:51 +0000346 if(response_buf)
347 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
350 wct /*wct */ );
351
Steve Frencha4544342005-08-24 13:59:35 -0700352 if(tcon != NULL)
353 cifs_stats_inc(&tcon->num_smbs_sent);
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return rc;
356}
357
358static int validate_t2(struct smb_t2_rsp * pSMB)
359{
360 int rc = -EINVAL;
361 int total_size;
362 char * pBCC;
363
364 /* check for plausible wct, bcc and t2 data and parm sizes */
365 /* check for parm and data offset going beyond end of smb */
366 if(pSMB->hdr.WordCount >= 10) {
367 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
368 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
369 /* check that bcc is at least as big as parms + data */
370 /* check that bcc is less than negotiated smb buffer */
371 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
372 if(total_size < 512) {
373 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
374 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700375 pBCC = (pSMB->hdr.WordCount * 2) +
376 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 (char *)pSMB;
378 if((total_size <= (*(u16 *)pBCC)) &&
379 (total_size <
380 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
381 return 0;
382 }
383
384 }
385 }
386 }
387 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
388 sizeof(struct smb_t2_rsp) + 16);
389 return rc;
390}
391int
392CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
393{
394 NEGOTIATE_REQ *pSMB;
395 NEGOTIATE_RSP *pSMBr;
396 int rc = 0;
397 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000398 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 struct TCP_Server_Info * server;
400 u16 count;
401
402 if(ses->server)
403 server = ses->server;
404 else {
405 rc = -EIO;
406 return rc;
407 }
408 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
409 (void **) &pSMB, (void **) &pSMBr);
410 if (rc)
411 return rc;
Steve French1982c342005-08-17 12:38:22 -0700412 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French39798772006-05-31 22:40:51 +0000414/* if (extended_security)
415 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/
416
417 count = 0;
418 for(i=0;i<CIFS_NUM_PROT;i++) {
419 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
420 count += strlen(protocols[i].name) + 1;
421 /* null at end of source and target buffers anyway */
422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->hdr.smb_buf_length += count;
424 pSMB->ByteCount = cpu_to_le16(count);
425
426 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
428 if (rc == 0) {
Steve French39798772006-05-31 22:40:51 +0000429 cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
430 /* Check wct = 1 error case */
431 if((pSMBr->hdr.WordCount < 13)
432 || (pSMBr->DialectIndex == BAD_PROT)) {
433 /* core returns wct = 1, but we do not ask for
434 core - otherwise it just comes when dialect
435 index is -1 indicating we could not negotiate
436 a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
Steve French3856a9d2006-06-01 19:38:46 +0000439#ifdef CONFIG_CIFS_WEAK_PW_HASH
440 } else if((pSMBr->hdr.WordCount == 13)
441 && (pSMBr->DialectIndex == LANMAN_PROT)) {
Steve French39798772006-05-31 22:40:51 +0000442 struct lanman_neg_rsp * rsp =
443 (struct lanman_neg_rsp *)pSMBr;
444
Steve French7c7b25b2006-06-01 19:20:10 +0000445 if((extended_security & CIFSSEC_MAY_LANMAN) ||
446 (extended_security & CIFSSEC_MAY_PLNTXT))
447 server->secType = LANMAN;
448 else {
449 cERROR(1, ("mount failed weak security disabled"
450 " in /proc/fs/cifs/SecurityFlags"));
451 rc = -EOPNOTSUPP;
452 goto neg_err_exit;
453 }
Steve French39798772006-05-31 22:40:51 +0000454 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
455 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
456 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
457 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
458
459 /* BB what do we do with raw mode? BB */
460 server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
461 /* Do we have to set signing flags? no signing
462 was available LANMAN - default should be ok */
463
464 /* BB FIXME set default dummy capabilities since
465 they are not returned by the server in this dialect */
466
467 /* get server time for time conversions and add
468 code to use it and timezone since this is not UTC */
469
470 if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
471 memcpy(server->cryptKey, rsp->EncryptionKey,
472 CIFS_CRYPTO_KEY_SIZE);
473 } else {
474 rc = -EIO;
475 goto neg_err_exit;
476 }
477
478 cFYI(1,("LANMAN negotiated")); /* BB removeme BB */
Steve French7c7b25b2006-06-01 19:20:10 +0000479#else /* weak security disabled */
Steve French7a0d2232006-06-01 19:44:37 +0000480 } else if(pSMBr->hdr.WordCount == 13) {
Steve French3856a9d2006-06-01 19:38:46 +0000481 cERROR(1,("mount failed, cifs module not built "
482 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000483 rc = -EOPNOTSUPP;
484#endif /* WEAK_PW_HASH */
Steve French39798772006-05-31 22:40:51 +0000485 goto neg_err_exit;
486 } else if(pSMBr->hdr.WordCount != 17) {
487 /* unknown wct */
488 rc = -EOPNOTSUPP;
489 goto neg_err_exit;
490 }
491
Steve Frencheeac8042006-01-13 21:34:58 -0800492 server->secMode = pSMBr->SecurityMode;
493 if((server->secMode & SECMODE_USER) == 0)
494 cFYI(1,("share mode security"));
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000495
496 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
497#ifdef CONFIG_CIFS_WEAK_PW_HASH
498 if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0)
499#endif /* CIFS_WEAK_PW_HASH */
500 cERROR(1,("Server requests plain text password"
501 " but client support disabled"));
Steve French7c7b25b2006-06-01 19:20:10 +0000502
503 if(extended_security & CIFSSEC_MUST_NTLMV2)
504 server->secType = NTLMv2;
505 else
506 server->secType = NTLM;
507 /* else krb5 ... */
508
Steve French09d1db52005-04-28 22:41:08 -0700509 /* one byte - no need to convert this or EncryptionKeyLen
510 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
512 /* probably no need to store and check maxvcs */
513 server->maxBuf =
514 min(le32_to_cpu(pSMBr->MaxBufferSize),
515 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
516 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve Frencheeac8042006-01-13 21:34:58 -0800517 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
519 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
520 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
521 /* BB with UTC do we ever need to be using srvr timezone? */
522 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
523 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
524 CIFS_CRYPTO_KEY_SIZE);
525 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
526 && (pSMBr->EncryptionKeyLength == 0)) {
527 /* decode security blob */
528 } else
529 rc = -EIO;
530
531 /* BB might be helpful to save off the domain of server here */
532
533 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
534 (server->capabilities & CAP_EXTENDED_SECURITY)) {
535 count = pSMBr->ByteCount;
536 if (count < 16)
537 rc = -EIO;
538 else if (count == 16) {
539 server->secType = RawNTLMSSP;
540 if (server->socketUseCount.counter > 1) {
541 if (memcmp
542 (server->server_GUID,
543 pSMBr->u.extended_response.
544 GUID, 16) != 0) {
Steve Frencheeac8042006-01-13 21:34:58 -0800545 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 memcpy(server->
547 server_GUID,
548 pSMBr->u.
549 extended_response.
550 GUID, 16);
551 }
552 } else
553 memcpy(server->server_GUID,
554 pSMBr->u.extended_response.
555 GUID, 16);
556 } else {
557 rc = decode_negTokenInit(pSMBr->u.
558 extended_response.
559 SecurityBlob,
560 count - 16,
561 &server->secType);
562 if(rc == 1) {
563 /* BB Need to fill struct for sessetup here */
564 rc = -EOPNOTSUPP;
565 } else {
566 rc = -EINVAL;
567 }
568 }
569 } else
570 server->capabilities &= ~CAP_EXTENDED_SECURITY;
571 if(sign_CIFS_PDUs == FALSE) {
572 if(server->secMode & SECMODE_SIGN_REQUIRED)
573 cERROR(1,
574 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700575 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 } else if(sign_CIFS_PDUs == 1) {
577 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700578 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
580
581 }
Steve French39798772006-05-31 22:40:51 +0000582neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700583 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 return rc;
585}
586
587int
588CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
589{
590 struct smb_hdr *smb_buffer;
591 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
592 int rc = 0;
593 int length;
594
595 cFYI(1, ("In tree disconnect"));
596 /*
597 * If last user of the connection and
598 * connection alive - disconnect it
599 * If this is the last connection on the server session disconnect it
600 * (and inside session disconnect we should check if tcp socket needs
601 * to be freed and kernel thread woken up).
602 */
603 if (tcon)
604 down(&tcon->tconSem);
605 else
606 return -EIO;
607
608 atomic_dec(&tcon->useCount);
609 if (atomic_read(&tcon->useCount) > 0) {
610 up(&tcon->tconSem);
611 return -EBUSY;
612 }
613
614 /* No need to return error on this operation if tid invalidated and
615 closed on server already e.g. due to tcp session crashing */
616 if(tcon->tidStatus == CifsNeedReconnect) {
617 up(&tcon->tconSem);
618 return 0;
619 }
620
621 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
622 up(&tcon->tconSem);
623 return -EIO;
624 }
Steve French09d1db52005-04-28 22:41:08 -0700625 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
626 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 if (rc) {
628 up(&tcon->tconSem);
629 return rc;
630 } else {
631 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
634 &length, 0);
635 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700636 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 if (smb_buffer)
639 cifs_small_buf_release(smb_buffer);
640 up(&tcon->tconSem);
641
642 /* No need to return error on this operation if tid invalidated and
643 closed on server already e.g. due to tcp session crashing */
644 if (rc == -EAGAIN)
645 rc = 0;
646
647 return rc;
648}
649
650int
651CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
652{
653 struct smb_hdr *smb_buffer_response;
654 LOGOFF_ANDX_REQ *pSMB;
655 int rc = 0;
656 int length;
657
658 cFYI(1, ("In SMBLogoff for session disconnect"));
659 if (ses)
660 down(&ses->sesSem);
661 else
662 return -EIO;
663
664 atomic_dec(&ses->inUse);
665 if (atomic_read(&ses->inUse) > 0) {
666 up(&ses->sesSem);
667 return -EBUSY;
668 }
669 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
670 if (rc) {
671 up(&ses->sesSem);
672 return rc;
673 }
674
675 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
676
677 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700678 pSMB->hdr.Mid = GetNextMid(ses->server);
679
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 if(ses->server->secMode &
681 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
682 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
683 }
684
685 pSMB->hdr.Uid = ses->Suid;
686
687 pSMB->AndXCommand = 0xFF;
688 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
689 smb_buffer_response, &length, 0);
690 if (ses->server) {
691 atomic_dec(&ses->server->socketUseCount);
692 if (atomic_read(&ses->server->socketUseCount) == 0) {
693 spin_lock(&GlobalMid_Lock);
694 ses->server->tcpStatus = CifsExiting;
695 spin_unlock(&GlobalMid_Lock);
696 rc = -ESHUTDOWN;
697 }
698 }
Steve Frencha59c6582005-08-17 12:12:19 -0700699 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700700 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 /* if session dead then we do not need to do ulogoff,
703 since server closed smb session, no sense reporting
704 error */
705 if (rc == -EAGAIN)
706 rc = 0;
707 return rc;
708}
709
710int
Steve French737b7582005-04-28 22:41:06 -0700711CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
712 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
714 DELETE_FILE_REQ *pSMB = NULL;
715 DELETE_FILE_RSP *pSMBr = NULL;
716 int rc = 0;
717 int bytes_returned;
718 int name_len;
719
720DelFileRetry:
721 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
722 (void **) &pSMBr);
723 if (rc)
724 return rc;
725
726 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
727 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500728 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700729 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 name_len++; /* trailing null */
731 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700732 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 name_len = strnlen(fileName, PATH_MAX);
734 name_len++; /* trailing null */
735 strncpy(pSMB->fileName, fileName, name_len);
736 }
737 pSMB->SearchAttributes =
738 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
739 pSMB->BufferFormat = 0x04;
740 pSMB->hdr.smb_buf_length += name_len + 1;
741 pSMB->ByteCount = cpu_to_le16(name_len + 1);
742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700744 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (rc) {
746 cFYI(1, ("Error in RMFile = %d", rc));
747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 cifs_buf_release(pSMB);
750 if (rc == -EAGAIN)
751 goto DelFileRetry;
752
753 return rc;
754}
755
756int
Steve French737b7582005-04-28 22:41:06 -0700757CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
758 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
760 DELETE_DIRECTORY_REQ *pSMB = NULL;
761 DELETE_DIRECTORY_RSP *pSMBr = NULL;
762 int rc = 0;
763 int bytes_returned;
764 int name_len;
765
766 cFYI(1, ("In CIFSSMBRmDir"));
767RmDirRetry:
768 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
769 (void **) &pSMBr);
770 if (rc)
771 return rc;
772
773 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700774 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
775 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 name_len++; /* trailing null */
777 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700778 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 name_len = strnlen(dirName, PATH_MAX);
780 name_len++; /* trailing null */
781 strncpy(pSMB->DirName, dirName, name_len);
782 }
783
784 pSMB->BufferFormat = 0x04;
785 pSMB->hdr.smb_buf_length += name_len + 1;
786 pSMB->ByteCount = cpu_to_le16(name_len + 1);
787 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
788 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700789 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (rc) {
791 cFYI(1, ("Error in RMDir = %d", rc));
792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 cifs_buf_release(pSMB);
795 if (rc == -EAGAIN)
796 goto RmDirRetry;
797 return rc;
798}
799
800int
801CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700802 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
804 int rc = 0;
805 CREATE_DIRECTORY_REQ *pSMB = NULL;
806 CREATE_DIRECTORY_RSP *pSMBr = NULL;
807 int bytes_returned;
808 int name_len;
809
810 cFYI(1, ("In CIFSSMBMkDir"));
811MkDirRetry:
812 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
813 (void **) &pSMBr);
814 if (rc)
815 return rc;
816
817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500818 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700819 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 name_len++; /* trailing null */
821 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700822 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 name_len = strnlen(name, PATH_MAX);
824 name_len++; /* trailing null */
825 strncpy(pSMB->DirName, name, name_len);
826 }
827
828 pSMB->BufferFormat = 0x04;
829 pSMB->hdr.smb_buf_length += name_len + 1;
830 pSMB->ByteCount = cpu_to_le16(name_len + 1);
831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700833 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 if (rc) {
835 cFYI(1, ("Error in Mkdir = %d", rc));
836 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 cifs_buf_release(pSMB);
839 if (rc == -EAGAIN)
840 goto MkDirRetry;
841 return rc;
842}
843
Steve Frencha9d02ad2005-08-24 23:06:05 -0700844static __u16 convert_disposition(int disposition)
845{
846 __u16 ofun = 0;
847
848 switch (disposition) {
849 case FILE_SUPERSEDE:
850 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
851 break;
852 case FILE_OPEN:
853 ofun = SMBOPEN_OAPPEND;
854 break;
855 case FILE_CREATE:
856 ofun = SMBOPEN_OCREATE;
857 break;
858 case FILE_OPEN_IF:
859 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
860 break;
861 case FILE_OVERWRITE:
862 ofun = SMBOPEN_OTRUNC;
863 break;
864 case FILE_OVERWRITE_IF:
865 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
866 break;
867 default:
868 cFYI(1,("unknown disposition %d",disposition));
869 ofun = SMBOPEN_OAPPEND; /* regular open */
870 }
871 return ofun;
872}
873
874int
875SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
876 const char *fileName, const int openDisposition,
877 const int access_flags, const int create_options, __u16 * netfid,
878 int *pOplock, FILE_ALL_INFO * pfile_info,
879 const struct nls_table *nls_codepage, int remap)
880{
881 int rc = -EACCES;
882 OPENX_REQ *pSMB = NULL;
883 OPENX_RSP *pSMBr = NULL;
884 int bytes_returned;
885 int name_len;
886 __u16 count;
887
888OldOpenRetry:
889 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
890 (void **) &pSMBr);
891 if (rc)
892 return rc;
893
894 pSMB->AndXCommand = 0xFF; /* none */
895
896 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
897 count = 1; /* account for one byte pad to word boundary */
898 name_len =
899 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
900 fileName, PATH_MAX, nls_codepage, remap);
901 name_len++; /* trailing null */
902 name_len *= 2;
903 } else { /* BB improve check for buffer overruns BB */
904 count = 0; /* no pad */
905 name_len = strnlen(fileName, PATH_MAX);
906 name_len++; /* trailing null */
907 strncpy(pSMB->fileName, fileName, name_len);
908 }
909 if (*pOplock & REQ_OPLOCK)
910 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
911 else if (*pOplock & REQ_BATCHOPLOCK) {
912 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
913 }
914 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
915 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
916 /* 0 = read
917 1 = write
918 2 = rw
919 3 = execute
920 */
921 pSMB->Mode = cpu_to_le16(2);
922 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
923 /* set file as system file if special file such
924 as fifo and server expecting SFU style and
925 no Unix extensions */
926
927 if(create_options & CREATE_OPTION_SPECIAL)
928 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
929 else
Steve French3e87d802005-09-18 20:49:21 -0700930 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700931
932 /* if ((omode & S_IWUGO) == 0)
933 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
934 /* Above line causes problems due to vfs splitting create into two
935 pieces - need to set mode after file created not while it is
936 being created */
937
938 /* BB FIXME BB */
939/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
940 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700941
942 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700943 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700944 count += name_len;
945 pSMB->hdr.smb_buf_length += count;
946
947 pSMB->ByteCount = cpu_to_le16(count);
948 /* long_op set to 1 to allow for oplock break timeouts */
949 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
950 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
951 cifs_stats_inc(&tcon->num_opens);
952 if (rc) {
953 cFYI(1, ("Error in Open = %d", rc));
954 } else {
955 /* BB verify if wct == 15 */
956
957/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
958
959 *netfid = pSMBr->Fid; /* cifs fid stays in le */
960 /* Let caller know file was created so we can set the mode. */
961 /* Do we care about the CreateAction in any other cases? */
962 /* BB FIXME BB */
963/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
964 *pOplock |= CIFS_CREATE_ACTION; */
965 /* BB FIXME END */
966
967 if(pfile_info) {
968 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
969 pfile_info->LastAccessTime = 0; /* BB fixme */
970 pfile_info->LastWriteTime = 0; /* BB fixme */
971 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700972 pfile_info->Attributes =
973 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700974 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700975 pfile_info->AllocationSize =
976 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
977 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700978 pfile_info->NumberOfLinks = cpu_to_le32(1);
979 }
980 }
981
982 cifs_buf_release(pSMB);
983 if (rc == -EAGAIN)
984 goto OldOpenRetry;
985 return rc;
986}
987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988int
989CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
990 const char *fileName, const int openDisposition,
991 const int access_flags, const int create_options, __u16 * netfid,
992 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700993 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994{
995 int rc = -EACCES;
996 OPEN_REQ *pSMB = NULL;
997 OPEN_RSP *pSMBr = NULL;
998 int bytes_returned;
999 int name_len;
1000 __u16 count;
1001
1002openRetry:
1003 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1004 (void **) &pSMBr);
1005 if (rc)
1006 return rc;
1007
1008 pSMB->AndXCommand = 0xFF; /* none */
1009
1010 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1011 count = 1; /* account for one byte pad to word boundary */
1012 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001013 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001014 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 name_len++; /* trailing null */
1016 name_len *= 2;
1017 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001018 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 count = 0; /* no pad */
1020 name_len = strnlen(fileName, PATH_MAX);
1021 name_len++; /* trailing null */
1022 pSMB->NameLength = cpu_to_le16(name_len);
1023 strncpy(pSMB->fileName, fileName, name_len);
1024 }
1025 if (*pOplock & REQ_OPLOCK)
1026 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1027 else if (*pOplock & REQ_BATCHOPLOCK) {
1028 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1029 }
1030 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1031 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001032 /* set file as system file if special file such
1033 as fifo and server expecting SFU style and
1034 no Unix extensions */
1035 if(create_options & CREATE_OPTION_SPECIAL)
1036 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1037 else
1038 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 /* XP does not handle ATTR_POSIX_SEMANTICS */
1040 /* but it helps speed up case sensitive checks for other
1041 servers such as Samba */
1042 if (tcon->ses->capabilities & CAP_UNIX)
1043 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1044
1045 /* if ((omode & S_IWUGO) == 0)
1046 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1047 /* Above line causes problems due to vfs splitting create into two
1048 pieces - need to set mode after file created not while it is
1049 being created */
1050 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1051 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001052 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001053 /* BB Expirement with various impersonation levels and verify */
1054 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 pSMB->SecurityFlags =
1056 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1057
1058 count += name_len;
1059 pSMB->hdr.smb_buf_length += count;
1060
1061 pSMB->ByteCount = cpu_to_le16(count);
1062 /* long_op set to 1 to allow for oplock break timeouts */
1063 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1064 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001065 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 if (rc) {
1067 cFYI(1, ("Error in Open = %d", rc));
1068 } else {
Steve French09d1db52005-04-28 22:41:08 -07001069 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1071 /* Let caller know file was created so we can set the mode. */
1072 /* Do we care about the CreateAction in any other cases? */
1073 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1074 *pOplock |= CIFS_CREATE_ACTION;
1075 if(pfile_info) {
1076 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1077 36 /* CreationTime to Attributes */);
1078 /* the file_info buf is endian converted by caller */
1079 pfile_info->AllocationSize = pSMBr->AllocationSize;
1080 pfile_info->EndOfFile = pSMBr->EndOfFile;
1081 pfile_info->NumberOfLinks = cpu_to_le32(1);
1082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 cifs_buf_release(pSMB);
1086 if (rc == -EAGAIN)
1087 goto openRetry;
1088 return rc;
1089}
1090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091int
1092CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001093 const int netfid, const unsigned int count,
1094 const __u64 lseek, unsigned int *nbytes, char **buf,
1095 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096{
1097 int rc = -EACCES;
1098 READ_REQ *pSMB = NULL;
1099 READ_RSP *pSMBr = NULL;
1100 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001101 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001102 int resp_buf_type = 0;
1103 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001106 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1107 wct = 12;
1108 else
1109 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
1111 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001112 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 if (rc)
1114 return rc;
1115
1116 /* tcon and ses pointer are checked in smb_init */
1117 if (tcon->ses->server == NULL)
1118 return -ECONNABORTED;
1119
Steve Frenchec637e32005-12-12 20:53:18 -08001120 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 pSMB->Fid = netfid;
1122 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001123 if(wct == 12)
1124 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001125 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1126 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 pSMB->Remaining = 0;
1129 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1130 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001131 if(wct == 12)
1132 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1133 else {
1134 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001135 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001136 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001137 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001138 }
Steve Frenchec637e32005-12-12 20:53:18 -08001139
1140 iov[0].iov_base = (char *)pSMB;
1141 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1142 rc = SendReceive2(xid, tcon->ses, iov,
1143 1 /* num iovecs */,
1144 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001145 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001146 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 if (rc) {
1148 cERROR(1, ("Send error in read = %d", rc));
1149 } else {
1150 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1151 data_length = data_length << 16;
1152 data_length += le16_to_cpu(pSMBr->DataLength);
1153 *nbytes = data_length;
1154
1155 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001156 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 || (data_length > count)) {
1158 cFYI(1,("bad length %d for count %d",data_length,count));
1159 rc = -EIO;
1160 *nbytes = 0;
1161 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001162 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001164/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1165 cERROR(1,("Faulting on read rc = %d",rc));
1166 rc = -EFAULT;
1167 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001169 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
1171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
Steve French4b8f9302006-02-26 16:41:18 +00001173/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001174 if(*buf) {
1175 if(resp_buf_type == CIFS_SMALL_BUFFER)
1176 cifs_small_buf_release(iov[0].iov_base);
1177 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1178 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001179 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1180 /* return buffer to caller to free */
1181 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001182 if(resp_buf_type == CIFS_SMALL_BUFFER)
1183 *pbuf_type = CIFS_SMALL_BUFFER;
1184 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1185 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001186 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001187
1188 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 since file handle passed in no longer valid */
1190 return rc;
1191}
1192
Steve Frenchec637e32005-12-12 20:53:18 -08001193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194int
1195CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1196 const int netfid, const unsigned int count,
1197 const __u64 offset, unsigned int *nbytes, const char *buf,
1198 const char __user * ubuf, const int long_op)
1199{
1200 int rc = -EACCES;
1201 WRITE_REQ *pSMB = NULL;
1202 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001203 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 __u32 bytes_sent;
1205 __u16 byte_count;
1206
1207 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001208 if(tcon->ses == NULL)
1209 return -ECONNABORTED;
1210
1211 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1212 wct = 14;
1213 else
1214 wct = 12;
1215
1216 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 (void **) &pSMBr);
1218 if (rc)
1219 return rc;
1220 /* tcon and ses pointer are checked in smb_init */
1221 if (tcon->ses->server == NULL)
1222 return -ECONNABORTED;
1223
1224 pSMB->AndXCommand = 0xFF; /* none */
1225 pSMB->Fid = netfid;
1226 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001227 if(wct == 14)
1228 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1229 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1230 return -EIO;
1231
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 pSMB->Reserved = 0xFFFFFFFF;
1233 pSMB->WriteMode = 0;
1234 pSMB->Remaining = 0;
1235
1236 /* Can increase buffer size if buffer is big enough in some cases - ie we
1237 can send more if LARGE_WRITE_X capability returned by the server and if
1238 our buffer is big enough or if we convert to iovecs on socket writes
1239 and eliminate the copy to the CIFS buffer */
1240 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1241 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1242 } else {
1243 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1244 & ~0xFF;
1245 }
1246
1247 if (bytes_sent > count)
1248 bytes_sent = count;
1249 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001250 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if(buf)
1252 memcpy(pSMB->Data,buf,bytes_sent);
1253 else if(ubuf) {
1254 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1255 cifs_buf_release(pSMB);
1256 return -EFAULT;
1257 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001258 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 /* No buffer */
1260 cifs_buf_release(pSMB);
1261 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001262 } /* else setting file size with write of zero bytes */
1263 if(wct == 14)
1264 byte_count = bytes_sent + 1; /* pad */
1265 else /* wct == 12 */ {
1266 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1269 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001270 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001271
1272 if(wct == 14)
1273 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001274 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001275 struct smb_com_writex_req * pSMBW =
1276 (struct smb_com_writex_req *)pSMB;
1277 pSMBW->ByteCount = cpu_to_le16(byte_count);
1278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
1280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1281 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001282 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 if (rc) {
1284 cFYI(1, ("Send error in write = %d", rc));
1285 *nbytes = 0;
1286 } else {
1287 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1288 *nbytes = (*nbytes) << 16;
1289 *nbytes += le16_to_cpu(pSMBr->Count);
1290 }
1291
1292 cifs_buf_release(pSMB);
1293
1294 /* Note: On -EAGAIN error only caller can retry on handle based calls
1295 since file handle passed in no longer valid */
1296
1297 return rc;
1298}
1299
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001300int
1301CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001303 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1304 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305{
1306 int rc = -EACCES;
1307 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001308 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001309 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001310 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Steve Frenchff7feac2005-11-15 16:45:16 -08001312 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1313
Steve French8cc64c62005-10-03 13:49:43 -07001314 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1315 wct = 14;
1316 else
1317 wct = 12;
1318 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (rc)
1320 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 /* tcon and ses pointer are checked in smb_init */
1322 if (tcon->ses->server == NULL)
1323 return -ECONNABORTED;
1324
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001325 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 pSMB->Fid = netfid;
1327 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001328 if(wct == 14)
1329 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1330 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1331 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 pSMB->Reserved = 0xFFFFFFFF;
1333 pSMB->WriteMode = 0;
1334 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 pSMB->DataOffset =
1337 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1338
Steve French3e844692005-10-03 13:37:24 -07001339 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1340 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001341 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001342 if(wct == 14)
1343 pSMB->hdr.smb_buf_length += count+1;
1344 else /* wct == 12 */
1345 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1346 if(wct == 14)
1347 pSMB->ByteCount = cpu_to_le16(count + 1);
1348 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1349 struct smb_com_writex_req * pSMBW =
1350 (struct smb_com_writex_req *)pSMB;
1351 pSMBW->ByteCount = cpu_to_le16(count + 5);
1352 }
Steve French3e844692005-10-03 13:37:24 -07001353 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001354 if(wct == 14)
1355 iov[0].iov_len = smb_hdr_len + 4;
1356 else /* wct == 12 pad bigger by four bytes */
1357 iov[0].iov_len = smb_hdr_len + 8;
1358
Steve French3e844692005-10-03 13:37:24 -07001359
Steve Frenchec637e32005-12-12 20:53:18 -08001360 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001361 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001362 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001364 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001366 } else if(resp_buf_type == 0) {
1367 /* presumably this can not happen, but best to be safe */
1368 rc = -EIO;
1369 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001370 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001371 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001372 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1373 *nbytes = (*nbytes) << 16;
1374 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Steve French4b8f9302006-02-26 16:41:18 +00001377/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001378 if(resp_buf_type == CIFS_SMALL_BUFFER)
1379 cifs_small_buf_release(iov[0].iov_base);
1380 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1381 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 /* Note: On -EAGAIN error only caller can retry on handle based calls
1384 since file handle passed in no longer valid */
1385
1386 return rc;
1387}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001388
1389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390int
1391CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1392 const __u16 smb_file_id, const __u64 len,
1393 const __u64 offset, const __u32 numUnlock,
1394 const __u32 numLock, const __u8 lockType, const int waitFlag)
1395{
1396 int rc = 0;
1397 LOCK_REQ *pSMB = NULL;
1398 LOCK_RSP *pSMBr = NULL;
1399 int bytes_returned;
1400 int timeout = 0;
1401 __u16 count;
1402
1403 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001404 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1405
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (rc)
1407 return rc;
1408
Steve French46810cb2005-04-28 22:41:09 -07001409 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1410
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1412 timeout = -1; /* no response expected */
1413 pSMB->Timeout = 0;
1414 } else if (waitFlag == TRUE) {
1415 timeout = 3; /* blocking operation, no timeout */
1416 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1417 } else {
1418 pSMB->Timeout = 0;
1419 }
1420
1421 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1422 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1423 pSMB->LockType = lockType;
1424 pSMB->AndXCommand = 0xFF; /* none */
1425 pSMB->Fid = smb_file_id; /* netfid stays le */
1426
1427 if((numLock != 0) || (numUnlock != 0)) {
1428 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1429 /* BB where to store pid high? */
1430 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1431 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1432 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1433 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1434 count = sizeof(LOCKING_ANDX_RANGE);
1435 } else {
1436 /* oplock break */
1437 count = 0;
1438 }
1439 pSMB->hdr.smb_buf_length += count;
1440 pSMB->ByteCount = cpu_to_le16(count);
1441
1442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1443 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001444 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 if (rc) {
1446 cFYI(1, ("Send error in Lock = %d", rc));
1447 }
Steve French46810cb2005-04-28 22:41:09 -07001448 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
1450 /* Note: On -EAGAIN error only caller can retry on handle based calls
1451 since file handle passed in no longer valid */
1452 return rc;
1453}
1454
1455int
Steve French08547b02006-02-28 22:39:25 +00001456CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1457 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001458 struct file_lock *pLockData, const __u16 lock_type,
1459 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001460{
1461 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1462 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1463 char *data_offset;
1464 struct cifs_posix_lock *parm_data;
1465 int rc = 0;
1466 int bytes_returned = 0;
1467 __u16 params, param_offset, offset, byte_count, count;
1468
1469 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001470
1471 if(pLockData == NULL)
1472 return EINVAL;
1473
Steve French08547b02006-02-28 22:39:25 +00001474 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1475
1476 if (rc)
1477 return rc;
1478
1479 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1480
1481 params = 6;
1482 pSMB->MaxSetupCount = 0;
1483 pSMB->Reserved = 0;
1484 pSMB->Flags = 0;
1485 pSMB->Timeout = 0;
1486 pSMB->Reserved2 = 0;
1487 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1488 offset = param_offset + params;
1489
1490 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1491
1492 count = sizeof(struct cifs_posix_lock);
1493 pSMB->MaxParameterCount = cpu_to_le16(2);
1494 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1495 pSMB->SetupCount = 1;
1496 pSMB->Reserved3 = 0;
1497 if(get_flag)
1498 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1499 else
1500 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1501 byte_count = 3 /* pad */ + params + count;
1502 pSMB->DataCount = cpu_to_le16(count);
1503 pSMB->ParameterCount = cpu_to_le16(params);
1504 pSMB->TotalDataCount = pSMB->DataCount;
1505 pSMB->TotalParameterCount = pSMB->ParameterCount;
1506 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1507 parm_data = (struct cifs_posix_lock *)
1508 (((char *) &pSMB->hdr.Protocol) + offset);
1509
1510 parm_data->lock_type = cpu_to_le16(lock_type);
1511 if(waitFlag)
Steve Frenchcec6815a2006-05-30 18:07:17 +00001512 parm_data->lock_flags = cpu_to_le16(1);
Steve French08547b02006-02-28 22:39:25 +00001513 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001514 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001515 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001516
1517 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001518 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001519 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1520 pSMB->Reserved4 = 0;
1521 pSMB->hdr.smb_buf_length += byte_count;
1522 pSMB->ByteCount = cpu_to_le16(byte_count);
1523 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1524 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1525 if (rc) {
1526 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001527 } else if (get_flag) {
1528 /* lock structure can be returned on get */
1529 __u16 data_offset;
1530 __u16 data_count;
1531 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001532
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001533 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1534 rc = -EIO; /* bad smb */
1535 goto plk_err_exit;
1536 }
1537 if(pLockData == NULL) {
1538 rc = -EINVAL;
1539 goto plk_err_exit;
1540 }
1541 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1542 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1543 if(data_count < sizeof(struct cifs_posix_lock)) {
1544 rc = -EIO;
1545 goto plk_err_exit;
1546 }
1547 parm_data = (struct cifs_posix_lock *)
1548 ((char *)&pSMBr->hdr.Protocol + data_offset);
1549 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1550 pLockData->fl_type = F_UNLCK;
1551 }
1552
1553plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001554 if (pSMB)
1555 cifs_small_buf_release(pSMB);
1556
1557 /* Note: On -EAGAIN error only caller can retry on handle based calls
1558 since file handle passed in no longer valid */
1559
1560 return rc;
1561}
1562
1563
1564int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1566{
1567 int rc = 0;
1568 CLOSE_REQ *pSMB = NULL;
1569 CLOSE_RSP *pSMBr = NULL;
1570 int bytes_returned;
1571 cFYI(1, ("In CIFSSMBClose"));
1572
1573/* do not retry on dead session on close */
1574 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1575 if(rc == -EAGAIN)
1576 return 0;
1577 if (rc)
1578 return rc;
1579
1580 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1581
1582 pSMB->FileID = (__u16) smb_file_id;
1583 pSMB->LastWriteTime = 0;
1584 pSMB->ByteCount = 0;
1585 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1586 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001587 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 if (rc) {
1589 if(rc!=-EINTR) {
1590 /* EINTR is expected when user ctl-c to kill app */
1591 cERROR(1, ("Send error in Close = %d", rc));
1592 }
1593 }
1594
1595 cifs_small_buf_release(pSMB);
1596
1597 /* Since session is dead, file will be closed on server already */
1598 if(rc == -EAGAIN)
1599 rc = 0;
1600
1601 return rc;
1602}
1603
1604int
1605CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1606 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001607 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
1609 int rc = 0;
1610 RENAME_REQ *pSMB = NULL;
1611 RENAME_RSP *pSMBr = NULL;
1612 int bytes_returned;
1613 int name_len, name_len2;
1614 __u16 count;
1615
1616 cFYI(1, ("In CIFSSMBRename"));
1617renameRetry:
1618 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1619 (void **) &pSMBr);
1620 if (rc)
1621 return rc;
1622
1623 pSMB->BufferFormat = 0x04;
1624 pSMB->SearchAttributes =
1625 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1626 ATTR_DIRECTORY);
1627
1628 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1629 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001630 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001631 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 name_len++; /* trailing null */
1633 name_len *= 2;
1634 pSMB->OldFileName[name_len] = 0x04; /* pad */
1635 /* protocol requires ASCII signature byte on Unicode string */
1636 pSMB->OldFileName[name_len + 1] = 0x00;
1637 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001638 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001639 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1641 name_len2 *= 2; /* convert to bytes */
1642 } else { /* BB improve the check for buffer overruns BB */
1643 name_len = strnlen(fromName, PATH_MAX);
1644 name_len++; /* trailing null */
1645 strncpy(pSMB->OldFileName, fromName, name_len);
1646 name_len2 = strnlen(toName, PATH_MAX);
1647 name_len2++; /* trailing null */
1648 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1649 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1650 name_len2++; /* trailing null */
1651 name_len2++; /* signature byte */
1652 }
1653
1654 count = 1 /* 1st signature byte */ + name_len + name_len2;
1655 pSMB->hdr.smb_buf_length += count;
1656 pSMB->ByteCount = cpu_to_le16(count);
1657
1658 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1659 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001660 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 if (rc) {
1662 cFYI(1, ("Send error in rename = %d", rc));
1663 }
1664
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 cifs_buf_release(pSMB);
1666
1667 if (rc == -EAGAIN)
1668 goto renameRetry;
1669
1670 return rc;
1671}
1672
1673int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001674 int netfid, char * target_name,
1675 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676{
1677 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1678 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1679 struct set_file_rename * rename_info;
1680 char *data_offset;
1681 char dummy_string[30];
1682 int rc = 0;
1683 int bytes_returned = 0;
1684 int len_of_str;
1685 __u16 params, param_offset, offset, count, byte_count;
1686
1687 cFYI(1, ("Rename to File by handle"));
1688 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1689 (void **) &pSMBr);
1690 if (rc)
1691 return rc;
1692
1693 params = 6;
1694 pSMB->MaxSetupCount = 0;
1695 pSMB->Reserved = 0;
1696 pSMB->Flags = 0;
1697 pSMB->Timeout = 0;
1698 pSMB->Reserved2 = 0;
1699 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1700 offset = param_offset + params;
1701
1702 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1703 rename_info = (struct set_file_rename *) data_offset;
1704 pSMB->MaxParameterCount = cpu_to_le16(2);
1705 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1706 pSMB->SetupCount = 1;
1707 pSMB->Reserved3 = 0;
1708 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1709 byte_count = 3 /* pad */ + params;
1710 pSMB->ParameterCount = cpu_to_le16(params);
1711 pSMB->TotalParameterCount = pSMB->ParameterCount;
1712 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1713 pSMB->DataOffset = cpu_to_le16(offset);
1714 /* construct random name ".cifs_tmp<inodenum><mid>" */
1715 rename_info->overwrite = cpu_to_le32(1);
1716 rename_info->root_fid = 0;
1717 /* unicode only call */
1718 if(target_name == NULL) {
1719 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001720 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001721 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001723 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001724 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 }
1726 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1727 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1728 byte_count += count;
1729 pSMB->DataCount = cpu_to_le16(count);
1730 pSMB->TotalDataCount = pSMB->DataCount;
1731 pSMB->Fid = netfid;
1732 pSMB->InformationLevel =
1733 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1734 pSMB->Reserved4 = 0;
1735 pSMB->hdr.smb_buf_length += byte_count;
1736 pSMB->ByteCount = cpu_to_le16(byte_count);
1737 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1738 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001739 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 if (rc) {
1741 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1742 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001743
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 cifs_buf_release(pSMB);
1745
1746 /* Note: On -EAGAIN error only caller can retry on handle based calls
1747 since file handle passed in no longer valid */
1748
1749 return rc;
1750}
1751
1752int
1753CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1754 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001755 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
1757 int rc = 0;
1758 COPY_REQ *pSMB = NULL;
1759 COPY_RSP *pSMBr = NULL;
1760 int bytes_returned;
1761 int name_len, name_len2;
1762 __u16 count;
1763
1764 cFYI(1, ("In CIFSSMBCopy"));
1765copyRetry:
1766 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1767 (void **) &pSMBr);
1768 if (rc)
1769 return rc;
1770
1771 pSMB->BufferFormat = 0x04;
1772 pSMB->Tid2 = target_tid;
1773
1774 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1775
1776 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001777 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001778 fromName, PATH_MAX, nls_codepage,
1779 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 name_len++; /* trailing null */
1781 name_len *= 2;
1782 pSMB->OldFileName[name_len] = 0x04; /* pad */
1783 /* protocol requires ASCII signature byte on Unicode string */
1784 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001785 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001786 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1788 name_len2 *= 2; /* convert to bytes */
1789 } else { /* BB improve the check for buffer overruns BB */
1790 name_len = strnlen(fromName, PATH_MAX);
1791 name_len++; /* trailing null */
1792 strncpy(pSMB->OldFileName, fromName, name_len);
1793 name_len2 = strnlen(toName, PATH_MAX);
1794 name_len2++; /* trailing null */
1795 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1796 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1797 name_len2++; /* trailing null */
1798 name_len2++; /* signature byte */
1799 }
1800
1801 count = 1 /* 1st signature byte */ + name_len + name_len2;
1802 pSMB->hdr.smb_buf_length += count;
1803 pSMB->ByteCount = cpu_to_le16(count);
1804
1805 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1806 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1807 if (rc) {
1808 cFYI(1, ("Send error in copy = %d with %d files copied",
1809 rc, le16_to_cpu(pSMBr->CopyCount)));
1810 }
1811 if (pSMB)
1812 cifs_buf_release(pSMB);
1813
1814 if (rc == -EAGAIN)
1815 goto copyRetry;
1816
1817 return rc;
1818}
1819
1820int
1821CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1822 const char *fromName, const char *toName,
1823 const struct nls_table *nls_codepage)
1824{
1825 TRANSACTION2_SPI_REQ *pSMB = NULL;
1826 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1827 char *data_offset;
1828 int name_len;
1829 int name_len_target;
1830 int rc = 0;
1831 int bytes_returned = 0;
1832 __u16 params, param_offset, offset, byte_count;
1833
1834 cFYI(1, ("In Symlink Unix style"));
1835createSymLinkRetry:
1836 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1837 (void **) &pSMBr);
1838 if (rc)
1839 return rc;
1840
1841 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1842 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001843 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* find define for this maxpathcomponent */
1845 , nls_codepage);
1846 name_len++; /* trailing null */
1847 name_len *= 2;
1848
1849 } else { /* BB improve the check for buffer overruns BB */
1850 name_len = strnlen(fromName, PATH_MAX);
1851 name_len++; /* trailing null */
1852 strncpy(pSMB->FileName, fromName, name_len);
1853 }
1854 params = 6 + name_len;
1855 pSMB->MaxSetupCount = 0;
1856 pSMB->Reserved = 0;
1857 pSMB->Flags = 0;
1858 pSMB->Timeout = 0;
1859 pSMB->Reserved2 = 0;
1860 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1861 InformationLevel) - 4;
1862 offset = param_offset + params;
1863
1864 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1866 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001867 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 /* find define for this maxpathcomponent */
1869 , nls_codepage);
1870 name_len_target++; /* trailing null */
1871 name_len_target *= 2;
1872 } else { /* BB improve the check for buffer overruns BB */
1873 name_len_target = strnlen(toName, PATH_MAX);
1874 name_len_target++; /* trailing null */
1875 strncpy(data_offset, toName, name_len_target);
1876 }
1877
1878 pSMB->MaxParameterCount = cpu_to_le16(2);
1879 /* BB find exact max on data count below from sess */
1880 pSMB->MaxDataCount = cpu_to_le16(1000);
1881 pSMB->SetupCount = 1;
1882 pSMB->Reserved3 = 0;
1883 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1884 byte_count = 3 /* pad */ + params + name_len_target;
1885 pSMB->DataCount = cpu_to_le16(name_len_target);
1886 pSMB->ParameterCount = cpu_to_le16(params);
1887 pSMB->TotalDataCount = pSMB->DataCount;
1888 pSMB->TotalParameterCount = pSMB->ParameterCount;
1889 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1890 pSMB->DataOffset = cpu_to_le16(offset);
1891 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1892 pSMB->Reserved4 = 0;
1893 pSMB->hdr.smb_buf_length += byte_count;
1894 pSMB->ByteCount = cpu_to_le16(byte_count);
1895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001897 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 if (rc) {
1899 cFYI(1,
1900 ("Send error in SetPathInfo (create symlink) = %d",
1901 rc));
1902 }
1903
1904 if (pSMB)
1905 cifs_buf_release(pSMB);
1906
1907 if (rc == -EAGAIN)
1908 goto createSymLinkRetry;
1909
1910 return rc;
1911}
1912
1913int
1914CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1915 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001916 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917{
1918 TRANSACTION2_SPI_REQ *pSMB = NULL;
1919 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1920 char *data_offset;
1921 int name_len;
1922 int name_len_target;
1923 int rc = 0;
1924 int bytes_returned = 0;
1925 __u16 params, param_offset, offset, byte_count;
1926
1927 cFYI(1, ("In Create Hard link Unix style"));
1928createHardLinkRetry:
1929 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1930 (void **) &pSMBr);
1931 if (rc)
1932 return rc;
1933
1934 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001935 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001936 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 name_len++; /* trailing null */
1938 name_len *= 2;
1939
1940 } else { /* BB improve the check for buffer overruns BB */
1941 name_len = strnlen(toName, PATH_MAX);
1942 name_len++; /* trailing null */
1943 strncpy(pSMB->FileName, toName, name_len);
1944 }
1945 params = 6 + name_len;
1946 pSMB->MaxSetupCount = 0;
1947 pSMB->Reserved = 0;
1948 pSMB->Flags = 0;
1949 pSMB->Timeout = 0;
1950 pSMB->Reserved2 = 0;
1951 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1952 InformationLevel) - 4;
1953 offset = param_offset + params;
1954
1955 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1956 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1957 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001958 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001959 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 name_len_target++; /* trailing null */
1961 name_len_target *= 2;
1962 } else { /* BB improve the check for buffer overruns BB */
1963 name_len_target = strnlen(fromName, PATH_MAX);
1964 name_len_target++; /* trailing null */
1965 strncpy(data_offset, fromName, name_len_target);
1966 }
1967
1968 pSMB->MaxParameterCount = cpu_to_le16(2);
1969 /* BB find exact max on data count below from sess*/
1970 pSMB->MaxDataCount = cpu_to_le16(1000);
1971 pSMB->SetupCount = 1;
1972 pSMB->Reserved3 = 0;
1973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1974 byte_count = 3 /* pad */ + params + name_len_target;
1975 pSMB->ParameterCount = cpu_to_le16(params);
1976 pSMB->TotalParameterCount = pSMB->ParameterCount;
1977 pSMB->DataCount = cpu_to_le16(name_len_target);
1978 pSMB->TotalDataCount = pSMB->DataCount;
1979 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1980 pSMB->DataOffset = cpu_to_le16(offset);
1981 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1982 pSMB->Reserved4 = 0;
1983 pSMB->hdr.smb_buf_length += byte_count;
1984 pSMB->ByteCount = cpu_to_le16(byte_count);
1985 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1986 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001987 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 if (rc) {
1989 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1990 }
1991
1992 cifs_buf_release(pSMB);
1993 if (rc == -EAGAIN)
1994 goto createHardLinkRetry;
1995
1996 return rc;
1997}
1998
1999int
2000CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2001 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002002 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003{
2004 int rc = 0;
2005 NT_RENAME_REQ *pSMB = NULL;
2006 RENAME_RSP *pSMBr = NULL;
2007 int bytes_returned;
2008 int name_len, name_len2;
2009 __u16 count;
2010
2011 cFYI(1, ("In CIFSCreateHardLink"));
2012winCreateHardLinkRetry:
2013
2014 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2015 (void **) &pSMBr);
2016 if (rc)
2017 return rc;
2018
2019 pSMB->SearchAttributes =
2020 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2021 ATTR_DIRECTORY);
2022 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2023 pSMB->ClusterCount = 0;
2024
2025 pSMB->BufferFormat = 0x04;
2026
2027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2028 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002029 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002030 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 name_len++; /* trailing null */
2032 name_len *= 2;
2033 pSMB->OldFileName[name_len] = 0; /* pad */
2034 pSMB->OldFileName[name_len + 1] = 0x04;
2035 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002036 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002037 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2039 name_len2 *= 2; /* convert to bytes */
2040 } else { /* BB improve the check for buffer overruns BB */
2041 name_len = strnlen(fromName, PATH_MAX);
2042 name_len++; /* trailing null */
2043 strncpy(pSMB->OldFileName, fromName, name_len);
2044 name_len2 = strnlen(toName, PATH_MAX);
2045 name_len2++; /* trailing null */
2046 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2047 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2048 name_len2++; /* trailing null */
2049 name_len2++; /* signature byte */
2050 }
2051
2052 count = 1 /* string type byte */ + name_len + name_len2;
2053 pSMB->hdr.smb_buf_length += count;
2054 pSMB->ByteCount = cpu_to_le16(count);
2055
2056 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2057 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002058 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 if (rc) {
2060 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2061 }
2062 cifs_buf_release(pSMB);
2063 if (rc == -EAGAIN)
2064 goto winCreateHardLinkRetry;
2065
2066 return rc;
2067}
2068
2069int
2070CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2071 const unsigned char *searchName,
2072 char *symlinkinfo, const int buflen,
2073 const struct nls_table *nls_codepage)
2074{
2075/* SMB_QUERY_FILE_UNIX_LINK */
2076 TRANSACTION2_QPI_REQ *pSMB = NULL;
2077 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2078 int rc = 0;
2079 int bytes_returned;
2080 int name_len;
2081 __u16 params, byte_count;
2082
2083 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2084
2085querySymLinkRetry:
2086 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2087 (void **) &pSMBr);
2088 if (rc)
2089 return rc;
2090
2091 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2092 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002093 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 /* find define for this maxpathcomponent */
2095 , nls_codepage);
2096 name_len++; /* trailing null */
2097 name_len *= 2;
2098 } else { /* BB improve the check for buffer overruns BB */
2099 name_len = strnlen(searchName, PATH_MAX);
2100 name_len++; /* trailing null */
2101 strncpy(pSMB->FileName, searchName, name_len);
2102 }
2103
2104 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2105 pSMB->TotalDataCount = 0;
2106 pSMB->MaxParameterCount = cpu_to_le16(2);
2107 /* BB find exact max data count below from sess structure BB */
2108 pSMB->MaxDataCount = cpu_to_le16(4000);
2109 pSMB->MaxSetupCount = 0;
2110 pSMB->Reserved = 0;
2111 pSMB->Flags = 0;
2112 pSMB->Timeout = 0;
2113 pSMB->Reserved2 = 0;
2114 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2115 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2116 pSMB->DataCount = 0;
2117 pSMB->DataOffset = 0;
2118 pSMB->SetupCount = 1;
2119 pSMB->Reserved3 = 0;
2120 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2121 byte_count = params + 1 /* pad */ ;
2122 pSMB->TotalParameterCount = cpu_to_le16(params);
2123 pSMB->ParameterCount = pSMB->TotalParameterCount;
2124 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2125 pSMB->Reserved4 = 0;
2126 pSMB->hdr.smb_buf_length += byte_count;
2127 pSMB->ByteCount = cpu_to_le16(byte_count);
2128
2129 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2130 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2131 if (rc) {
2132 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2133 } else {
2134 /* decode response */
2135
2136 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2137 if (rc || (pSMBr->ByteCount < 2))
2138 /* BB also check enough total bytes returned */
2139 rc = -EIO; /* bad smb */
2140 else {
2141 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2142 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2143
2144 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2145 name_len = UniStrnlen((wchar_t *) ((char *)
2146 &pSMBr->hdr.Protocol +data_offset),
2147 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002148 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002150 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 data_offset),
2152 name_len, nls_codepage);
2153 } else {
2154 strncpy(symlinkinfo,
2155 (char *) &pSMBr->hdr.Protocol +
2156 data_offset,
2157 min_t(const int, buflen, count));
2158 }
2159 symlinkinfo[buflen] = 0;
2160 /* just in case so calling code does not go off the end of buffer */
2161 }
2162 }
2163 cifs_buf_release(pSMB);
2164 if (rc == -EAGAIN)
2165 goto querySymLinkRetry;
2166 return rc;
2167}
2168
Steve French0a4b92c2006-01-12 15:44:21 -08002169/* Initialize NT TRANSACT SMB into small smb request buffer.
2170 This assumes that all NT TRANSACTS that we init here have
2171 total parm and data under about 400 bytes (to fit in small cifs
2172 buffer size), which is the case so far, it easily fits. NB:
2173 Setup words themselves and ByteCount
2174 MaxSetupCount (size of returned setup area) and
2175 MaxParameterCount (returned parms size) must be set by caller */
2176static int
2177smb_init_ntransact(const __u16 sub_command, const int setup_count,
2178 const int parm_len, struct cifsTconInfo *tcon,
2179 void ** ret_buf)
2180{
2181 int rc;
2182 __u32 temp_offset;
2183 struct smb_com_ntransact_req * pSMB;
2184
2185 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2186 (void **)&pSMB);
2187 if (rc)
2188 return rc;
2189 *ret_buf = (void *)pSMB;
2190 pSMB->Reserved = 0;
2191 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2192 pSMB->TotalDataCount = 0;
2193 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2194 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2195 pSMB->ParameterCount = pSMB->TotalParameterCount;
2196 pSMB->DataCount = pSMB->TotalDataCount;
2197 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2198 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2199 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2200 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2201 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2202 pSMB->SubCommand = cpu_to_le16(sub_command);
2203 return 0;
2204}
2205
2206static int
2207validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2208 int * pdatalen, int * pparmlen)
2209{
2210 char * end_of_smb;
2211 __u32 data_count, data_offset, parm_count, parm_offset;
2212 struct smb_com_ntransact_rsp * pSMBr;
2213
2214 if(buf == NULL)
2215 return -EINVAL;
2216
2217 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2218
2219 /* ByteCount was converted from little endian in SendReceive */
2220 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2221 (char *)&pSMBr->ByteCount;
2222
2223
2224 data_offset = le32_to_cpu(pSMBr->DataOffset);
2225 data_count = le32_to_cpu(pSMBr->DataCount);
2226 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2227 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2228
2229 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2230 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2231
2232 /* should we also check that parm and data areas do not overlap? */
2233 if(*ppparm > end_of_smb) {
2234 cFYI(1,("parms start after end of smb"));
2235 return -EINVAL;
2236 } else if(parm_count + *ppparm > end_of_smb) {
2237 cFYI(1,("parm end after end of smb"));
2238 return -EINVAL;
2239 } else if(*ppdata > end_of_smb) {
2240 cFYI(1,("data starts after end of smb"));
2241 return -EINVAL;
2242 } else if(data_count + *ppdata > end_of_smb) {
2243 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2244 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2245 return -EINVAL;
2246 } else if(parm_count + data_count > pSMBr->ByteCount) {
2247 cFYI(1,("parm count and data count larger than SMB"));
2248 return -EINVAL;
2249 }
2250 return 0;
2251}
2252
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253int
2254CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2255 const unsigned char *searchName,
2256 char *symlinkinfo, const int buflen,__u16 fid,
2257 const struct nls_table *nls_codepage)
2258{
2259 int rc = 0;
2260 int bytes_returned;
2261 int name_len;
2262 struct smb_com_transaction_ioctl_req * pSMB;
2263 struct smb_com_transaction_ioctl_rsp * pSMBr;
2264
2265 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2266 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2267 (void **) &pSMBr);
2268 if (rc)
2269 return rc;
2270
2271 pSMB->TotalParameterCount = 0 ;
2272 pSMB->TotalDataCount = 0;
2273 pSMB->MaxParameterCount = cpu_to_le32(2);
2274 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002275 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2276 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 pSMB->MaxSetupCount = 4;
2278 pSMB->Reserved = 0;
2279 pSMB->ParameterOffset = 0;
2280 pSMB->DataCount = 0;
2281 pSMB->DataOffset = 0;
2282 pSMB->SetupCount = 4;
2283 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2284 pSMB->ParameterCount = pSMB->TotalParameterCount;
2285 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2286 pSMB->IsFsctl = 1; /* FSCTL */
2287 pSMB->IsRootFlag = 0;
2288 pSMB->Fid = fid; /* file handle always le */
2289 pSMB->ByteCount = 0;
2290
2291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2292 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2293 if (rc) {
2294 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2295 } else { /* decode response */
2296 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2297 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2298 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2299 /* BB also check enough total bytes returned */
2300 rc = -EIO; /* bad smb */
2301 else {
2302 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002303 char * end_of_smb = 2 /* sizeof byte count */ +
2304 pSMBr->ByteCount +
2305 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 struct reparse_data * reparse_buf = (struct reparse_data *)
2308 ((char *)&pSMBr->hdr.Protocol + data_offset);
2309 if((char*)reparse_buf >= end_of_smb) {
2310 rc = -EIO;
2311 goto qreparse_out;
2312 }
2313 if((reparse_buf->LinkNamesBuf +
2314 reparse_buf->TargetNameOffset +
2315 reparse_buf->TargetNameLen) >
2316 end_of_smb) {
2317 cFYI(1,("reparse buf extended beyond SMB"));
2318 rc = -EIO;
2319 goto qreparse_out;
2320 }
2321
2322 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2323 name_len = UniStrnlen((wchar_t *)
2324 (reparse_buf->LinkNamesBuf +
2325 reparse_buf->TargetNameOffset),
2326 min(buflen/2, reparse_buf->TargetNameLen / 2));
2327 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002328 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 reparse_buf->TargetNameOffset),
2330 name_len, nls_codepage);
2331 } else { /* ASCII names */
2332 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2333 reparse_buf->TargetNameOffset,
2334 min_t(const int, buflen, reparse_buf->TargetNameLen));
2335 }
2336 } else {
2337 rc = -EIO;
2338 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2339 }
2340 symlinkinfo[buflen] = 0; /* just in case so the caller
2341 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002342 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 }
2344 }
2345qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002346 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
2348 /* Note: On -EAGAIN error only caller can retry on handle based calls
2349 since file handle passed in no longer valid */
2350
2351 return rc;
2352}
2353
2354#ifdef CONFIG_CIFS_POSIX
2355
2356/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2357static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2358{
2359 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002360 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2361 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2362 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2364
2365 return;
2366}
2367
2368/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002369static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2370 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371{
2372 int size = 0;
2373 int i;
2374 __u16 count;
2375 struct cifs_posix_ace * pACE;
2376 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2377 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2378
2379 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2380 return -EOPNOTSUPP;
2381
2382 if(acl_type & ACL_TYPE_ACCESS) {
2383 count = le16_to_cpu(cifs_acl->access_entry_count);
2384 pACE = &cifs_acl->ace_array[0];
2385 size = sizeof(struct cifs_posix_acl);
2386 size += sizeof(struct cifs_posix_ace) * count;
2387 /* check if we would go beyond end of SMB */
2388 if(size_of_data_area < size) {
2389 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2390 return -EINVAL;
2391 }
2392 } else if(acl_type & ACL_TYPE_DEFAULT) {
2393 count = le16_to_cpu(cifs_acl->access_entry_count);
2394 size = sizeof(struct cifs_posix_acl);
2395 size += sizeof(struct cifs_posix_ace) * count;
2396/* skip past access ACEs to get to default ACEs */
2397 pACE = &cifs_acl->ace_array[count];
2398 count = le16_to_cpu(cifs_acl->default_entry_count);
2399 size += sizeof(struct cifs_posix_ace) * count;
2400 /* check if we would go beyond end of SMB */
2401 if(size_of_data_area < size)
2402 return -EINVAL;
2403 } else {
2404 /* illegal type */
2405 return -EINVAL;
2406 }
2407
2408 size = posix_acl_xattr_size(count);
2409 if((buflen == 0) || (local_acl == NULL)) {
2410 /* used to query ACL EA size */
2411 } else if(size > buflen) {
2412 return -ERANGE;
2413 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002414 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 for(i = 0;i < count ;i++) {
2416 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2417 pACE ++;
2418 }
2419 }
2420 return size;
2421}
2422
2423static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2424 const posix_acl_xattr_entry * local_ace)
2425{
2426 __u16 rc = 0; /* 0 = ACL converted ok */
2427
Steve Frenchff7feac2005-11-15 16:45:16 -08002428 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2429 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002431 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 /* Probably no need to le convert -1 on any arch but can not hurt */
2433 cifs_ace->cifs_uid = cpu_to_le64(-1);
2434 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002435 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2437 return rc;
2438}
2439
2440/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2441static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2442 const int acl_type)
2443{
2444 __u16 rc = 0;
2445 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2446 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2447 int count;
2448 int i;
2449
2450 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2451 return 0;
2452
2453 count = posix_acl_xattr_count((size_t)buflen);
2454 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002455 count, buflen, le32_to_cpu(local_acl->a_version)));
2456 if(le32_to_cpu(local_acl->a_version) != 2) {
2457 cFYI(1,("unknown POSIX ACL version %d",
2458 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 return 0;
2460 }
2461 cifs_acl->version = cpu_to_le16(1);
2462 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002463 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002465 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 else {
2467 cFYI(1,("unknown ACL type %d",acl_type));
2468 return 0;
2469 }
2470 for(i=0;i<count;i++) {
2471 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2472 &local_acl->a_entries[i]);
2473 if(rc != 0) {
2474 /* ACE not converted */
2475 break;
2476 }
2477 }
2478 if(rc == 0) {
2479 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2480 rc += sizeof(struct cifs_posix_acl);
2481 /* BB add check to make sure ACL does not overflow SMB */
2482 }
2483 return rc;
2484}
2485
2486int
2487CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2488 const unsigned char *searchName,
2489 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002490 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491{
2492/* SMB_QUERY_POSIX_ACL */
2493 TRANSACTION2_QPI_REQ *pSMB = NULL;
2494 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2495 int rc = 0;
2496 int bytes_returned;
2497 int name_len;
2498 __u16 params, byte_count;
2499
2500 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2501
2502queryAclRetry:
2503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2504 (void **) &pSMBr);
2505 if (rc)
2506 return rc;
2507
2508 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2509 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002510 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002511 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 name_len++; /* trailing null */
2513 name_len *= 2;
2514 pSMB->FileName[name_len] = 0;
2515 pSMB->FileName[name_len+1] = 0;
2516 } else { /* BB improve the check for buffer overruns BB */
2517 name_len = strnlen(searchName, PATH_MAX);
2518 name_len++; /* trailing null */
2519 strncpy(pSMB->FileName, searchName, name_len);
2520 }
2521
2522 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2523 pSMB->TotalDataCount = 0;
2524 pSMB->MaxParameterCount = cpu_to_le16(2);
2525 /* BB find exact max data count below from sess structure BB */
2526 pSMB->MaxDataCount = cpu_to_le16(4000);
2527 pSMB->MaxSetupCount = 0;
2528 pSMB->Reserved = 0;
2529 pSMB->Flags = 0;
2530 pSMB->Timeout = 0;
2531 pSMB->Reserved2 = 0;
2532 pSMB->ParameterOffset = cpu_to_le16(
2533 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2534 pSMB->DataCount = 0;
2535 pSMB->DataOffset = 0;
2536 pSMB->SetupCount = 1;
2537 pSMB->Reserved3 = 0;
2538 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2539 byte_count = params + 1 /* pad */ ;
2540 pSMB->TotalParameterCount = cpu_to_le16(params);
2541 pSMB->ParameterCount = pSMB->TotalParameterCount;
2542 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2543 pSMB->Reserved4 = 0;
2544 pSMB->hdr.smb_buf_length += byte_count;
2545 pSMB->ByteCount = cpu_to_le16(byte_count);
2546
2547 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2548 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002549 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 if (rc) {
2551 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2552 } else {
2553 /* decode response */
2554
2555 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2556 if (rc || (pSMBr->ByteCount < 2))
2557 /* BB also check enough total bytes returned */
2558 rc = -EIO; /* bad smb */
2559 else {
2560 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2561 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2562 rc = cifs_copy_posix_acl(acl_inf,
2563 (char *)&pSMBr->hdr.Protocol+data_offset,
2564 buflen,acl_type,count);
2565 }
2566 }
2567 cifs_buf_release(pSMB);
2568 if (rc == -EAGAIN)
2569 goto queryAclRetry;
2570 return rc;
2571}
2572
2573int
2574CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2575 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002576 const char *local_acl, const int buflen,
2577 const int acl_type,
2578 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579{
2580 struct smb_com_transaction2_spi_req *pSMB = NULL;
2581 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2582 char *parm_data;
2583 int name_len;
2584 int rc = 0;
2585 int bytes_returned = 0;
2586 __u16 params, byte_count, data_count, param_offset, offset;
2587
2588 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2589setAclRetry:
2590 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2591 (void **) &pSMBr);
2592 if (rc)
2593 return rc;
2594 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2595 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002596 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002597 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 name_len++; /* trailing null */
2599 name_len *= 2;
2600 } else { /* BB improve the check for buffer overruns BB */
2601 name_len = strnlen(fileName, PATH_MAX);
2602 name_len++; /* trailing null */
2603 strncpy(pSMB->FileName, fileName, name_len);
2604 }
2605 params = 6 + name_len;
2606 pSMB->MaxParameterCount = cpu_to_le16(2);
2607 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2608 pSMB->MaxSetupCount = 0;
2609 pSMB->Reserved = 0;
2610 pSMB->Flags = 0;
2611 pSMB->Timeout = 0;
2612 pSMB->Reserved2 = 0;
2613 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2614 InformationLevel) - 4;
2615 offset = param_offset + params;
2616 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2617 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2618
2619 /* convert to on the wire format for POSIX ACL */
2620 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2621
2622 if(data_count == 0) {
2623 rc = -EOPNOTSUPP;
2624 goto setACLerrorExit;
2625 }
2626 pSMB->DataOffset = cpu_to_le16(offset);
2627 pSMB->SetupCount = 1;
2628 pSMB->Reserved3 = 0;
2629 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2630 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2631 byte_count = 3 /* pad */ + params + data_count;
2632 pSMB->DataCount = cpu_to_le16(data_count);
2633 pSMB->TotalDataCount = pSMB->DataCount;
2634 pSMB->ParameterCount = cpu_to_le16(params);
2635 pSMB->TotalParameterCount = pSMB->ParameterCount;
2636 pSMB->Reserved4 = 0;
2637 pSMB->hdr.smb_buf_length += byte_count;
2638 pSMB->ByteCount = cpu_to_le16(byte_count);
2639 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2640 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2641 if (rc) {
2642 cFYI(1, ("Set POSIX ACL returned %d", rc));
2643 }
2644
2645setACLerrorExit:
2646 cifs_buf_release(pSMB);
2647 if (rc == -EAGAIN)
2648 goto setAclRetry;
2649 return rc;
2650}
2651
Steve Frenchf654bac2005-04-28 22:41:04 -07002652/* BB fix tabs in this function FIXME BB */
2653int
2654CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2655 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2656{
2657 int rc = 0;
2658 struct smb_t2_qfi_req *pSMB = NULL;
2659 struct smb_t2_qfi_rsp *pSMBr = NULL;
2660 int bytes_returned;
2661 __u16 params, byte_count;
2662
2663 cFYI(1,("In GetExtAttr"));
2664 if(tcon == NULL)
2665 return -ENODEV;
2666
2667GetExtAttrRetry:
2668 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2669 (void **) &pSMBr);
2670 if (rc)
2671 return rc;
2672
Steve Frenchc67593a2005-04-28 22:41:04 -07002673 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002674 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002675 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002676 /* BB find exact max data count below from sess structure BB */
2677 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2678 pSMB->t2.MaxSetupCount = 0;
2679 pSMB->t2.Reserved = 0;
2680 pSMB->t2.Flags = 0;
2681 pSMB->t2.Timeout = 0;
2682 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002683 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2684 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002685 pSMB->t2.DataCount = 0;
2686 pSMB->t2.DataOffset = 0;
2687 pSMB->t2.SetupCount = 1;
2688 pSMB->t2.Reserved3 = 0;
2689 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002690 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002691 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2692 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2693 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002694 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002695 pSMB->Fid = netfid;
2696 pSMB->hdr.smb_buf_length += byte_count;
2697 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2698
2699 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2700 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2701 if (rc) {
2702 cFYI(1, ("error %d in GetExtAttr", rc));
2703 } else {
2704 /* decode response */
2705 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2706 if (rc || (pSMBr->ByteCount < 2))
2707 /* BB also check enough total bytes returned */
2708 /* If rc should we check for EOPNOSUPP and
2709 disable the srvino flag? or in caller? */
2710 rc = -EIO; /* bad smb */
2711 else {
2712 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2713 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2714 struct file_chattr_info * pfinfo;
2715 /* BB Do we need a cast or hash here ? */
2716 if(count != 16) {
2717 cFYI(1, ("Illegal size ret in GetExtAttr"));
2718 rc = -EIO;
2719 goto GetExtAttrOut;
2720 }
2721 pfinfo = (struct file_chattr_info *)
2722 (data_offset + (char *) &pSMBr->hdr.Protocol);
2723 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2724 *pMask = le64_to_cpu(pfinfo->mask);
2725 }
2726 }
2727GetExtAttrOut:
2728 cifs_buf_release(pSMB);
2729 if (rc == -EAGAIN)
2730 goto GetExtAttrRetry;
2731 return rc;
2732}
2733
2734
2735#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
Steve Frencheeac8042006-01-13 21:34:58 -08002737
2738/* security id for everyone */
2739const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2740/* group users */
2741const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2742
Steve French0a4b92c2006-01-12 15:44:21 -08002743/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002744static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002745{
Steve French0a4b92c2006-01-12 15:44:21 -08002746 return 0;
2747}
2748
2749/* Get Security Descriptor (by handle) from remote server for a file or dir */
2750int
2751CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2752 /* BB fix up return info */ char *acl_inf, const int buflen,
2753 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2754{
2755 int rc = 0;
2756 int buf_type = 0;
2757 QUERY_SEC_DESC_REQ * pSMB;
2758 struct kvec iov[1];
2759
2760 cFYI(1, ("GetCifsACL"));
2761
2762 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2763 8 /* parm len */, tcon, (void **) &pSMB);
2764 if (rc)
2765 return rc;
2766
2767 pSMB->MaxParameterCount = cpu_to_le32(4);
2768 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2769 pSMB->MaxSetupCount = 0;
2770 pSMB->Fid = fid; /* file handle always le */
2771 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2772 CIFS_ACL_DACL);
2773 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2774 pSMB->hdr.smb_buf_length += 11;
2775 iov[0].iov_base = (char *)pSMB;
2776 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2777
2778 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2779 cifs_stats_inc(&tcon->num_acl_get);
2780 if (rc) {
2781 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2782 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002783 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002784 __le32 * parm;
2785 int parm_len;
2786 int data_len;
2787 int acl_len;
2788 struct smb_com_ntransact_rsp * pSMBr;
2789
2790/* validate_nttransact */
2791 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2792 (char **)&psec_desc,
2793 &parm_len, &data_len);
2794
2795 if(rc)
2796 goto qsec_out;
2797 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2798
2799 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2800
2801 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2802 rc = -EIO; /* bad smb */
2803 goto qsec_out;
2804 }
2805
2806/* BB check that data area is minimum length and as big as acl_len */
2807
2808 acl_len = le32_to_cpu(*(__le32 *)parm);
2809 /* BB check if(acl_len > bufsize) */
2810
2811 parse_sec_desc(psec_desc, acl_len);
2812 }
2813qsec_out:
2814 if(buf_type == CIFS_SMALL_BUFFER)
2815 cifs_small_buf_release(iov[0].iov_base);
2816 else if(buf_type == CIFS_LARGE_BUFFER)
2817 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002818/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002819 return rc;
2820}
2821
2822
Steve French6b8edfe2005-08-23 20:26:03 -07002823/* Legacy Query Path Information call for lookup to old servers such
2824 as Win9x/WinME */
2825int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2826 const unsigned char *searchName,
2827 FILE_ALL_INFO * pFinfo,
2828 const struct nls_table *nls_codepage, int remap)
2829{
2830 QUERY_INFORMATION_REQ * pSMB;
2831 QUERY_INFORMATION_RSP * pSMBr;
2832 int rc = 0;
2833 int bytes_returned;
2834 int name_len;
2835
2836 cFYI(1, ("In SMBQPath path %s", searchName));
2837QInfRetry:
2838 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2839 (void **) &pSMBr);
2840 if (rc)
2841 return rc;
2842
2843 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2844 name_len =
2845 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2846 PATH_MAX, nls_codepage, remap);
2847 name_len++; /* trailing null */
2848 name_len *= 2;
2849 } else {
2850 name_len = strnlen(searchName, PATH_MAX);
2851 name_len++; /* trailing null */
2852 strncpy(pSMB->FileName, searchName, name_len);
2853 }
2854 pSMB->BufferFormat = 0x04;
2855 name_len++; /* account for buffer type byte */
2856 pSMB->hdr.smb_buf_length += (__u16) name_len;
2857 pSMB->ByteCount = cpu_to_le16(name_len);
2858
2859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2861 if (rc) {
2862 cFYI(1, ("Send error in QueryInfo = %d", rc));
2863 } else if (pFinfo) { /* decode response */
2864 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002865 pFinfo->AllocationSize =
2866 cpu_to_le64(le32_to_cpu(pSMBr->size));
2867 pFinfo->EndOfFile = pFinfo->AllocationSize;
2868 pFinfo->Attributes =
2869 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002870 } else
2871 rc = -EIO; /* bad buffer passed in */
2872
2873 cifs_buf_release(pSMB);
2874
2875 if (rc == -EAGAIN)
2876 goto QInfRetry;
2877
2878 return rc;
2879}
2880
2881
2882
2883
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884int
2885CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2886 const unsigned char *searchName,
2887 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002888 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889{
2890/* level 263 SMB_QUERY_FILE_ALL_INFO */
2891 TRANSACTION2_QPI_REQ *pSMB = NULL;
2892 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2893 int rc = 0;
2894 int bytes_returned;
2895 int name_len;
2896 __u16 params, byte_count;
2897
2898/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2899QPathInfoRetry:
2900 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2901 (void **) &pSMBr);
2902 if (rc)
2903 return rc;
2904
2905 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2906 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002907 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002908 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 name_len++; /* trailing null */
2910 name_len *= 2;
2911 } else { /* BB improve the check for buffer overruns BB */
2912 name_len = strnlen(searchName, PATH_MAX);
2913 name_len++; /* trailing null */
2914 strncpy(pSMB->FileName, searchName, name_len);
2915 }
2916
2917 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2918 pSMB->TotalDataCount = 0;
2919 pSMB->MaxParameterCount = cpu_to_le16(2);
2920 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2921 pSMB->MaxSetupCount = 0;
2922 pSMB->Reserved = 0;
2923 pSMB->Flags = 0;
2924 pSMB->Timeout = 0;
2925 pSMB->Reserved2 = 0;
2926 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2927 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2928 pSMB->DataCount = 0;
2929 pSMB->DataOffset = 0;
2930 pSMB->SetupCount = 1;
2931 pSMB->Reserved3 = 0;
2932 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2933 byte_count = params + 1 /* pad */ ;
2934 pSMB->TotalParameterCount = cpu_to_le16(params);
2935 pSMB->ParameterCount = pSMB->TotalParameterCount;
2936 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2937 pSMB->Reserved4 = 0;
2938 pSMB->hdr.smb_buf_length += byte_count;
2939 pSMB->ByteCount = cpu_to_le16(byte_count);
2940
2941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2943 if (rc) {
2944 cFYI(1, ("Send error in QPathInfo = %d", rc));
2945 } else { /* decode response */
2946 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2947
2948 if (rc || (pSMBr->ByteCount < 40))
2949 rc = -EIO; /* bad smb */
2950 else if (pFindData){
2951 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2952 memcpy((char *) pFindData,
2953 (char *) &pSMBr->hdr.Protocol +
2954 data_offset, sizeof (FILE_ALL_INFO));
2955 } else
2956 rc = -ENOMEM;
2957 }
2958 cifs_buf_release(pSMB);
2959 if (rc == -EAGAIN)
2960 goto QPathInfoRetry;
2961
2962 return rc;
2963}
2964
2965int
2966CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2967 const unsigned char *searchName,
2968 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002969 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970{
2971/* SMB_QUERY_FILE_UNIX_BASIC */
2972 TRANSACTION2_QPI_REQ *pSMB = NULL;
2973 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2974 int rc = 0;
2975 int bytes_returned = 0;
2976 int name_len;
2977 __u16 params, byte_count;
2978
2979 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2980UnixQPathInfoRetry:
2981 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2982 (void **) &pSMBr);
2983 if (rc)
2984 return rc;
2985
2986 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2987 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002988 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002989 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 name_len++; /* trailing null */
2991 name_len *= 2;
2992 } else { /* BB improve the check for buffer overruns BB */
2993 name_len = strnlen(searchName, PATH_MAX);
2994 name_len++; /* trailing null */
2995 strncpy(pSMB->FileName, searchName, name_len);
2996 }
2997
2998 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2999 pSMB->TotalDataCount = 0;
3000 pSMB->MaxParameterCount = cpu_to_le16(2);
3001 /* BB find exact max SMB PDU from sess structure BB */
3002 pSMB->MaxDataCount = cpu_to_le16(4000);
3003 pSMB->MaxSetupCount = 0;
3004 pSMB->Reserved = 0;
3005 pSMB->Flags = 0;
3006 pSMB->Timeout = 0;
3007 pSMB->Reserved2 = 0;
3008 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3009 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3010 pSMB->DataCount = 0;
3011 pSMB->DataOffset = 0;
3012 pSMB->SetupCount = 1;
3013 pSMB->Reserved3 = 0;
3014 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3015 byte_count = params + 1 /* pad */ ;
3016 pSMB->TotalParameterCount = cpu_to_le16(params);
3017 pSMB->ParameterCount = pSMB->TotalParameterCount;
3018 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3019 pSMB->Reserved4 = 0;
3020 pSMB->hdr.smb_buf_length += byte_count;
3021 pSMB->ByteCount = cpu_to_le16(byte_count);
3022
3023 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3024 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3025 if (rc) {
3026 cFYI(1, ("Send error in QPathInfo = %d", rc));
3027 } else { /* decode response */
3028 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3029
3030 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3031 rc = -EIO; /* bad smb */
3032 } else {
3033 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3034 memcpy((char *) pFindData,
3035 (char *) &pSMBr->hdr.Protocol +
3036 data_offset,
3037 sizeof (FILE_UNIX_BASIC_INFO));
3038 }
3039 }
3040 cifs_buf_release(pSMB);
3041 if (rc == -EAGAIN)
3042 goto UnixQPathInfoRetry;
3043
3044 return rc;
3045}
3046
3047#if 0 /* function unused at present */
3048int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3049 const char *searchName, FILE_ALL_INFO * findData,
3050 const struct nls_table *nls_codepage)
3051{
3052/* level 257 SMB_ */
3053 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3054 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3055 int rc = 0;
3056 int bytes_returned;
3057 int name_len;
3058 __u16 params, byte_count;
3059
3060 cFYI(1, ("In FindUnique"));
3061findUniqueRetry:
3062 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3063 (void **) &pSMBr);
3064 if (rc)
3065 return rc;
3066
3067 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3068 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003069 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 /* find define for this maxpathcomponent */
3071 , nls_codepage);
3072 name_len++; /* trailing null */
3073 name_len *= 2;
3074 } else { /* BB improve the check for buffer overruns BB */
3075 name_len = strnlen(searchName, PATH_MAX);
3076 name_len++; /* trailing null */
3077 strncpy(pSMB->FileName, searchName, name_len);
3078 }
3079
3080 params = 12 + name_len /* includes null */ ;
3081 pSMB->TotalDataCount = 0; /* no EAs */
3082 pSMB->MaxParameterCount = cpu_to_le16(2);
3083 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3084 pSMB->MaxSetupCount = 0;
3085 pSMB->Reserved = 0;
3086 pSMB->Flags = 0;
3087 pSMB->Timeout = 0;
3088 pSMB->Reserved2 = 0;
3089 pSMB->ParameterOffset = cpu_to_le16(
3090 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3091 pSMB->DataCount = 0;
3092 pSMB->DataOffset = 0;
3093 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3094 pSMB->Reserved3 = 0;
3095 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3096 byte_count = params + 1 /* pad */ ;
3097 pSMB->TotalParameterCount = cpu_to_le16(params);
3098 pSMB->ParameterCount = pSMB->TotalParameterCount;
3099 pSMB->SearchAttributes =
3100 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3101 ATTR_DIRECTORY);
3102 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3103 pSMB->SearchFlags = cpu_to_le16(1);
3104 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3105 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3106 pSMB->hdr.smb_buf_length += byte_count;
3107 pSMB->ByteCount = cpu_to_le16(byte_count);
3108
3109 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3110 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3111
3112 if (rc) {
3113 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3114 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003115 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 /* BB fill in */
3117 }
3118
3119 cifs_buf_release(pSMB);
3120 if (rc == -EAGAIN)
3121 goto findUniqueRetry;
3122
3123 return rc;
3124}
3125#endif /* end unused (temporarily) function */
3126
3127/* xid, tcon, searchName and codepage are input parms, rest are returned */
3128int
3129CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3130 const char *searchName,
3131 const struct nls_table *nls_codepage,
3132 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003133 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134{
3135/* level 257 SMB_ */
3136 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3137 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3138 T2_FFIRST_RSP_PARMS * parms;
3139 int rc = 0;
3140 int bytes_returned = 0;
3141 int name_len;
3142 __u16 params, byte_count;
3143
Steve French737b7582005-04-28 22:41:06 -07003144 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145
3146findFirstRetry:
3147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3148 (void **) &pSMBr);
3149 if (rc)
3150 return rc;
3151
3152 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3153 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003154 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003155 PATH_MAX, nls_codepage, remap);
3156 /* We can not add the asterik earlier in case
3157 it got remapped to 0xF03A as if it were part of the
3158 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003160 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003161 pSMB->FileName[name_len+1] = 0;
3162 pSMB->FileName[name_len+2] = '*';
3163 pSMB->FileName[name_len+3] = 0;
3164 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3166 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003167 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 } else { /* BB add check for overrun of SMB buf BB */
3169 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170/* BB fix here and in unicode clause above ie
3171 if(name_len > buffersize-header)
3172 free buffer exit; BB */
3173 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003174 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003175 pSMB->FileName[name_len+1] = '*';
3176 pSMB->FileName[name_len+2] = 0;
3177 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 }
3179
3180 params = 12 + name_len /* includes null */ ;
3181 pSMB->TotalDataCount = 0; /* no EAs */
3182 pSMB->MaxParameterCount = cpu_to_le16(10);
3183 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3184 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3185 pSMB->MaxSetupCount = 0;
3186 pSMB->Reserved = 0;
3187 pSMB->Flags = 0;
3188 pSMB->Timeout = 0;
3189 pSMB->Reserved2 = 0;
3190 byte_count = params + 1 /* pad */ ;
3191 pSMB->TotalParameterCount = cpu_to_le16(params);
3192 pSMB->ParameterCount = pSMB->TotalParameterCount;
3193 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003194 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3195 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 pSMB->DataCount = 0;
3197 pSMB->DataOffset = 0;
3198 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3199 pSMB->Reserved3 = 0;
3200 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3201 pSMB->SearchAttributes =
3202 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3203 ATTR_DIRECTORY);
3204 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3205 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3206 CIFS_SEARCH_RETURN_RESUME);
3207 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3208
3209 /* BB what should we set StorageType to? Does it matter? BB */
3210 pSMB->SearchStorageType = 0;
3211 pSMB->hdr.smb_buf_length += byte_count;
3212 pSMB->ByteCount = cpu_to_le16(byte_count);
3213
3214 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3215 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003216 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Steve French88274812006-03-09 22:21:45 +00003218 if (rc) {/* BB add logic to retry regular search if Unix search
3219 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 /* BB Add code to handle unsupported level rc */
3221 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003222
Steve French88274812006-03-09 22:21:45 +00003223 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
3225 /* BB eventually could optimize out free and realloc of buf */
3226 /* for this case */
3227 if (rc == -EAGAIN)
3228 goto findFirstRetry;
3229 } else { /* decode response */
3230 /* BB remember to free buffer if error BB */
3231 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3232 if(rc == 0) {
3233 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3234 psrch_inf->unicode = TRUE;
3235 else
3236 psrch_inf->unicode = FALSE;
3237
3238 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003239 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 psrch_inf->srch_entries_start =
3241 (char *) &pSMBr->hdr.Protocol +
3242 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3244 le16_to_cpu(pSMBr->t2.ParameterOffset));
3245
3246 if(parms->EndofSearch)
3247 psrch_inf->endOfSearch = TRUE;
3248 else
3249 psrch_inf->endOfSearch = FALSE;
3250
3251 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003252 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 *pnetfid = parms->SearchHandle;
3255 } else {
3256 cifs_buf_release(pSMB);
3257 }
3258 }
3259
3260 return rc;
3261}
3262
3263int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3264 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3265{
3266 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3267 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3268 T2_FNEXT_RSP_PARMS * parms;
3269 char *response_data;
3270 int rc = 0;
3271 int bytes_returned, name_len;
3272 __u16 params, byte_count;
3273
3274 cFYI(1, ("In FindNext"));
3275
3276 if(psrch_inf->endOfSearch == TRUE)
3277 return -ENOENT;
3278
3279 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3280 (void **) &pSMBr);
3281 if (rc)
3282 return rc;
3283
3284 params = 14; /* includes 2 bytes of null string, converted to LE below */
3285 byte_count = 0;
3286 pSMB->TotalDataCount = 0; /* no EAs */
3287 pSMB->MaxParameterCount = cpu_to_le16(8);
3288 pSMB->MaxDataCount =
3289 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3290 pSMB->MaxSetupCount = 0;
3291 pSMB->Reserved = 0;
3292 pSMB->Flags = 0;
3293 pSMB->Timeout = 0;
3294 pSMB->Reserved2 = 0;
3295 pSMB->ParameterOffset = cpu_to_le16(
3296 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3297 pSMB->DataCount = 0;
3298 pSMB->DataOffset = 0;
3299 pSMB->SetupCount = 1;
3300 pSMB->Reserved3 = 0;
3301 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3302 pSMB->SearchHandle = searchHandle; /* always kept as le */
3303 pSMB->SearchCount =
3304 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3305 /* test for Unix extensions */
3306/* if (tcon->ses->capabilities & CAP_UNIX) {
3307 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3308 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3309 } else {
3310 pSMB->InformationLevel =
3311 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3312 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3313 } */
3314 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3315 pSMB->ResumeKey = psrch_inf->resume_key;
3316 pSMB->SearchFlags =
3317 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3318
3319 name_len = psrch_inf->resume_name_len;
3320 params += name_len;
3321 if(name_len < PATH_MAX) {
3322 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3323 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003324 /* 14 byte parm len above enough for 2 byte null terminator */
3325 pSMB->ResumeFileName[name_len] = 0;
3326 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 } else {
3328 rc = -EINVAL;
3329 goto FNext2_err_exit;
3330 }
3331 byte_count = params + 1 /* pad */ ;
3332 pSMB->TotalParameterCount = cpu_to_le16(params);
3333 pSMB->ParameterCount = pSMB->TotalParameterCount;
3334 pSMB->hdr.smb_buf_length += byte_count;
3335 pSMB->ByteCount = cpu_to_le16(byte_count);
3336
3337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3338 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003339 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 if (rc) {
3341 if (rc == -EBADF) {
3342 psrch_inf->endOfSearch = TRUE;
3343 rc = 0; /* search probably was closed at end of search above */
3344 } else
3345 cFYI(1, ("FindNext returned = %d", rc));
3346 } else { /* decode response */
3347 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3348
3349 if(rc == 0) {
3350 /* BB fixme add lock for file (srch_info) struct here */
3351 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3352 psrch_inf->unicode = TRUE;
3353 else
3354 psrch_inf->unicode = FALSE;
3355 response_data = (char *) &pSMBr->hdr.Protocol +
3356 le16_to_cpu(pSMBr->t2.ParameterOffset);
3357 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3358 response_data = (char *)&pSMBr->hdr.Protocol +
3359 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003360 if(psrch_inf->smallBuf)
3361 cifs_small_buf_release(
3362 psrch_inf->ntwrk_buf_start);
3363 else
3364 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 psrch_inf->srch_entries_start = response_data;
3366 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003367 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 if(parms->EndofSearch)
3369 psrch_inf->endOfSearch = TRUE;
3370 else
3371 psrch_inf->endOfSearch = FALSE;
3372
3373 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3374 psrch_inf->index_of_last_entry +=
3375 psrch_inf->entries_in_buffer;
3376/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3377
3378 /* BB fixme add unlock here */
3379 }
3380
3381 }
3382
3383 /* BB On error, should we leave previous search buf (and count and
3384 last entry fields) intact or free the previous one? */
3385
3386 /* Note: On -EAGAIN error only caller can retry on handle based calls
3387 since file handle passed in no longer valid */
3388FNext2_err_exit:
3389 if (rc != 0)
3390 cifs_buf_release(pSMB);
3391
3392 return rc;
3393}
3394
3395int
3396CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3397{
3398 int rc = 0;
3399 FINDCLOSE_REQ *pSMB = NULL;
3400 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3401 int bytes_returned;
3402
3403 cFYI(1, ("In CIFSSMBFindClose"));
3404 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3405
3406 /* no sense returning error if session restarted
3407 as file handle has been closed */
3408 if(rc == -EAGAIN)
3409 return 0;
3410 if (rc)
3411 return rc;
3412
3413 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3414 pSMB->FileID = searchHandle;
3415 pSMB->ByteCount = 0;
3416 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3417 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3418 if (rc) {
3419 cERROR(1, ("Send error in FindClose = %d", rc));
3420 }
Steve Frencha4544342005-08-24 13:59:35 -07003421 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 cifs_small_buf_release(pSMB);
3423
3424 /* Since session is dead, search handle closed on server already */
3425 if (rc == -EAGAIN)
3426 rc = 0;
3427
3428 return rc;
3429}
3430
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431int
3432CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3433 const unsigned char *searchName,
3434 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003435 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436{
3437 int rc = 0;
3438 TRANSACTION2_QPI_REQ *pSMB = NULL;
3439 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3440 int name_len, bytes_returned;
3441 __u16 params, byte_count;
3442
3443 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3444 if(tcon == NULL)
3445 return -ENODEV;
3446
3447GetInodeNumberRetry:
3448 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3449 (void **) &pSMBr);
3450 if (rc)
3451 return rc;
3452
3453
3454 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3455 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003456 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003457 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 name_len++; /* trailing null */
3459 name_len *= 2;
3460 } else { /* BB improve the check for buffer overruns BB */
3461 name_len = strnlen(searchName, PATH_MAX);
3462 name_len++; /* trailing null */
3463 strncpy(pSMB->FileName, searchName, name_len);
3464 }
3465
3466 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3467 pSMB->TotalDataCount = 0;
3468 pSMB->MaxParameterCount = cpu_to_le16(2);
3469 /* BB find exact max data count below from sess structure BB */
3470 pSMB->MaxDataCount = cpu_to_le16(4000);
3471 pSMB->MaxSetupCount = 0;
3472 pSMB->Reserved = 0;
3473 pSMB->Flags = 0;
3474 pSMB->Timeout = 0;
3475 pSMB->Reserved2 = 0;
3476 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3477 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3478 pSMB->DataCount = 0;
3479 pSMB->DataOffset = 0;
3480 pSMB->SetupCount = 1;
3481 pSMB->Reserved3 = 0;
3482 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3483 byte_count = params + 1 /* pad */ ;
3484 pSMB->TotalParameterCount = cpu_to_le16(params);
3485 pSMB->ParameterCount = pSMB->TotalParameterCount;
3486 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3487 pSMB->Reserved4 = 0;
3488 pSMB->hdr.smb_buf_length += byte_count;
3489 pSMB->ByteCount = cpu_to_le16(byte_count);
3490
3491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3493 if (rc) {
3494 cFYI(1, ("error %d in QueryInternalInfo", rc));
3495 } else {
3496 /* decode response */
3497 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3498 if (rc || (pSMBr->ByteCount < 2))
3499 /* BB also check enough total bytes returned */
3500 /* If rc should we check for EOPNOSUPP and
3501 disable the srvino flag? or in caller? */
3502 rc = -EIO; /* bad smb */
3503 else {
3504 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3505 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3506 struct file_internal_info * pfinfo;
3507 /* BB Do we need a cast or hash here ? */
3508 if(count < 8) {
3509 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3510 rc = -EIO;
3511 goto GetInodeNumOut;
3512 }
3513 pfinfo = (struct file_internal_info *)
3514 (data_offset + (char *) &pSMBr->hdr.Protocol);
3515 *inode_number = pfinfo->UniqueId;
3516 }
3517 }
3518GetInodeNumOut:
3519 cifs_buf_release(pSMB);
3520 if (rc == -EAGAIN)
3521 goto GetInodeNumberRetry;
3522 return rc;
3523}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
3525int
3526CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3527 const unsigned char *searchName,
3528 unsigned char **targetUNCs,
3529 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003530 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531{
3532/* TRANS2_GET_DFS_REFERRAL */
3533 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3534 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3535 struct dfs_referral_level_3 * referrals = NULL;
3536 int rc = 0;
3537 int bytes_returned;
3538 int name_len;
3539 unsigned int i;
3540 char * temp;
3541 __u16 params, byte_count;
3542 *number_of_UNC_in_array = 0;
3543 *targetUNCs = NULL;
3544
3545 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3546 if (ses == NULL)
3547 return -ENODEV;
3548getDFSRetry:
3549 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3550 (void **) &pSMBr);
3551 if (rc)
3552 return rc;
Steve French1982c342005-08-17 12:38:22 -07003553
3554 /* server pointer checked in called function,
3555 but should never be null here anyway */
3556 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 pSMB->hdr.Tid = ses->ipc_tid;
3558 pSMB->hdr.Uid = ses->Suid;
3559 if (ses->capabilities & CAP_STATUS32) {
3560 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3561 }
3562 if (ses->capabilities & CAP_DFS) {
3563 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3564 }
3565
3566 if (ses->capabilities & CAP_UNICODE) {
3567 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3568 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003569 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003570 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 name_len++; /* trailing null */
3572 name_len *= 2;
3573 } else { /* BB improve the check for buffer overruns BB */
3574 name_len = strnlen(searchName, PATH_MAX);
3575 name_len++; /* trailing null */
3576 strncpy(pSMB->RequestFileName, searchName, name_len);
3577 }
3578
3579 params = 2 /* level */ + name_len /*includes null */ ;
3580 pSMB->TotalDataCount = 0;
3581 pSMB->DataCount = 0;
3582 pSMB->DataOffset = 0;
3583 pSMB->MaxParameterCount = 0;
3584 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3585 pSMB->MaxSetupCount = 0;
3586 pSMB->Reserved = 0;
3587 pSMB->Flags = 0;
3588 pSMB->Timeout = 0;
3589 pSMB->Reserved2 = 0;
3590 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3591 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3592 pSMB->SetupCount = 1;
3593 pSMB->Reserved3 = 0;
3594 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3595 byte_count = params + 3 /* pad */ ;
3596 pSMB->ParameterCount = cpu_to_le16(params);
3597 pSMB->TotalParameterCount = pSMB->ParameterCount;
3598 pSMB->MaxReferralLevel = cpu_to_le16(3);
3599 pSMB->hdr.smb_buf_length += byte_count;
3600 pSMB->ByteCount = cpu_to_le16(byte_count);
3601
3602 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3604 if (rc) {
3605 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3606 } else { /* decode response */
3607/* BB Add logic to parse referrals here */
3608 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3609
3610 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3611 rc = -EIO; /* bad smb */
3612 else {
3613 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3614 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3615
3616 cFYI(1,
3617 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3618 pSMBr->ByteCount, data_offset));
3619 referrals =
3620 (struct dfs_referral_level_3 *)
3621 (8 /* sizeof start of data block */ +
3622 data_offset +
3623 (char *) &pSMBr->hdr.Protocol);
3624 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",
3625 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)));
3626 /* BB This field is actually two bytes in from start of
3627 data block so we could do safety check that DataBlock
3628 begins at address of pSMBr->NumberOfReferrals */
3629 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3630
3631 /* BB Fix below so can return more than one referral */
3632 if(*number_of_UNC_in_array > 1)
3633 *number_of_UNC_in_array = 1;
3634
3635 /* get the length of the strings describing refs */
3636 name_len = 0;
3637 for(i=0;i<*number_of_UNC_in_array;i++) {
3638 /* make sure that DfsPathOffset not past end */
3639 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3640 if (offset > data_count) {
3641 /* if invalid referral, stop here and do
3642 not try to copy any more */
3643 *number_of_UNC_in_array = i;
3644 break;
3645 }
3646 temp = ((char *)referrals) + offset;
3647
3648 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3649 name_len += UniStrnlen((wchar_t *)temp,data_count);
3650 } else {
3651 name_len += strnlen(temp,data_count);
3652 }
3653 referrals++;
3654 /* BB add check that referral pointer does not fall off end PDU */
3655
3656 }
3657 /* BB add check for name_len bigger than bcc */
3658 *targetUNCs =
3659 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3660 if(*targetUNCs == NULL) {
3661 rc = -ENOMEM;
3662 goto GetDFSRefExit;
3663 }
3664 /* copy the ref strings */
3665 referrals =
3666 (struct dfs_referral_level_3 *)
3667 (8 /* sizeof data hdr */ +
3668 data_offset +
3669 (char *) &pSMBr->hdr.Protocol);
3670
3671 for(i=0;i<*number_of_UNC_in_array;i++) {
3672 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3673 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3674 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003675 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 } else {
3677 strncpy(*targetUNCs,temp,name_len);
3678 }
3679 /* BB update target_uncs pointers */
3680 referrals++;
3681 }
3682 temp = *targetUNCs;
3683 temp[name_len] = 0;
3684 }
3685
3686 }
3687GetDFSRefExit:
3688 if (pSMB)
3689 cifs_buf_release(pSMB);
3690
3691 if (rc == -EAGAIN)
3692 goto getDFSRetry;
3693
3694 return rc;
3695}
3696
Steve French20962432005-09-21 22:05:57 -07003697/* Query File System Info such as free space to old servers such as Win 9x */
3698int
3699SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3700{
3701/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3702 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3703 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3704 FILE_SYSTEM_ALLOC_INFO *response_data;
3705 int rc = 0;
3706 int bytes_returned = 0;
3707 __u16 params, byte_count;
3708
3709 cFYI(1, ("OldQFSInfo"));
3710oldQFSInfoRetry:
3711 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3712 (void **) &pSMBr);
3713 if (rc)
3714 return rc;
3715 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3716 (void **) &pSMBr);
3717 if (rc)
3718 return rc;
3719
3720 params = 2; /* level */
3721 pSMB->TotalDataCount = 0;
3722 pSMB->MaxParameterCount = cpu_to_le16(2);
3723 pSMB->MaxDataCount = cpu_to_le16(1000);
3724 pSMB->MaxSetupCount = 0;
3725 pSMB->Reserved = 0;
3726 pSMB->Flags = 0;
3727 pSMB->Timeout = 0;
3728 pSMB->Reserved2 = 0;
3729 byte_count = params + 1 /* pad */ ;
3730 pSMB->TotalParameterCount = cpu_to_le16(params);
3731 pSMB->ParameterCount = pSMB->TotalParameterCount;
3732 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3733 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3734 pSMB->DataCount = 0;
3735 pSMB->DataOffset = 0;
3736 pSMB->SetupCount = 1;
3737 pSMB->Reserved3 = 0;
3738 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3739 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3740 pSMB->hdr.smb_buf_length += byte_count;
3741 pSMB->ByteCount = cpu_to_le16(byte_count);
3742
3743 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3744 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3745 if (rc) {
3746 cFYI(1, ("Send error in QFSInfo = %d", rc));
3747 } else { /* decode response */
3748 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3749
3750 if (rc || (pSMBr->ByteCount < 18))
3751 rc = -EIO; /* bad smb */
3752 else {
3753 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3754 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3755 pSMBr->ByteCount, data_offset));
3756
3757 response_data =
3758 (FILE_SYSTEM_ALLOC_INFO *)
3759 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3760 FSData->f_bsize =
3761 le16_to_cpu(response_data->BytesPerSector) *
3762 le32_to_cpu(response_data->
3763 SectorsPerAllocationUnit);
3764 FSData->f_blocks =
3765 le32_to_cpu(response_data->TotalAllocationUnits);
3766 FSData->f_bfree = FSData->f_bavail =
3767 le32_to_cpu(response_data->FreeAllocationUnits);
3768 cFYI(1,
3769 ("Blocks: %lld Free: %lld Block size %ld",
3770 (unsigned long long)FSData->f_blocks,
3771 (unsigned long long)FSData->f_bfree,
3772 FSData->f_bsize));
3773 }
3774 }
3775 cifs_buf_release(pSMB);
3776
3777 if (rc == -EAGAIN)
3778 goto oldQFSInfoRetry;
3779
3780 return rc;
3781}
3782
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783int
Steve French737b7582005-04-28 22:41:06 -07003784CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785{
3786/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3787 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3788 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3789 FILE_SYSTEM_INFO *response_data;
3790 int rc = 0;
3791 int bytes_returned = 0;
3792 __u16 params, byte_count;
3793
3794 cFYI(1, ("In QFSInfo"));
3795QFSInfoRetry:
3796 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3797 (void **) &pSMBr);
3798 if (rc)
3799 return rc;
3800
3801 params = 2; /* level */
3802 pSMB->TotalDataCount = 0;
3803 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003804 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 pSMB->MaxSetupCount = 0;
3806 pSMB->Reserved = 0;
3807 pSMB->Flags = 0;
3808 pSMB->Timeout = 0;
3809 pSMB->Reserved2 = 0;
3810 byte_count = params + 1 /* pad */ ;
3811 pSMB->TotalParameterCount = cpu_to_le16(params);
3812 pSMB->ParameterCount = pSMB->TotalParameterCount;
3813 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3814 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3815 pSMB->DataCount = 0;
3816 pSMB->DataOffset = 0;
3817 pSMB->SetupCount = 1;
3818 pSMB->Reserved3 = 0;
3819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3820 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3821 pSMB->hdr.smb_buf_length += byte_count;
3822 pSMB->ByteCount = cpu_to_le16(byte_count);
3823
3824 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3825 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3826 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003827 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 } else { /* decode response */
3829 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3830
Steve French20962432005-09-21 22:05:57 -07003831 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 rc = -EIO; /* bad smb */
3833 else {
3834 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835
3836 response_data =
3837 (FILE_SYSTEM_INFO
3838 *) (((char *) &pSMBr->hdr.Protocol) +
3839 data_offset);
3840 FSData->f_bsize =
3841 le32_to_cpu(response_data->BytesPerSector) *
3842 le32_to_cpu(response_data->
3843 SectorsPerAllocationUnit);
3844 FSData->f_blocks =
3845 le64_to_cpu(response_data->TotalAllocationUnits);
3846 FSData->f_bfree = FSData->f_bavail =
3847 le64_to_cpu(response_data->FreeAllocationUnits);
3848 cFYI(1,
3849 ("Blocks: %lld Free: %lld Block size %ld",
3850 (unsigned long long)FSData->f_blocks,
3851 (unsigned long long)FSData->f_bfree,
3852 FSData->f_bsize));
3853 }
3854 }
3855 cifs_buf_release(pSMB);
3856
3857 if (rc == -EAGAIN)
3858 goto QFSInfoRetry;
3859
3860 return rc;
3861}
3862
3863int
Steve French737b7582005-04-28 22:41:06 -07003864CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865{
3866/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3867 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3868 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3869 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3870 int rc = 0;
3871 int bytes_returned = 0;
3872 __u16 params, byte_count;
3873
3874 cFYI(1, ("In QFSAttributeInfo"));
3875QFSAttributeRetry:
3876 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3877 (void **) &pSMBr);
3878 if (rc)
3879 return rc;
3880
3881 params = 2; /* level */
3882 pSMB->TotalDataCount = 0;
3883 pSMB->MaxParameterCount = cpu_to_le16(2);
3884 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3885 pSMB->MaxSetupCount = 0;
3886 pSMB->Reserved = 0;
3887 pSMB->Flags = 0;
3888 pSMB->Timeout = 0;
3889 pSMB->Reserved2 = 0;
3890 byte_count = params + 1 /* pad */ ;
3891 pSMB->TotalParameterCount = cpu_to_le16(params);
3892 pSMB->ParameterCount = pSMB->TotalParameterCount;
3893 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3894 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3895 pSMB->DataCount = 0;
3896 pSMB->DataOffset = 0;
3897 pSMB->SetupCount = 1;
3898 pSMB->Reserved3 = 0;
3899 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3900 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3901 pSMB->hdr.smb_buf_length += byte_count;
3902 pSMB->ByteCount = cpu_to_le16(byte_count);
3903
3904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3906 if (rc) {
3907 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3908 } else { /* decode response */
3909 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3910
3911 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3912 rc = -EIO; /* bad smb */
3913 } else {
3914 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3915 response_data =
3916 (FILE_SYSTEM_ATTRIBUTE_INFO
3917 *) (((char *) &pSMBr->hdr.Protocol) +
3918 data_offset);
3919 memcpy(&tcon->fsAttrInfo, response_data,
3920 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3921 }
3922 }
3923 cifs_buf_release(pSMB);
3924
3925 if (rc == -EAGAIN)
3926 goto QFSAttributeRetry;
3927
3928 return rc;
3929}
3930
3931int
Steve French737b7582005-04-28 22:41:06 -07003932CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933{
3934/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3935 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3936 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3937 FILE_SYSTEM_DEVICE_INFO *response_data;
3938 int rc = 0;
3939 int bytes_returned = 0;
3940 __u16 params, byte_count;
3941
3942 cFYI(1, ("In QFSDeviceInfo"));
3943QFSDeviceRetry:
3944 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3945 (void **) &pSMBr);
3946 if (rc)
3947 return rc;
3948
3949 params = 2; /* level */
3950 pSMB->TotalDataCount = 0;
3951 pSMB->MaxParameterCount = cpu_to_le16(2);
3952 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3953 pSMB->MaxSetupCount = 0;
3954 pSMB->Reserved = 0;
3955 pSMB->Flags = 0;
3956 pSMB->Timeout = 0;
3957 pSMB->Reserved2 = 0;
3958 byte_count = params + 1 /* pad */ ;
3959 pSMB->TotalParameterCount = cpu_to_le16(params);
3960 pSMB->ParameterCount = pSMB->TotalParameterCount;
3961 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3962 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3963
3964 pSMB->DataCount = 0;
3965 pSMB->DataOffset = 0;
3966 pSMB->SetupCount = 1;
3967 pSMB->Reserved3 = 0;
3968 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3969 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3970 pSMB->hdr.smb_buf_length += byte_count;
3971 pSMB->ByteCount = cpu_to_le16(byte_count);
3972
3973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3975 if (rc) {
3976 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3977 } else { /* decode response */
3978 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3979
3980 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3981 rc = -EIO; /* bad smb */
3982 else {
3983 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3984 response_data =
Steve French737b7582005-04-28 22:41:06 -07003985 (FILE_SYSTEM_DEVICE_INFO *)
3986 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 data_offset);
3988 memcpy(&tcon->fsDevInfo, response_data,
3989 sizeof (FILE_SYSTEM_DEVICE_INFO));
3990 }
3991 }
3992 cifs_buf_release(pSMB);
3993
3994 if (rc == -EAGAIN)
3995 goto QFSDeviceRetry;
3996
3997 return rc;
3998}
3999
4000int
Steve French737b7582005-04-28 22:41:06 -07004001CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002{
4003/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4004 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4005 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4006 FILE_SYSTEM_UNIX_INFO *response_data;
4007 int rc = 0;
4008 int bytes_returned = 0;
4009 __u16 params, byte_count;
4010
4011 cFYI(1, ("In QFSUnixInfo"));
4012QFSUnixRetry:
4013 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4014 (void **) &pSMBr);
4015 if (rc)
4016 return rc;
4017
4018 params = 2; /* level */
4019 pSMB->TotalDataCount = 0;
4020 pSMB->DataCount = 0;
4021 pSMB->DataOffset = 0;
4022 pSMB->MaxParameterCount = cpu_to_le16(2);
4023 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4024 pSMB->MaxSetupCount = 0;
4025 pSMB->Reserved = 0;
4026 pSMB->Flags = 0;
4027 pSMB->Timeout = 0;
4028 pSMB->Reserved2 = 0;
4029 byte_count = params + 1 /* pad */ ;
4030 pSMB->ParameterCount = cpu_to_le16(params);
4031 pSMB->TotalParameterCount = pSMB->ParameterCount;
4032 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4033 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4034 pSMB->SetupCount = 1;
4035 pSMB->Reserved3 = 0;
4036 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4037 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4038 pSMB->hdr.smb_buf_length += byte_count;
4039 pSMB->ByteCount = cpu_to_le16(byte_count);
4040
4041 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4042 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4043 if (rc) {
4044 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4045 } else { /* decode response */
4046 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4047
4048 if (rc || (pSMBr->ByteCount < 13)) {
4049 rc = -EIO; /* bad smb */
4050 } else {
4051 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4052 response_data =
4053 (FILE_SYSTEM_UNIX_INFO
4054 *) (((char *) &pSMBr->hdr.Protocol) +
4055 data_offset);
4056 memcpy(&tcon->fsUnixInfo, response_data,
4057 sizeof (FILE_SYSTEM_UNIX_INFO));
4058 }
4059 }
4060 cifs_buf_release(pSMB);
4061
4062 if (rc == -EAGAIN)
4063 goto QFSUnixRetry;
4064
4065
4066 return rc;
4067}
4068
Jeremy Allisonac670552005-06-22 17:26:35 -07004069int
Steve French45abc6e2005-06-23 13:42:03 -05004070CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004071{
4072/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4073 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4074 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4075 int rc = 0;
4076 int bytes_returned = 0;
4077 __u16 params, param_offset, offset, byte_count;
4078
4079 cFYI(1, ("In SETFSUnixInfo"));
4080SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004081 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004082 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4083 (void **) &pSMBr);
4084 if (rc)
4085 return rc;
4086
4087 params = 4; /* 2 bytes zero followed by info level. */
4088 pSMB->MaxSetupCount = 0;
4089 pSMB->Reserved = 0;
4090 pSMB->Flags = 0;
4091 pSMB->Timeout = 0;
4092 pSMB->Reserved2 = 0;
4093 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4094 offset = param_offset + params;
4095
4096 pSMB->MaxParameterCount = cpu_to_le16(4);
4097 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4098 pSMB->SetupCount = 1;
4099 pSMB->Reserved3 = 0;
4100 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4101 byte_count = 1 /* pad */ + params + 12;
4102
4103 pSMB->DataCount = cpu_to_le16(12);
4104 pSMB->ParameterCount = cpu_to_le16(params);
4105 pSMB->TotalDataCount = pSMB->DataCount;
4106 pSMB->TotalParameterCount = pSMB->ParameterCount;
4107 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4108 pSMB->DataOffset = cpu_to_le16(offset);
4109
4110 /* Params. */
4111 pSMB->FileNum = 0;
4112 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4113
4114 /* Data. */
4115 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4116 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4117 pSMB->ClientUnixCap = cpu_to_le64(cap);
4118
4119 pSMB->hdr.smb_buf_length += byte_count;
4120 pSMB->ByteCount = cpu_to_le16(byte_count);
4121
4122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4124 if (rc) {
4125 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4126 } else { /* decode response */
4127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4128 if (rc) {
4129 rc = -EIO; /* bad smb */
4130 }
4131 }
4132 cifs_buf_release(pSMB);
4133
4134 if (rc == -EAGAIN)
4135 goto SETFSUnixRetry;
4136
4137 return rc;
4138}
4139
4140
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141
4142int
4143CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004144 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145{
4146/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4147 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4148 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4149 FILE_SYSTEM_POSIX_INFO *response_data;
4150 int rc = 0;
4151 int bytes_returned = 0;
4152 __u16 params, byte_count;
4153
4154 cFYI(1, ("In QFSPosixInfo"));
4155QFSPosixRetry:
4156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4157 (void **) &pSMBr);
4158 if (rc)
4159 return rc;
4160
4161 params = 2; /* level */
4162 pSMB->TotalDataCount = 0;
4163 pSMB->DataCount = 0;
4164 pSMB->DataOffset = 0;
4165 pSMB->MaxParameterCount = cpu_to_le16(2);
4166 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4167 pSMB->MaxSetupCount = 0;
4168 pSMB->Reserved = 0;
4169 pSMB->Flags = 0;
4170 pSMB->Timeout = 0;
4171 pSMB->Reserved2 = 0;
4172 byte_count = params + 1 /* pad */ ;
4173 pSMB->ParameterCount = cpu_to_le16(params);
4174 pSMB->TotalParameterCount = pSMB->ParameterCount;
4175 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4176 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4177 pSMB->SetupCount = 1;
4178 pSMB->Reserved3 = 0;
4179 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4180 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4181 pSMB->hdr.smb_buf_length += byte_count;
4182 pSMB->ByteCount = cpu_to_le16(byte_count);
4183
4184 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4185 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4186 if (rc) {
4187 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4188 } else { /* decode response */
4189 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4190
4191 if (rc || (pSMBr->ByteCount < 13)) {
4192 rc = -EIO; /* bad smb */
4193 } else {
4194 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4195 response_data =
4196 (FILE_SYSTEM_POSIX_INFO
4197 *) (((char *) &pSMBr->hdr.Protocol) +
4198 data_offset);
4199 FSData->f_bsize =
4200 le32_to_cpu(response_data->BlockSize);
4201 FSData->f_blocks =
4202 le64_to_cpu(response_data->TotalBlocks);
4203 FSData->f_bfree =
4204 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004205 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 FSData->f_bavail = FSData->f_bfree;
4207 } else {
4208 FSData->f_bavail =
4209 le64_to_cpu(response_data->UserBlocksAvail);
4210 }
Steve French70ca7342005-09-22 16:32:06 -07004211 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 FSData->f_files =
4213 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004214 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 FSData->f_ffree =
4216 le64_to_cpu(response_data->FreeFileNodes);
4217 }
4218 }
4219 cifs_buf_release(pSMB);
4220
4221 if (rc == -EAGAIN)
4222 goto QFSPosixRetry;
4223
4224 return rc;
4225}
4226
4227
4228/* We can not use write of zero bytes trick to
4229 set file size due to need for large file support. Also note that
4230 this SetPathInfo is preferred to SetFileInfo based method in next
4231 routine which is only needed to work around a sharing violation bug
4232 in Samba which this routine can run into */
4233
4234int
4235CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004236 __u64 size, int SetAllocation,
4237 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238{
4239 struct smb_com_transaction2_spi_req *pSMB = NULL;
4240 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4241 struct file_end_of_file_info *parm_data;
4242 int name_len;
4243 int rc = 0;
4244 int bytes_returned = 0;
4245 __u16 params, byte_count, data_count, param_offset, offset;
4246
4247 cFYI(1, ("In SetEOF"));
4248SetEOFRetry:
4249 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4250 (void **) &pSMBr);
4251 if (rc)
4252 return rc;
4253
4254 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4255 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004256 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004257 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 name_len++; /* trailing null */
4259 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004260 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 name_len = strnlen(fileName, PATH_MAX);
4262 name_len++; /* trailing null */
4263 strncpy(pSMB->FileName, fileName, name_len);
4264 }
4265 params = 6 + name_len;
4266 data_count = sizeof (struct file_end_of_file_info);
4267 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004268 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 pSMB->MaxSetupCount = 0;
4270 pSMB->Reserved = 0;
4271 pSMB->Flags = 0;
4272 pSMB->Timeout = 0;
4273 pSMB->Reserved2 = 0;
4274 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4275 InformationLevel) - 4;
4276 offset = param_offset + params;
4277 if(SetAllocation) {
4278 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4279 pSMB->InformationLevel =
4280 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4281 else
4282 pSMB->InformationLevel =
4283 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4284 } else /* Set File Size */ {
4285 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4286 pSMB->InformationLevel =
4287 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4288 else
4289 pSMB->InformationLevel =
4290 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4291 }
4292
4293 parm_data =
4294 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4295 offset);
4296 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4297 pSMB->DataOffset = cpu_to_le16(offset);
4298 pSMB->SetupCount = 1;
4299 pSMB->Reserved3 = 0;
4300 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4301 byte_count = 3 /* pad */ + params + data_count;
4302 pSMB->DataCount = cpu_to_le16(data_count);
4303 pSMB->TotalDataCount = pSMB->DataCount;
4304 pSMB->ParameterCount = cpu_to_le16(params);
4305 pSMB->TotalParameterCount = pSMB->ParameterCount;
4306 pSMB->Reserved4 = 0;
4307 pSMB->hdr.smb_buf_length += byte_count;
4308 parm_data->FileSize = cpu_to_le64(size);
4309 pSMB->ByteCount = cpu_to_le16(byte_count);
4310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4312 if (rc) {
4313 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4314 }
4315
4316 cifs_buf_release(pSMB);
4317
4318 if (rc == -EAGAIN)
4319 goto SetEOFRetry;
4320
4321 return rc;
4322}
4323
4324int
4325CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4326 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4327{
4328 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4329 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4330 char *data_offset;
4331 struct file_end_of_file_info *parm_data;
4332 int rc = 0;
4333 int bytes_returned = 0;
4334 __u16 params, param_offset, offset, byte_count, count;
4335
4336 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4337 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004338 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4339
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 if (rc)
4341 return rc;
4342
Steve Frenchcd634992005-04-28 22:41:10 -07004343 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4344
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4346 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4347
4348 params = 6;
4349 pSMB->MaxSetupCount = 0;
4350 pSMB->Reserved = 0;
4351 pSMB->Flags = 0;
4352 pSMB->Timeout = 0;
4353 pSMB->Reserved2 = 0;
4354 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4355 offset = param_offset + params;
4356
4357 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4358
4359 count = sizeof(struct file_end_of_file_info);
4360 pSMB->MaxParameterCount = cpu_to_le16(2);
4361 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4362 pSMB->SetupCount = 1;
4363 pSMB->Reserved3 = 0;
4364 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4365 byte_count = 3 /* pad */ + params + count;
4366 pSMB->DataCount = cpu_to_le16(count);
4367 pSMB->ParameterCount = cpu_to_le16(params);
4368 pSMB->TotalDataCount = pSMB->DataCount;
4369 pSMB->TotalParameterCount = pSMB->ParameterCount;
4370 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4371 parm_data =
4372 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4373 offset);
4374 pSMB->DataOffset = cpu_to_le16(offset);
4375 parm_data->FileSize = cpu_to_le64(size);
4376 pSMB->Fid = fid;
4377 if(SetAllocation) {
4378 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4379 pSMB->InformationLevel =
4380 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4381 else
4382 pSMB->InformationLevel =
4383 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4384 } else /* Set File Size */ {
4385 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4386 pSMB->InformationLevel =
4387 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4388 else
4389 pSMB->InformationLevel =
4390 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4391 }
4392 pSMB->Reserved4 = 0;
4393 pSMB->hdr.smb_buf_length += byte_count;
4394 pSMB->ByteCount = cpu_to_le16(byte_count);
4395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4396 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4397 if (rc) {
4398 cFYI(1,
4399 ("Send error in SetFileInfo (SetFileSize) = %d",
4400 rc));
4401 }
4402
4403 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004404 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405
4406 /* Note: On -EAGAIN error only caller can retry on handle based calls
4407 since file handle passed in no longer valid */
4408
4409 return rc;
4410}
4411
4412/* Some legacy servers such as NT4 require that the file times be set on
4413 an open handle, rather than by pathname - this is awkward due to
4414 potential access conflicts on the open, but it is unavoidable for these
4415 old servers since the only other choice is to go from 100 nanosecond DCE
4416 time and resort to the original setpathinfo level which takes the ancient
4417 DOS time format with 2 second granularity */
4418int
4419CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4420 __u16 fid)
4421{
4422 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4423 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4424 char *data_offset;
4425 int rc = 0;
4426 int bytes_returned = 0;
4427 __u16 params, param_offset, offset, byte_count, count;
4428
4429 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004430 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 if (rc)
4433 return rc;
4434
Steve Frenchcd634992005-04-28 22:41:10 -07004435 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4436
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 /* At this point there is no need to override the current pid
4438 with the pid of the opener, but that could change if we someday
4439 use an existing handle (rather than opening one on the fly) */
4440 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4441 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4442
4443 params = 6;
4444 pSMB->MaxSetupCount = 0;
4445 pSMB->Reserved = 0;
4446 pSMB->Flags = 0;
4447 pSMB->Timeout = 0;
4448 pSMB->Reserved2 = 0;
4449 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4450 offset = param_offset + params;
4451
4452 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4453
4454 count = sizeof (FILE_BASIC_INFO);
4455 pSMB->MaxParameterCount = cpu_to_le16(2);
4456 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4457 pSMB->SetupCount = 1;
4458 pSMB->Reserved3 = 0;
4459 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4460 byte_count = 3 /* pad */ + params + count;
4461 pSMB->DataCount = cpu_to_le16(count);
4462 pSMB->ParameterCount = cpu_to_le16(params);
4463 pSMB->TotalDataCount = pSMB->DataCount;
4464 pSMB->TotalParameterCount = pSMB->ParameterCount;
4465 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4466 pSMB->DataOffset = cpu_to_le16(offset);
4467 pSMB->Fid = fid;
4468 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4469 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4470 else
4471 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4472 pSMB->Reserved4 = 0;
4473 pSMB->hdr.smb_buf_length += byte_count;
4474 pSMB->ByteCount = cpu_to_le16(byte_count);
4475 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4476 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4477 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4478 if (rc) {
4479 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4480 }
4481
Steve Frenchcd634992005-04-28 22:41:10 -07004482 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483
4484 /* Note: On -EAGAIN error only caller can retry on handle based calls
4485 since file handle passed in no longer valid */
4486
4487 return rc;
4488}
4489
4490
4491int
4492CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4493 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004494 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495{
4496 TRANSACTION2_SPI_REQ *pSMB = NULL;
4497 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4498 int name_len;
4499 int rc = 0;
4500 int bytes_returned = 0;
4501 char *data_offset;
4502 __u16 params, param_offset, offset, byte_count, count;
4503
4504 cFYI(1, ("In SetTimes"));
4505
4506SetTimesRetry:
4507 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4508 (void **) &pSMBr);
4509 if (rc)
4510 return rc;
4511
4512 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4513 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004514 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004515 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 name_len++; /* trailing null */
4517 name_len *= 2;
4518 } else { /* BB improve the check for buffer overruns BB */
4519 name_len = strnlen(fileName, PATH_MAX);
4520 name_len++; /* trailing null */
4521 strncpy(pSMB->FileName, fileName, name_len);
4522 }
4523
4524 params = 6 + name_len;
4525 count = sizeof (FILE_BASIC_INFO);
4526 pSMB->MaxParameterCount = cpu_to_le16(2);
4527 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4528 pSMB->MaxSetupCount = 0;
4529 pSMB->Reserved = 0;
4530 pSMB->Flags = 0;
4531 pSMB->Timeout = 0;
4532 pSMB->Reserved2 = 0;
4533 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4534 InformationLevel) - 4;
4535 offset = param_offset + params;
4536 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4537 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4538 pSMB->DataOffset = cpu_to_le16(offset);
4539 pSMB->SetupCount = 1;
4540 pSMB->Reserved3 = 0;
4541 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4542 byte_count = 3 /* pad */ + params + count;
4543
4544 pSMB->DataCount = cpu_to_le16(count);
4545 pSMB->ParameterCount = cpu_to_le16(params);
4546 pSMB->TotalDataCount = pSMB->DataCount;
4547 pSMB->TotalParameterCount = pSMB->ParameterCount;
4548 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4549 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4550 else
4551 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4552 pSMB->Reserved4 = 0;
4553 pSMB->hdr.smb_buf_length += byte_count;
4554 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4555 pSMB->ByteCount = cpu_to_le16(byte_count);
4556 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4557 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4558 if (rc) {
4559 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4560 }
4561
4562 cifs_buf_release(pSMB);
4563
4564 if (rc == -EAGAIN)
4565 goto SetTimesRetry;
4566
4567 return rc;
4568}
4569
4570/* Can not be used to set time stamps yet (due to old DOS time format) */
4571/* Can be used to set attributes */
4572#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4573 handling it anyway and NT4 was what we thought it would be needed for
4574 Do not delete it until we prove whether needed for Win9x though */
4575int
4576CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4577 __u16 dos_attrs, const struct nls_table *nls_codepage)
4578{
4579 SETATTR_REQ *pSMB = NULL;
4580 SETATTR_RSP *pSMBr = NULL;
4581 int rc = 0;
4582 int bytes_returned;
4583 int name_len;
4584
4585 cFYI(1, ("In SetAttrLegacy"));
4586
4587SetAttrLgcyRetry:
4588 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4589 (void **) &pSMBr);
4590 if (rc)
4591 return rc;
4592
4593 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4594 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004595 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 PATH_MAX, nls_codepage);
4597 name_len++; /* trailing null */
4598 name_len *= 2;
4599 } else { /* BB improve the check for buffer overruns BB */
4600 name_len = strnlen(fileName, PATH_MAX);
4601 name_len++; /* trailing null */
4602 strncpy(pSMB->fileName, fileName, name_len);
4603 }
4604 pSMB->attr = cpu_to_le16(dos_attrs);
4605 pSMB->BufferFormat = 0x04;
4606 pSMB->hdr.smb_buf_length += name_len + 1;
4607 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4608 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4609 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4610 if (rc) {
4611 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4612 }
4613
4614 cifs_buf_release(pSMB);
4615
4616 if (rc == -EAGAIN)
4617 goto SetAttrLgcyRetry;
4618
4619 return rc;
4620}
4621#endif /* temporarily unneeded SetAttr legacy function */
4622
4623int
4624CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004625 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4626 dev_t device, const struct nls_table *nls_codepage,
4627 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628{
4629 TRANSACTION2_SPI_REQ *pSMB = NULL;
4630 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4631 int name_len;
4632 int rc = 0;
4633 int bytes_returned = 0;
4634 FILE_UNIX_BASIC_INFO *data_offset;
4635 __u16 params, param_offset, offset, count, byte_count;
4636
4637 cFYI(1, ("In SetUID/GID/Mode"));
4638setPermsRetry:
4639 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4640 (void **) &pSMBr);
4641 if (rc)
4642 return rc;
4643
4644 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4645 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004646 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004647 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 name_len++; /* trailing null */
4649 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004650 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 name_len = strnlen(fileName, PATH_MAX);
4652 name_len++; /* trailing null */
4653 strncpy(pSMB->FileName, fileName, name_len);
4654 }
4655
4656 params = 6 + name_len;
4657 count = sizeof (FILE_UNIX_BASIC_INFO);
4658 pSMB->MaxParameterCount = cpu_to_le16(2);
4659 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4660 pSMB->MaxSetupCount = 0;
4661 pSMB->Reserved = 0;
4662 pSMB->Flags = 0;
4663 pSMB->Timeout = 0;
4664 pSMB->Reserved2 = 0;
4665 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4666 InformationLevel) - 4;
4667 offset = param_offset + params;
4668 data_offset =
4669 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4670 offset);
4671 memset(data_offset, 0, count);
4672 pSMB->DataOffset = cpu_to_le16(offset);
4673 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4674 pSMB->SetupCount = 1;
4675 pSMB->Reserved3 = 0;
4676 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4677 byte_count = 3 /* pad */ + params + count;
4678 pSMB->ParameterCount = cpu_to_le16(params);
4679 pSMB->DataCount = cpu_to_le16(count);
4680 pSMB->TotalParameterCount = pSMB->ParameterCount;
4681 pSMB->TotalDataCount = pSMB->DataCount;
4682 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4683 pSMB->Reserved4 = 0;
4684 pSMB->hdr.smb_buf_length += byte_count;
4685 data_offset->Uid = cpu_to_le64(uid);
4686 data_offset->Gid = cpu_to_le64(gid);
4687 /* better to leave device as zero when it is */
4688 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4689 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4690 data_offset->Permissions = cpu_to_le64(mode);
4691
4692 if(S_ISREG(mode))
4693 data_offset->Type = cpu_to_le32(UNIX_FILE);
4694 else if(S_ISDIR(mode))
4695 data_offset->Type = cpu_to_le32(UNIX_DIR);
4696 else if(S_ISLNK(mode))
4697 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4698 else if(S_ISCHR(mode))
4699 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4700 else if(S_ISBLK(mode))
4701 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4702 else if(S_ISFIFO(mode))
4703 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4704 else if(S_ISSOCK(mode))
4705 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4706
4707
4708 pSMB->ByteCount = cpu_to_le16(byte_count);
4709 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4710 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4711 if (rc) {
4712 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4713 }
4714
4715 if (pSMB)
4716 cifs_buf_release(pSMB);
4717 if (rc == -EAGAIN)
4718 goto setPermsRetry;
4719 return rc;
4720}
4721
4722int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004723 const int notify_subdirs, const __u16 netfid,
4724 __u32 filter, struct file * pfile, int multishot,
4725 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726{
4727 int rc = 0;
4728 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004729 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004730 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 int bytes_returned;
4732
4733 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4734 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4735 (void **) &pSMBr);
4736 if (rc)
4737 return rc;
4738
4739 pSMB->TotalParameterCount = 0 ;
4740 pSMB->TotalDataCount = 0;
4741 pSMB->MaxParameterCount = cpu_to_le32(2);
4742 /* BB find exact data count max from sess structure BB */
4743 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004744/* BB VERIFY verify which is correct for above BB */
4745 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4746 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4747
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 pSMB->MaxSetupCount = 4;
4749 pSMB->Reserved = 0;
4750 pSMB->ParameterOffset = 0;
4751 pSMB->DataCount = 0;
4752 pSMB->DataOffset = 0;
4753 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4754 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4755 pSMB->ParameterCount = pSMB->TotalParameterCount;
4756 if(notify_subdirs)
4757 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4758 pSMB->Reserved2 = 0;
4759 pSMB->CompletionFilter = cpu_to_le32(filter);
4760 pSMB->Fid = netfid; /* file handle always le */
4761 pSMB->ByteCount = 0;
4762
4763 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4764 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4765 if (rc) {
4766 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004767 } else {
4768 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004769 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004770 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004771 sizeof(struct dir_notify_req),
4772 GFP_KERNEL);
4773 if(dnotify_req) {
4774 dnotify_req->Pid = pSMB->hdr.Pid;
4775 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4776 dnotify_req->Mid = pSMB->hdr.Mid;
4777 dnotify_req->Tid = pSMB->hdr.Tid;
4778 dnotify_req->Uid = pSMB->hdr.Uid;
4779 dnotify_req->netfid = netfid;
4780 dnotify_req->pfile = pfile;
4781 dnotify_req->filter = filter;
4782 dnotify_req->multishot = multishot;
4783 spin_lock(&GlobalMid_Lock);
4784 list_add_tail(&dnotify_req->lhead,
4785 &GlobalDnotifyReqList);
4786 spin_unlock(&GlobalMid_Lock);
4787 } else
4788 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 }
4790 cifs_buf_release(pSMB);
4791 return rc;
4792}
4793#ifdef CONFIG_CIFS_XATTR
4794ssize_t
4795CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4796 const unsigned char *searchName,
4797 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004798 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799{
4800 /* BB assumes one setup word */
4801 TRANSACTION2_QPI_REQ *pSMB = NULL;
4802 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4803 int rc = 0;
4804 int bytes_returned;
4805 int name_len;
4806 struct fea * temp_fea;
4807 char * temp_ptr;
4808 __u16 params, byte_count;
4809
4810 cFYI(1, ("In Query All EAs path %s", searchName));
4811QAllEAsRetry:
4812 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4813 (void **) &pSMBr);
4814 if (rc)
4815 return rc;
4816
4817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4818 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004819 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004820 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 name_len++; /* trailing null */
4822 name_len *= 2;
4823 } else { /* BB improve the check for buffer overruns BB */
4824 name_len = strnlen(searchName, PATH_MAX);
4825 name_len++; /* trailing null */
4826 strncpy(pSMB->FileName, searchName, name_len);
4827 }
4828
4829 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4830 pSMB->TotalDataCount = 0;
4831 pSMB->MaxParameterCount = cpu_to_le16(2);
4832 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4833 pSMB->MaxSetupCount = 0;
4834 pSMB->Reserved = 0;
4835 pSMB->Flags = 0;
4836 pSMB->Timeout = 0;
4837 pSMB->Reserved2 = 0;
4838 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4839 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4840 pSMB->DataCount = 0;
4841 pSMB->DataOffset = 0;
4842 pSMB->SetupCount = 1;
4843 pSMB->Reserved3 = 0;
4844 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4845 byte_count = params + 1 /* pad */ ;
4846 pSMB->TotalParameterCount = cpu_to_le16(params);
4847 pSMB->ParameterCount = pSMB->TotalParameterCount;
4848 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4849 pSMB->Reserved4 = 0;
4850 pSMB->hdr.smb_buf_length += byte_count;
4851 pSMB->ByteCount = cpu_to_le16(byte_count);
4852
4853 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4854 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4855 if (rc) {
4856 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4857 } else { /* decode response */
4858 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4859
4860 /* BB also check enough total bytes returned */
4861 /* BB we need to improve the validity checking
4862 of these trans2 responses */
4863 if (rc || (pSMBr->ByteCount < 4))
4864 rc = -EIO; /* bad smb */
4865 /* else if (pFindData){
4866 memcpy((char *) pFindData,
4867 (char *) &pSMBr->hdr.Protocol +
4868 data_offset, kl);
4869 }*/ else {
4870 /* check that length of list is not more than bcc */
4871 /* check that each entry does not go beyond length
4872 of list */
4873 /* check that each element of each entry does not
4874 go beyond end of list */
4875 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4876 struct fealist * ea_response_data;
4877 rc = 0;
4878 /* validate_trans2_offsets() */
4879 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4880 ea_response_data = (struct fealist *)
4881 (((char *) &pSMBr->hdr.Protocol) +
4882 data_offset);
4883 name_len = le32_to_cpu(ea_response_data->list_len);
4884 cFYI(1,("ea length %d", name_len));
4885 if(name_len <= 8) {
4886 /* returned EA size zeroed at top of function */
4887 cFYI(1,("empty EA list returned from server"));
4888 } else {
4889 /* account for ea list len */
4890 name_len -= 4;
4891 temp_fea = ea_response_data->list;
4892 temp_ptr = (char *)temp_fea;
4893 while(name_len > 0) {
4894 __u16 value_len;
4895 name_len -= 4;
4896 temp_ptr += 4;
4897 rc += temp_fea->name_len;
4898 /* account for prefix user. and trailing null */
4899 rc = rc + 5 + 1;
4900 if(rc<(int)buf_size) {
4901 memcpy(EAData,"user.",5);
4902 EAData+=5;
4903 memcpy(EAData,temp_ptr,temp_fea->name_len);
4904 EAData+=temp_fea->name_len;
4905 /* null terminate name */
4906 *EAData = 0;
4907 EAData = EAData + 1;
4908 } else if(buf_size == 0) {
4909 /* skip copy - calc size only */
4910 } else {
4911 /* stop before overrun buffer */
4912 rc = -ERANGE;
4913 break;
4914 }
4915 name_len -= temp_fea->name_len;
4916 temp_ptr += temp_fea->name_len;
4917 /* account for trailing null */
4918 name_len--;
4919 temp_ptr++;
4920 value_len = le16_to_cpu(temp_fea->value_len);
4921 name_len -= value_len;
4922 temp_ptr += value_len;
4923 /* BB check that temp_ptr is still within smb BB*/
4924 /* no trailing null to account for in value len */
4925 /* go on to next EA */
4926 temp_fea = (struct fea *)temp_ptr;
4927 }
4928 }
4929 }
4930 }
4931 if (pSMB)
4932 cifs_buf_release(pSMB);
4933 if (rc == -EAGAIN)
4934 goto QAllEAsRetry;
4935
4936 return (ssize_t)rc;
4937}
4938
4939ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4940 const unsigned char * searchName,const unsigned char * ea_name,
4941 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004942 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943{
4944 TRANSACTION2_QPI_REQ *pSMB = NULL;
4945 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4946 int rc = 0;
4947 int bytes_returned;
4948 int name_len;
4949 struct fea * temp_fea;
4950 char * temp_ptr;
4951 __u16 params, byte_count;
4952
4953 cFYI(1, ("In Query EA path %s", searchName));
4954QEARetry:
4955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4956 (void **) &pSMBr);
4957 if (rc)
4958 return rc;
4959
4960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4961 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004962 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004963 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 name_len++; /* trailing null */
4965 name_len *= 2;
4966 } else { /* BB improve the check for buffer overruns BB */
4967 name_len = strnlen(searchName, PATH_MAX);
4968 name_len++; /* trailing null */
4969 strncpy(pSMB->FileName, searchName, name_len);
4970 }
4971
4972 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4973 pSMB->TotalDataCount = 0;
4974 pSMB->MaxParameterCount = cpu_to_le16(2);
4975 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4976 pSMB->MaxSetupCount = 0;
4977 pSMB->Reserved = 0;
4978 pSMB->Flags = 0;
4979 pSMB->Timeout = 0;
4980 pSMB->Reserved2 = 0;
4981 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4982 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4983 pSMB->DataCount = 0;
4984 pSMB->DataOffset = 0;
4985 pSMB->SetupCount = 1;
4986 pSMB->Reserved3 = 0;
4987 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4988 byte_count = params + 1 /* pad */ ;
4989 pSMB->TotalParameterCount = cpu_to_le16(params);
4990 pSMB->ParameterCount = pSMB->TotalParameterCount;
4991 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4992 pSMB->Reserved4 = 0;
4993 pSMB->hdr.smb_buf_length += byte_count;
4994 pSMB->ByteCount = cpu_to_le16(byte_count);
4995
4996 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4997 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4998 if (rc) {
4999 cFYI(1, ("Send error in Query EA = %d", rc));
5000 } else { /* decode response */
5001 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5002
5003 /* BB also check enough total bytes returned */
5004 /* BB we need to improve the validity checking
5005 of these trans2 responses */
5006 if (rc || (pSMBr->ByteCount < 4))
5007 rc = -EIO; /* bad smb */
5008 /* else if (pFindData){
5009 memcpy((char *) pFindData,
5010 (char *) &pSMBr->hdr.Protocol +
5011 data_offset, kl);
5012 }*/ else {
5013 /* check that length of list is not more than bcc */
5014 /* check that each entry does not go beyond length
5015 of list */
5016 /* check that each element of each entry does not
5017 go beyond end of list */
5018 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5019 struct fealist * ea_response_data;
5020 rc = -ENODATA;
5021 /* validate_trans2_offsets() */
5022 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5023 ea_response_data = (struct fealist *)
5024 (((char *) &pSMBr->hdr.Protocol) +
5025 data_offset);
5026 name_len = le32_to_cpu(ea_response_data->list_len);
5027 cFYI(1,("ea length %d", name_len));
5028 if(name_len <= 8) {
5029 /* returned EA size zeroed at top of function */
5030 cFYI(1,("empty EA list returned from server"));
5031 } else {
5032 /* account for ea list len */
5033 name_len -= 4;
5034 temp_fea = ea_response_data->list;
5035 temp_ptr = (char *)temp_fea;
5036 /* loop through checking if we have a matching
5037 name and then return the associated value */
5038 while(name_len > 0) {
5039 __u16 value_len;
5040 name_len -= 4;
5041 temp_ptr += 4;
5042 value_len = le16_to_cpu(temp_fea->value_len);
5043 /* BB validate that value_len falls within SMB,
5044 even though maximum for name_len is 255 */
5045 if(memcmp(temp_fea->name,ea_name,
5046 temp_fea->name_len) == 0) {
5047 /* found a match */
5048 rc = value_len;
5049 /* account for prefix user. and trailing null */
5050 if(rc<=(int)buf_size) {
5051 memcpy(ea_value,
5052 temp_fea->name+temp_fea->name_len+1,
5053 rc);
5054 /* ea values, unlike ea names,
5055 are not null terminated */
5056 } else if(buf_size == 0) {
5057 /* skip copy - calc size only */
5058 } else {
5059 /* stop before overrun buffer */
5060 rc = -ERANGE;
5061 }
5062 break;
5063 }
5064 name_len -= temp_fea->name_len;
5065 temp_ptr += temp_fea->name_len;
5066 /* account for trailing null */
5067 name_len--;
5068 temp_ptr++;
5069 name_len -= value_len;
5070 temp_ptr += value_len;
5071 /* no trailing null to account for in value len */
5072 /* go on to next EA */
5073 temp_fea = (struct fea *)temp_ptr;
5074 }
5075 }
5076 }
5077 }
5078 if (pSMB)
5079 cifs_buf_release(pSMB);
5080 if (rc == -EAGAIN)
5081 goto QEARetry;
5082
5083 return (ssize_t)rc;
5084}
5085
5086int
5087CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5088 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005089 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5090 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091{
5092 struct smb_com_transaction2_spi_req *pSMB = NULL;
5093 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5094 struct fealist *parm_data;
5095 int name_len;
5096 int rc = 0;
5097 int bytes_returned = 0;
5098 __u16 params, param_offset, byte_count, offset, count;
5099
5100 cFYI(1, ("In SetEA"));
5101SetEARetry:
5102 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5103 (void **) &pSMBr);
5104 if (rc)
5105 return rc;
5106
5107 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5108 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005109 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005110 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 name_len++; /* trailing null */
5112 name_len *= 2;
5113 } else { /* BB improve the check for buffer overruns BB */
5114 name_len = strnlen(fileName, PATH_MAX);
5115 name_len++; /* trailing null */
5116 strncpy(pSMB->FileName, fileName, name_len);
5117 }
5118
5119 params = 6 + name_len;
5120
5121 /* done calculating parms using name_len of file name,
5122 now use name_len to calculate length of ea name
5123 we are going to create in the inode xattrs */
5124 if(ea_name == NULL)
5125 name_len = 0;
5126 else
5127 name_len = strnlen(ea_name,255);
5128
5129 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5130 pSMB->MaxParameterCount = cpu_to_le16(2);
5131 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5132 pSMB->MaxSetupCount = 0;
5133 pSMB->Reserved = 0;
5134 pSMB->Flags = 0;
5135 pSMB->Timeout = 0;
5136 pSMB->Reserved2 = 0;
5137 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5138 InformationLevel) - 4;
5139 offset = param_offset + params;
5140 pSMB->InformationLevel =
5141 cpu_to_le16(SMB_SET_FILE_EA);
5142
5143 parm_data =
5144 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5145 offset);
5146 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5147 pSMB->DataOffset = cpu_to_le16(offset);
5148 pSMB->SetupCount = 1;
5149 pSMB->Reserved3 = 0;
5150 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5151 byte_count = 3 /* pad */ + params + count;
5152 pSMB->DataCount = cpu_to_le16(count);
5153 parm_data->list_len = cpu_to_le32(count);
5154 parm_data->list[0].EA_flags = 0;
5155 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005156 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 /* EA names are always ASCII */
5158 if(ea_name)
5159 strncpy(parm_data->list[0].name,ea_name,name_len);
5160 parm_data->list[0].name[name_len] = 0;
5161 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5162 /* caller ensures that ea_value_len is less than 64K but
5163 we need to ensure that it fits within the smb */
5164
5165 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5166 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5167 if(ea_value_len)
5168 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5169
5170 pSMB->TotalDataCount = pSMB->DataCount;
5171 pSMB->ParameterCount = cpu_to_le16(params);
5172 pSMB->TotalParameterCount = pSMB->ParameterCount;
5173 pSMB->Reserved4 = 0;
5174 pSMB->hdr.smb_buf_length += byte_count;
5175 pSMB->ByteCount = cpu_to_le16(byte_count);
5176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5178 if (rc) {
5179 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5180 }
5181
5182 cifs_buf_release(pSMB);
5183
5184 if (rc == -EAGAIN)
5185 goto SetEARetry;
5186
5187 return rc;
5188}
5189
5190#endif