blob: da3154fa9c8a6057acd1d026cbde06d2fe6ac092 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French12b3b8f2006-02-09 21:12:47 +00004 * Copyright (C) International Business Machines Corp., 2002,2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly different for reconnection purposes since we never want */
28 /* to reuse a stale file handle and the caller knows the file handle */
29
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
Steve Frencheeac8042006-01-13 21:34:58 -080040#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000051 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 {BAD_PROT, "\2"}
53};
54#else
55static struct {
56 int index;
57 char *name;
58} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000059#ifdef CONFIG_CIFS_WEAK_PW_HASH
60 {LANMAN_PROT, "\2LM1.2X002"},
61#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 {CIFS_PROT, "\2NT LM 0.12"},
63 {BAD_PROT, "\2"}
64};
65#endif
66
Steve French39798772006-05-31 22:40:51 +000067/* define the number of elements in the cifs dialect array */
68#ifdef CONFIG_CIFS_POSIX
69#ifdef CONFIG_CIFS_WEAK_PW_HASH
70#define CIFS_NUM_PROT 3
71#else
72#define CIFS_NUM_PROT 2
73#endif /* CIFS_WEAK_PW_HASH */
74#else /* not posix */
75#ifdef CONFIG_CIFS_WEAK_PW_HASH
76#define CIFS_NUM_PROT 2
77#else
78#define CIFS_NUM_PROT 1
79#endif /* CONFIG_CIFS_WEAK_PW_HASH */
80#endif /* CIFS_POSIX */
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83/* Mark as invalid, all open files on tree connections since they
84 were closed when session to server was lost */
85static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
86{
87 struct cifsFileInfo *open_file = NULL;
88 struct list_head * tmp;
89 struct list_head * tmp1;
90
91/* list all files open on tree connection and mark them invalid */
92 write_lock(&GlobalSMBSeslock);
93 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
94 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
95 if(open_file) {
96 open_file->invalidHandle = TRUE;
97 }
98 }
99 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
104/* If the return code is zero, this function must fill in request_buf pointer */
105static int
106small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
107 void **request_buf /* returned */)
108{
109 int rc = 0;
110
111 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
112 check for tcp and smb session status done differently
113 for those three - in the calling routine */
114 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800115 if(tcon->tidStatus == CifsExiting) {
116 /* only tree disconnect, open, and write,
117 (and ulogoff which does not have tcon)
118 are allowed as we start force umount */
119 if((smb_command != SMB_COM_WRITE_ANDX) &&
120 (smb_command != SMB_COM_OPEN_ANDX) &&
121 (smb_command != SMB_COM_TREE_DISCONNECT)) {
122 cFYI(1,("can not send cmd %d while umounting",
123 smb_command));
124 return -ENODEV;
125 }
126 }
Steve French31ca3bc2005-04-28 22:41:11 -0700127 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
128 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 struct nls_table *nls_codepage;
130 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700131 reconnect, should be greater than cifs socket
132 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
134 wait_event_interruptible_timeout(tcon->ses->server->response_q,
135 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
136 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
137 /* on "soft" mounts we wait once */
138 if((tcon->retry == FALSE) ||
139 (tcon->ses->status == CifsExiting)) {
140 cFYI(1,("gave up waiting on reconnect in smb_init"));
141 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700142 } /* else "hard" mount - keep retrying
143 until process is killed or server
144 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 } else /* TCP session is reestablished now */
146 break;
147
148 }
149
150 nls_codepage = load_nls_default();
151 /* need to prevent multiple threads trying to
152 simultaneously reconnect the same SMB session */
153 down(&tcon->ses->sesSem);
154 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700155 rc = cifs_setup_session(0, tcon->ses,
156 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
158 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700159 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
160 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700162 /* BB FIXME add code to check if wsize needs
163 update due to negotiated smb buffer size
164 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 if(rc == 0)
166 atomic_inc(&tconInfoReconnectCount);
167
168 cFYI(1, ("reconnect tcon rc = %d", rc));
169 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700170 it is safer (and faster) to reopen files
171 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700174 know whether we can continue or not without
175 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 switch(smb_command) {
177 case SMB_COM_READ_ANDX:
178 case SMB_COM_WRITE_ANDX:
179 case SMB_COM_CLOSE:
180 case SMB_COM_FIND_CLOSE2:
181 case SMB_COM_LOCKING_ANDX: {
182 unload_nls(nls_codepage);
183 return -EAGAIN;
184 }
185 }
186 } else {
187 up(&tcon->ses->sesSem);
188 }
189 unload_nls(nls_codepage);
190
191 } else {
192 return -EIO;
193 }
194 }
195 if(rc)
196 return rc;
197
198 *request_buf = cifs_small_buf_get();
199 if (*request_buf == NULL) {
200 /* BB should we add a retry in here if not a writepage? */
201 return -ENOMEM;
202 }
203
204 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
205
Steve Frencha4544342005-08-24 13:59:35 -0700206 if(tcon != NULL)
207 cifs_stats_inc(&tcon->num_smbs_sent);
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000210}
211
212#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French12b3b8f2006-02-09 21:12:47 +0000213int
Steve French5815449d2006-02-14 01:36:20 +0000214small_smb_init_no_tc(const int smb_command, const int wct,
215 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000216{
217 int rc;
218 struct smb_hdr * buffer;
219
Steve French5815449d2006-02-14 01:36:20 +0000220 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000221 if(rc)
222 return rc;
223
Steve French04fdabe2006-02-10 05:52:50 +0000224 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000225 buffer->Mid = GetNextMid(ses->server);
226 if (ses->capabilities & CAP_UNICODE)
227 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000228 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000229 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
230
231 /* uid, tid can stay at zero as set in header assemble */
232
233 /* BB add support for turning on the signing when
234 this function is used after 1st of session setup requests */
235
236 return rc;
237}
Steve French5815449d2006-02-14 01:36:20 +0000238#endif /* CONFIG_CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240/* If the return code is zero, this function must fill in request_buf pointer */
241static int
242smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
243 void **request_buf /* returned */ ,
244 void **response_buf /* returned */ )
245{
246 int rc = 0;
247
248 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
249 check for tcp and smb session status done differently
250 for those three - in the calling routine */
251 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800252 if(tcon->tidStatus == CifsExiting) {
253 /* only tree disconnect, open, and write,
254 (and ulogoff which does not have tcon)
255 are allowed as we start force umount */
256 if((smb_command != SMB_COM_WRITE_ANDX) &&
257 (smb_command != SMB_COM_OPEN_ANDX) &&
258 (smb_command != SMB_COM_TREE_DISCONNECT)) {
259 cFYI(1,("can not send cmd %d while umounting",
260 smb_command));
261 return -ENODEV;
262 }
263 }
264
Steve French31ca3bc2005-04-28 22:41:11 -0700265 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
266 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700268 /* Give Demultiplex thread up to 10 seconds to
269 reconnect, should be greater than cifs socket
270 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
272 wait_event_interruptible_timeout(tcon->ses->server->response_q,
273 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700274 if(tcon->ses->server->tcpStatus ==
275 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* on "soft" mounts we wait once */
277 if((tcon->retry == FALSE) ||
278 (tcon->ses->status == CifsExiting)) {
279 cFYI(1,("gave up waiting on reconnect in smb_init"));
280 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700281 } /* else "hard" mount - keep retrying
282 until process is killed or server
283 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 } else /* TCP session is reestablished now */
285 break;
286
287 }
288
289 nls_codepage = load_nls_default();
290 /* need to prevent multiple threads trying to
291 simultaneously reconnect the same SMB session */
292 down(&tcon->ses->sesSem);
293 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700294 rc = cifs_setup_session(0, tcon->ses,
295 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
297 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700298 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
299 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700301 /* BB FIXME add code to check if wsize needs
302 update due to negotiated smb buffer size
303 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 if(rc == 0)
305 atomic_inc(&tconInfoReconnectCount);
306
307 cFYI(1, ("reconnect tcon rc = %d", rc));
308 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700309 it is safer (and faster) to reopen files
310 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700313 know whether we can continue or not without
314 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 switch(smb_command) {
316 case SMB_COM_READ_ANDX:
317 case SMB_COM_WRITE_ANDX:
318 case SMB_COM_CLOSE:
319 case SMB_COM_FIND_CLOSE2:
320 case SMB_COM_LOCKING_ANDX: {
321 unload_nls(nls_codepage);
322 return -EAGAIN;
323 }
324 }
325 } else {
326 up(&tcon->ses->sesSem);
327 }
328 unload_nls(nls_codepage);
329
330 } else {
331 return -EIO;
332 }
333 }
334 if(rc)
335 return rc;
336
337 *request_buf = cifs_buf_get();
338 if (*request_buf == NULL) {
339 /* BB should we add a retry in here if not a writepage? */
340 return -ENOMEM;
341 }
342 /* Although the original thought was we needed the response buf for */
343 /* potential retries of smb operations it turns out we can determine */
344 /* from the mid flags when the request buffer can be resent without */
345 /* having to use a second distinct buffer for the response */
Steve French39798772006-05-31 22:40:51 +0000346 if(response_buf)
347 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
350 wct /*wct */ );
351
Steve Frencha4544342005-08-24 13:59:35 -0700352 if(tcon != NULL)
353 cifs_stats_inc(&tcon->num_smbs_sent);
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return rc;
356}
357
358static int validate_t2(struct smb_t2_rsp * pSMB)
359{
360 int rc = -EINVAL;
361 int total_size;
362 char * pBCC;
363
364 /* check for plausible wct, bcc and t2 data and parm sizes */
365 /* check for parm and data offset going beyond end of smb */
366 if(pSMB->hdr.WordCount >= 10) {
367 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
368 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
369 /* check that bcc is at least as big as parms + data */
370 /* check that bcc is less than negotiated smb buffer */
371 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
372 if(total_size < 512) {
373 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
374 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700375 pBCC = (pSMB->hdr.WordCount * 2) +
376 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 (char *)pSMB;
378 if((total_size <= (*(u16 *)pBCC)) &&
379 (total_size <
380 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
381 return 0;
382 }
383
384 }
385 }
386 }
387 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
388 sizeof(struct smb_t2_rsp) + 16);
389 return rc;
390}
391int
392CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
393{
394 NEGOTIATE_REQ *pSMB;
395 NEGOTIATE_RSP *pSMBr;
396 int rc = 0;
397 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000398 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 struct TCP_Server_Info * server;
400 u16 count;
401
402 if(ses->server)
403 server = ses->server;
404 else {
405 rc = -EIO;
406 return rc;
407 }
408 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
409 (void **) &pSMB, (void **) &pSMBr);
410 if (rc)
411 return rc;
Steve French1982c342005-08-17 12:38:22 -0700412 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French39798772006-05-31 22:40:51 +0000414/* if (extended_security)
415 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/
416
417 count = 0;
418 for(i=0;i<CIFS_NUM_PROT;i++) {
419 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
420 count += strlen(protocols[i].name) + 1;
421 /* null at end of source and target buffers anyway */
422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->hdr.smb_buf_length += count;
424 pSMB->ByteCount = cpu_to_le16(count);
425
426 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
428 if (rc == 0) {
Steve French39798772006-05-31 22:40:51 +0000429 cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
430 /* Check wct = 1 error case */
431 if((pSMBr->hdr.WordCount < 13)
432 || (pSMBr->DialectIndex == BAD_PROT)) {
433 /* core returns wct = 1, but we do not ask for
434 core - otherwise it just comes when dialect
435 index is -1 indicating we could not negotiate
436 a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
439 } else if((pSMBr->hdr.WordCount == 13) &&
440 (pSMBr->DialectIndex == LANMAN_PROT)) {
441 struct lanman_neg_rsp * rsp =
442 (struct lanman_neg_rsp *)pSMBr;
443
444
445 /* BB Mark ses struct as negotiated lanman level BB */
446 server->secType = LANMAN;
447 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
448 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
449 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
450 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
451
452 /* BB what do we do with raw mode? BB */
453 server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
454 /* Do we have to set signing flags? no signing
455 was available LANMAN - default should be ok */
456
457 /* BB FIXME set default dummy capabilities since
458 they are not returned by the server in this dialect */
459
460 /* get server time for time conversions and add
461 code to use it and timezone since this is not UTC */
462
463 if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
464 memcpy(server->cryptKey, rsp->EncryptionKey,
465 CIFS_CRYPTO_KEY_SIZE);
466 } else {
467 rc = -EIO;
468 goto neg_err_exit;
469 }
470
471 cFYI(1,("LANMAN negotiated")); /* BB removeme BB */
472 goto neg_err_exit;
473 } else if(pSMBr->hdr.WordCount != 17) {
474 /* unknown wct */
475 rc = -EOPNOTSUPP;
476 goto neg_err_exit;
477 }
478
Steve Frencheeac8042006-01-13 21:34:58 -0800479 server->secMode = pSMBr->SecurityMode;
480 if((server->secMode & SECMODE_USER) == 0)
481 cFYI(1,("share mode security"));
482 server->secType = NTLM; /* BB override default for
Steve French09d1db52005-04-28 22:41:08 -0700483 NTLMv2 or kerberos v5 */
484 /* one byte - no need to convert this or EncryptionKeyLen
485 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
487 /* probably no need to store and check maxvcs */
488 server->maxBuf =
489 min(le32_to_cpu(pSMBr->MaxBufferSize),
490 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
491 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve Frencheeac8042006-01-13 21:34:58 -0800492 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
494 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
495 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
496 /* BB with UTC do we ever need to be using srvr timezone? */
497 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
498 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
499 CIFS_CRYPTO_KEY_SIZE);
500 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
501 && (pSMBr->EncryptionKeyLength == 0)) {
502 /* decode security blob */
503 } else
504 rc = -EIO;
505
506 /* BB might be helpful to save off the domain of server here */
507
508 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
509 (server->capabilities & CAP_EXTENDED_SECURITY)) {
510 count = pSMBr->ByteCount;
511 if (count < 16)
512 rc = -EIO;
513 else if (count == 16) {
514 server->secType = RawNTLMSSP;
515 if (server->socketUseCount.counter > 1) {
516 if (memcmp
517 (server->server_GUID,
518 pSMBr->u.extended_response.
519 GUID, 16) != 0) {
Steve Frencheeac8042006-01-13 21:34:58 -0800520 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 memcpy(server->
522 server_GUID,
523 pSMBr->u.
524 extended_response.
525 GUID, 16);
526 }
527 } else
528 memcpy(server->server_GUID,
529 pSMBr->u.extended_response.
530 GUID, 16);
531 } else {
532 rc = decode_negTokenInit(pSMBr->u.
533 extended_response.
534 SecurityBlob,
535 count - 16,
536 &server->secType);
537 if(rc == 1) {
538 /* BB Need to fill struct for sessetup here */
539 rc = -EOPNOTSUPP;
540 } else {
541 rc = -EINVAL;
542 }
543 }
544 } else
545 server->capabilities &= ~CAP_EXTENDED_SECURITY;
546 if(sign_CIFS_PDUs == FALSE) {
547 if(server->secMode & SECMODE_SIGN_REQUIRED)
548 cERROR(1,
549 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700550 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 } else if(sign_CIFS_PDUs == 1) {
552 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700553 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 }
555
556 }
Steve French39798772006-05-31 22:40:51 +0000557neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700558 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 return rc;
560}
561
562int
563CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
564{
565 struct smb_hdr *smb_buffer;
566 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
567 int rc = 0;
568 int length;
569
570 cFYI(1, ("In tree disconnect"));
571 /*
572 * If last user of the connection and
573 * connection alive - disconnect it
574 * If this is the last connection on the server session disconnect it
575 * (and inside session disconnect we should check if tcp socket needs
576 * to be freed and kernel thread woken up).
577 */
578 if (tcon)
579 down(&tcon->tconSem);
580 else
581 return -EIO;
582
583 atomic_dec(&tcon->useCount);
584 if (atomic_read(&tcon->useCount) > 0) {
585 up(&tcon->tconSem);
586 return -EBUSY;
587 }
588
589 /* No need to return error on this operation if tid invalidated and
590 closed on server already e.g. due to tcp session crashing */
591 if(tcon->tidStatus == CifsNeedReconnect) {
592 up(&tcon->tconSem);
593 return 0;
594 }
595
596 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
597 up(&tcon->tconSem);
598 return -EIO;
599 }
Steve French09d1db52005-04-28 22:41:08 -0700600 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
601 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 if (rc) {
603 up(&tcon->tconSem);
604 return rc;
605 } else {
606 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
609 &length, 0);
610 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700611 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 if (smb_buffer)
614 cifs_small_buf_release(smb_buffer);
615 up(&tcon->tconSem);
616
617 /* No need to return error on this operation if tid invalidated and
618 closed on server already e.g. due to tcp session crashing */
619 if (rc == -EAGAIN)
620 rc = 0;
621
622 return rc;
623}
624
625int
626CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
627{
628 struct smb_hdr *smb_buffer_response;
629 LOGOFF_ANDX_REQ *pSMB;
630 int rc = 0;
631 int length;
632
633 cFYI(1, ("In SMBLogoff for session disconnect"));
634 if (ses)
635 down(&ses->sesSem);
636 else
637 return -EIO;
638
639 atomic_dec(&ses->inUse);
640 if (atomic_read(&ses->inUse) > 0) {
641 up(&ses->sesSem);
642 return -EBUSY;
643 }
644 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
645 if (rc) {
646 up(&ses->sesSem);
647 return rc;
648 }
649
650 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
651
652 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700653 pSMB->hdr.Mid = GetNextMid(ses->server);
654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if(ses->server->secMode &
656 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
657 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
658 }
659
660 pSMB->hdr.Uid = ses->Suid;
661
662 pSMB->AndXCommand = 0xFF;
663 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
664 smb_buffer_response, &length, 0);
665 if (ses->server) {
666 atomic_dec(&ses->server->socketUseCount);
667 if (atomic_read(&ses->server->socketUseCount) == 0) {
668 spin_lock(&GlobalMid_Lock);
669 ses->server->tcpStatus = CifsExiting;
670 spin_unlock(&GlobalMid_Lock);
671 rc = -ESHUTDOWN;
672 }
673 }
Steve Frencha59c6582005-08-17 12:12:19 -0700674 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700675 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
677 /* if session dead then we do not need to do ulogoff,
678 since server closed smb session, no sense reporting
679 error */
680 if (rc == -EAGAIN)
681 rc = 0;
682 return rc;
683}
684
685int
Steve French737b7582005-04-28 22:41:06 -0700686CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
687 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 DELETE_FILE_REQ *pSMB = NULL;
690 DELETE_FILE_RSP *pSMBr = NULL;
691 int rc = 0;
692 int bytes_returned;
693 int name_len;
694
695DelFileRetry:
696 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
697 (void **) &pSMBr);
698 if (rc)
699 return rc;
700
701 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
702 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500703 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700704 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 name_len++; /* trailing null */
706 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700707 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 name_len = strnlen(fileName, PATH_MAX);
709 name_len++; /* trailing null */
710 strncpy(pSMB->fileName, fileName, name_len);
711 }
712 pSMB->SearchAttributes =
713 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
714 pSMB->BufferFormat = 0x04;
715 pSMB->hdr.smb_buf_length += name_len + 1;
716 pSMB->ByteCount = cpu_to_le16(name_len + 1);
717 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
718 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700719 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 if (rc) {
721 cFYI(1, ("Error in RMFile = %d", rc));
722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 cifs_buf_release(pSMB);
725 if (rc == -EAGAIN)
726 goto DelFileRetry;
727
728 return rc;
729}
730
731int
Steve French737b7582005-04-28 22:41:06 -0700732CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
733 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
735 DELETE_DIRECTORY_REQ *pSMB = NULL;
736 DELETE_DIRECTORY_RSP *pSMBr = NULL;
737 int rc = 0;
738 int bytes_returned;
739 int name_len;
740
741 cFYI(1, ("In CIFSSMBRmDir"));
742RmDirRetry:
743 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
744 (void **) &pSMBr);
745 if (rc)
746 return rc;
747
748 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700749 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
750 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 name_len++; /* trailing null */
752 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700753 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 name_len = strnlen(dirName, PATH_MAX);
755 name_len++; /* trailing null */
756 strncpy(pSMB->DirName, dirName, name_len);
757 }
758
759 pSMB->BufferFormat = 0x04;
760 pSMB->hdr.smb_buf_length += name_len + 1;
761 pSMB->ByteCount = cpu_to_le16(name_len + 1);
762 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
763 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700764 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (rc) {
766 cFYI(1, ("Error in RMDir = %d", rc));
767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 cifs_buf_release(pSMB);
770 if (rc == -EAGAIN)
771 goto RmDirRetry;
772 return rc;
773}
774
775int
776CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700777 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 int rc = 0;
780 CREATE_DIRECTORY_REQ *pSMB = NULL;
781 CREATE_DIRECTORY_RSP *pSMBr = NULL;
782 int bytes_returned;
783 int name_len;
784
785 cFYI(1, ("In CIFSSMBMkDir"));
786MkDirRetry:
787 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
788 (void **) &pSMBr);
789 if (rc)
790 return rc;
791
792 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500793 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700794 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 name_len++; /* trailing null */
796 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700797 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 name_len = strnlen(name, PATH_MAX);
799 name_len++; /* trailing null */
800 strncpy(pSMB->DirName, name, name_len);
801 }
802
803 pSMB->BufferFormat = 0x04;
804 pSMB->hdr.smb_buf_length += name_len + 1;
805 pSMB->ByteCount = cpu_to_le16(name_len + 1);
806 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
807 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700808 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if (rc) {
810 cFYI(1, ("Error in Mkdir = %d", rc));
811 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 cifs_buf_release(pSMB);
814 if (rc == -EAGAIN)
815 goto MkDirRetry;
816 return rc;
817}
818
Steve Frencha9d02ad2005-08-24 23:06:05 -0700819static __u16 convert_disposition(int disposition)
820{
821 __u16 ofun = 0;
822
823 switch (disposition) {
824 case FILE_SUPERSEDE:
825 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
826 break;
827 case FILE_OPEN:
828 ofun = SMBOPEN_OAPPEND;
829 break;
830 case FILE_CREATE:
831 ofun = SMBOPEN_OCREATE;
832 break;
833 case FILE_OPEN_IF:
834 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
835 break;
836 case FILE_OVERWRITE:
837 ofun = SMBOPEN_OTRUNC;
838 break;
839 case FILE_OVERWRITE_IF:
840 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
841 break;
842 default:
843 cFYI(1,("unknown disposition %d",disposition));
844 ofun = SMBOPEN_OAPPEND; /* regular open */
845 }
846 return ofun;
847}
848
849int
850SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
851 const char *fileName, const int openDisposition,
852 const int access_flags, const int create_options, __u16 * netfid,
853 int *pOplock, FILE_ALL_INFO * pfile_info,
854 const struct nls_table *nls_codepage, int remap)
855{
856 int rc = -EACCES;
857 OPENX_REQ *pSMB = NULL;
858 OPENX_RSP *pSMBr = NULL;
859 int bytes_returned;
860 int name_len;
861 __u16 count;
862
863OldOpenRetry:
864 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
865 (void **) &pSMBr);
866 if (rc)
867 return rc;
868
869 pSMB->AndXCommand = 0xFF; /* none */
870
871 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
872 count = 1; /* account for one byte pad to word boundary */
873 name_len =
874 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
875 fileName, PATH_MAX, nls_codepage, remap);
876 name_len++; /* trailing null */
877 name_len *= 2;
878 } else { /* BB improve check for buffer overruns BB */
879 count = 0; /* no pad */
880 name_len = strnlen(fileName, PATH_MAX);
881 name_len++; /* trailing null */
882 strncpy(pSMB->fileName, fileName, name_len);
883 }
884 if (*pOplock & REQ_OPLOCK)
885 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
886 else if (*pOplock & REQ_BATCHOPLOCK) {
887 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
888 }
889 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
890 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
891 /* 0 = read
892 1 = write
893 2 = rw
894 3 = execute
895 */
896 pSMB->Mode = cpu_to_le16(2);
897 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
898 /* set file as system file if special file such
899 as fifo and server expecting SFU style and
900 no Unix extensions */
901
902 if(create_options & CREATE_OPTION_SPECIAL)
903 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
904 else
Steve French3e87d802005-09-18 20:49:21 -0700905 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700906
907 /* if ((omode & S_IWUGO) == 0)
908 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
909 /* Above line causes problems due to vfs splitting create into two
910 pieces - need to set mode after file created not while it is
911 being created */
912
913 /* BB FIXME BB */
914/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
915 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700916
917 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700918 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700919 count += name_len;
920 pSMB->hdr.smb_buf_length += count;
921
922 pSMB->ByteCount = cpu_to_le16(count);
923 /* long_op set to 1 to allow for oplock break timeouts */
924 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
925 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
926 cifs_stats_inc(&tcon->num_opens);
927 if (rc) {
928 cFYI(1, ("Error in Open = %d", rc));
929 } else {
930 /* BB verify if wct == 15 */
931
932/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
933
934 *netfid = pSMBr->Fid; /* cifs fid stays in le */
935 /* Let caller know file was created so we can set the mode. */
936 /* Do we care about the CreateAction in any other cases? */
937 /* BB FIXME BB */
938/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
939 *pOplock |= CIFS_CREATE_ACTION; */
940 /* BB FIXME END */
941
942 if(pfile_info) {
943 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
944 pfile_info->LastAccessTime = 0; /* BB fixme */
945 pfile_info->LastWriteTime = 0; /* BB fixme */
946 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700947 pfile_info->Attributes =
948 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700949 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700950 pfile_info->AllocationSize =
951 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
952 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700953 pfile_info->NumberOfLinks = cpu_to_le32(1);
954 }
955 }
956
957 cifs_buf_release(pSMB);
958 if (rc == -EAGAIN)
959 goto OldOpenRetry;
960 return rc;
961}
962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963int
964CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
965 const char *fileName, const int openDisposition,
966 const int access_flags, const int create_options, __u16 * netfid,
967 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700968 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 int rc = -EACCES;
971 OPEN_REQ *pSMB = NULL;
972 OPEN_RSP *pSMBr = NULL;
973 int bytes_returned;
974 int name_len;
975 __u16 count;
976
977openRetry:
978 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
979 (void **) &pSMBr);
980 if (rc)
981 return rc;
982
983 pSMB->AndXCommand = 0xFF; /* none */
984
985 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
986 count = 1; /* account for one byte pad to word boundary */
987 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500988 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700989 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 name_len++; /* trailing null */
991 name_len *= 2;
992 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700993 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 count = 0; /* no pad */
995 name_len = strnlen(fileName, PATH_MAX);
996 name_len++; /* trailing null */
997 pSMB->NameLength = cpu_to_le16(name_len);
998 strncpy(pSMB->fileName, fileName, name_len);
999 }
1000 if (*pOplock & REQ_OPLOCK)
1001 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1002 else if (*pOplock & REQ_BATCHOPLOCK) {
1003 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1004 }
1005 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1006 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001007 /* set file as system file if special file such
1008 as fifo and server expecting SFU style and
1009 no Unix extensions */
1010 if(create_options & CREATE_OPTION_SPECIAL)
1011 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1012 else
1013 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 /* XP does not handle ATTR_POSIX_SEMANTICS */
1015 /* but it helps speed up case sensitive checks for other
1016 servers such as Samba */
1017 if (tcon->ses->capabilities & CAP_UNIX)
1018 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1019
1020 /* if ((omode & S_IWUGO) == 0)
1021 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1022 /* Above line causes problems due to vfs splitting create into two
1023 pieces - need to set mode after file created not while it is
1024 being created */
1025 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1026 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001027 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001028 /* BB Expirement with various impersonation levels and verify */
1029 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 pSMB->SecurityFlags =
1031 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1032
1033 count += name_len;
1034 pSMB->hdr.smb_buf_length += count;
1035
1036 pSMB->ByteCount = cpu_to_le16(count);
1037 /* long_op set to 1 to allow for oplock break timeouts */
1038 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1039 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001040 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 if (rc) {
1042 cFYI(1, ("Error in Open = %d", rc));
1043 } else {
Steve French09d1db52005-04-28 22:41:08 -07001044 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1046 /* Let caller know file was created so we can set the mode. */
1047 /* Do we care about the CreateAction in any other cases? */
1048 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1049 *pOplock |= CIFS_CREATE_ACTION;
1050 if(pfile_info) {
1051 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1052 36 /* CreationTime to Attributes */);
1053 /* the file_info buf is endian converted by caller */
1054 pfile_info->AllocationSize = pSMBr->AllocationSize;
1055 pfile_info->EndOfFile = pSMBr->EndOfFile;
1056 pfile_info->NumberOfLinks = cpu_to_le32(1);
1057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 cifs_buf_release(pSMB);
1061 if (rc == -EAGAIN)
1062 goto openRetry;
1063 return rc;
1064}
1065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066int
1067CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001068 const int netfid, const unsigned int count,
1069 const __u64 lseek, unsigned int *nbytes, char **buf,
1070 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
1072 int rc = -EACCES;
1073 READ_REQ *pSMB = NULL;
1074 READ_RSP *pSMBr = NULL;
1075 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001076 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001077 int resp_buf_type = 0;
1078 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001081 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1082 wct = 12;
1083 else
1084 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001087 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 if (rc)
1089 return rc;
1090
1091 /* tcon and ses pointer are checked in smb_init */
1092 if (tcon->ses->server == NULL)
1093 return -ECONNABORTED;
1094
Steve Frenchec637e32005-12-12 20:53:18 -08001095 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 pSMB->Fid = netfid;
1097 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001098 if(wct == 12)
1099 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001100 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1101 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001102
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 pSMB->Remaining = 0;
1104 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1105 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001106 if(wct == 12)
1107 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1108 else {
1109 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001110 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001111 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001112 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001113 }
Steve Frenchec637e32005-12-12 20:53:18 -08001114
1115 iov[0].iov_base = (char *)pSMB;
1116 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1117 rc = SendReceive2(xid, tcon->ses, iov,
1118 1 /* num iovecs */,
1119 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001120 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001121 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 if (rc) {
1123 cERROR(1, ("Send error in read = %d", rc));
1124 } else {
1125 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1126 data_length = data_length << 16;
1127 data_length += le16_to_cpu(pSMBr->DataLength);
1128 *nbytes = data_length;
1129
1130 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001131 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 || (data_length > count)) {
1133 cFYI(1,("bad length %d for count %d",data_length,count));
1134 rc = -EIO;
1135 *nbytes = 0;
1136 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001137 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001139/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1140 cERROR(1,("Faulting on read rc = %d",rc));
1141 rc = -EFAULT;
1142 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001144 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 }
1146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Steve French4b8f9302006-02-26 16:41:18 +00001148/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001149 if(*buf) {
1150 if(resp_buf_type == CIFS_SMALL_BUFFER)
1151 cifs_small_buf_release(iov[0].iov_base);
1152 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1153 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001154 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1155 /* return buffer to caller to free */
1156 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001157 if(resp_buf_type == CIFS_SMALL_BUFFER)
1158 *pbuf_type = CIFS_SMALL_BUFFER;
1159 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1160 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001161 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001162
1163 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 since file handle passed in no longer valid */
1165 return rc;
1166}
1167
Steve Frenchec637e32005-12-12 20:53:18 -08001168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169int
1170CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1171 const int netfid, const unsigned int count,
1172 const __u64 offset, unsigned int *nbytes, const char *buf,
1173 const char __user * ubuf, const int long_op)
1174{
1175 int rc = -EACCES;
1176 WRITE_REQ *pSMB = NULL;
1177 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001178 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 __u32 bytes_sent;
1180 __u16 byte_count;
1181
1182 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001183 if(tcon->ses == NULL)
1184 return -ECONNABORTED;
1185
1186 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1187 wct = 14;
1188 else
1189 wct = 12;
1190
1191 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 (void **) &pSMBr);
1193 if (rc)
1194 return rc;
1195 /* tcon and ses pointer are checked in smb_init */
1196 if (tcon->ses->server == NULL)
1197 return -ECONNABORTED;
1198
1199 pSMB->AndXCommand = 0xFF; /* none */
1200 pSMB->Fid = netfid;
1201 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001202 if(wct == 14)
1203 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1204 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1205 return -EIO;
1206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 pSMB->Reserved = 0xFFFFFFFF;
1208 pSMB->WriteMode = 0;
1209 pSMB->Remaining = 0;
1210
1211 /* Can increase buffer size if buffer is big enough in some cases - ie we
1212 can send more if LARGE_WRITE_X capability returned by the server and if
1213 our buffer is big enough or if we convert to iovecs on socket writes
1214 and eliminate the copy to the CIFS buffer */
1215 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1216 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1217 } else {
1218 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1219 & ~0xFF;
1220 }
1221
1222 if (bytes_sent > count)
1223 bytes_sent = count;
1224 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001225 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 if(buf)
1227 memcpy(pSMB->Data,buf,bytes_sent);
1228 else if(ubuf) {
1229 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1230 cifs_buf_release(pSMB);
1231 return -EFAULT;
1232 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001233 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 /* No buffer */
1235 cifs_buf_release(pSMB);
1236 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001237 } /* else setting file size with write of zero bytes */
1238 if(wct == 14)
1239 byte_count = bytes_sent + 1; /* pad */
1240 else /* wct == 12 */ {
1241 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1244 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001245 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001246
1247 if(wct == 14)
1248 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001249 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001250 struct smb_com_writex_req * pSMBW =
1251 (struct smb_com_writex_req *)pSMB;
1252 pSMBW->ByteCount = cpu_to_le16(byte_count);
1253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1256 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001257 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if (rc) {
1259 cFYI(1, ("Send error in write = %d", rc));
1260 *nbytes = 0;
1261 } else {
1262 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1263 *nbytes = (*nbytes) << 16;
1264 *nbytes += le16_to_cpu(pSMBr->Count);
1265 }
1266
1267 cifs_buf_release(pSMB);
1268
1269 /* Note: On -EAGAIN error only caller can retry on handle based calls
1270 since file handle passed in no longer valid */
1271
1272 return rc;
1273}
1274
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001275int
1276CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001278 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1279 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280{
1281 int rc = -EACCES;
1282 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001283 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001284 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001285 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
Steve Frenchff7feac2005-11-15 16:45:16 -08001287 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1288
Steve French8cc64c62005-10-03 13:49:43 -07001289 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1290 wct = 14;
1291 else
1292 wct = 12;
1293 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (rc)
1295 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 /* tcon and ses pointer are checked in smb_init */
1297 if (tcon->ses->server == NULL)
1298 return -ECONNABORTED;
1299
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001300 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 pSMB->Fid = netfid;
1302 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001303 if(wct == 14)
1304 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1305 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1306 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 pSMB->Reserved = 0xFFFFFFFF;
1308 pSMB->WriteMode = 0;
1309 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 pSMB->DataOffset =
1312 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1313
Steve French3e844692005-10-03 13:37:24 -07001314 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1315 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001316 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001317 if(wct == 14)
1318 pSMB->hdr.smb_buf_length += count+1;
1319 else /* wct == 12 */
1320 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1321 if(wct == 14)
1322 pSMB->ByteCount = cpu_to_le16(count + 1);
1323 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1324 struct smb_com_writex_req * pSMBW =
1325 (struct smb_com_writex_req *)pSMB;
1326 pSMBW->ByteCount = cpu_to_le16(count + 5);
1327 }
Steve French3e844692005-10-03 13:37:24 -07001328 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001329 if(wct == 14)
1330 iov[0].iov_len = smb_hdr_len + 4;
1331 else /* wct == 12 pad bigger by four bytes */
1332 iov[0].iov_len = smb_hdr_len + 8;
1333
Steve French3e844692005-10-03 13:37:24 -07001334
Steve Frenchec637e32005-12-12 20:53:18 -08001335 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001336 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001337 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001339 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001341 } else if(resp_buf_type == 0) {
1342 /* presumably this can not happen, but best to be safe */
1343 rc = -EIO;
1344 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001345 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001346 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001347 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1348 *nbytes = (*nbytes) << 16;
1349 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Steve French4b8f9302006-02-26 16:41:18 +00001352/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001353 if(resp_buf_type == CIFS_SMALL_BUFFER)
1354 cifs_small_buf_release(iov[0].iov_base);
1355 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1356 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 /* Note: On -EAGAIN error only caller can retry on handle based calls
1359 since file handle passed in no longer valid */
1360
1361 return rc;
1362}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001363
1364
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365int
1366CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1367 const __u16 smb_file_id, const __u64 len,
1368 const __u64 offset, const __u32 numUnlock,
1369 const __u32 numLock, const __u8 lockType, const int waitFlag)
1370{
1371 int rc = 0;
1372 LOCK_REQ *pSMB = NULL;
1373 LOCK_RSP *pSMBr = NULL;
1374 int bytes_returned;
1375 int timeout = 0;
1376 __u16 count;
1377
1378 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001379 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (rc)
1382 return rc;
1383
Steve French46810cb2005-04-28 22:41:09 -07001384 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1387 timeout = -1; /* no response expected */
1388 pSMB->Timeout = 0;
1389 } else if (waitFlag == TRUE) {
1390 timeout = 3; /* blocking operation, no timeout */
1391 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1392 } else {
1393 pSMB->Timeout = 0;
1394 }
1395
1396 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1397 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1398 pSMB->LockType = lockType;
1399 pSMB->AndXCommand = 0xFF; /* none */
1400 pSMB->Fid = smb_file_id; /* netfid stays le */
1401
1402 if((numLock != 0) || (numUnlock != 0)) {
1403 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1404 /* BB where to store pid high? */
1405 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1406 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1407 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1408 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1409 count = sizeof(LOCKING_ANDX_RANGE);
1410 } else {
1411 /* oplock break */
1412 count = 0;
1413 }
1414 pSMB->hdr.smb_buf_length += count;
1415 pSMB->ByteCount = cpu_to_le16(count);
1416
1417 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1418 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001419 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 if (rc) {
1421 cFYI(1, ("Send error in Lock = %d", rc));
1422 }
Steve French46810cb2005-04-28 22:41:09 -07001423 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
1425 /* Note: On -EAGAIN error only caller can retry on handle based calls
1426 since file handle passed in no longer valid */
1427 return rc;
1428}
1429
1430int
Steve French08547b02006-02-28 22:39:25 +00001431CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1432 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001433 struct file_lock *pLockData, const __u16 lock_type,
1434 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001435{
1436 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1437 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1438 char *data_offset;
1439 struct cifs_posix_lock *parm_data;
1440 int rc = 0;
1441 int bytes_returned = 0;
1442 __u16 params, param_offset, offset, byte_count, count;
1443
1444 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001445
1446 if(pLockData == NULL)
1447 return EINVAL;
1448
Steve French08547b02006-02-28 22:39:25 +00001449 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1450
1451 if (rc)
1452 return rc;
1453
1454 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1455
1456 params = 6;
1457 pSMB->MaxSetupCount = 0;
1458 pSMB->Reserved = 0;
1459 pSMB->Flags = 0;
1460 pSMB->Timeout = 0;
1461 pSMB->Reserved2 = 0;
1462 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1463 offset = param_offset + params;
1464
1465 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1466
1467 count = sizeof(struct cifs_posix_lock);
1468 pSMB->MaxParameterCount = cpu_to_le16(2);
1469 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1470 pSMB->SetupCount = 1;
1471 pSMB->Reserved3 = 0;
1472 if(get_flag)
1473 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1474 else
1475 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1476 byte_count = 3 /* pad */ + params + count;
1477 pSMB->DataCount = cpu_to_le16(count);
1478 pSMB->ParameterCount = cpu_to_le16(params);
1479 pSMB->TotalDataCount = pSMB->DataCount;
1480 pSMB->TotalParameterCount = pSMB->ParameterCount;
1481 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1482 parm_data = (struct cifs_posix_lock *)
1483 (((char *) &pSMB->hdr.Protocol) + offset);
1484
1485 parm_data->lock_type = cpu_to_le16(lock_type);
1486 if(waitFlag)
Steve Frenchcec6815a2006-05-30 18:07:17 +00001487 parm_data->lock_flags = cpu_to_le16(1);
Steve French08547b02006-02-28 22:39:25 +00001488 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001489 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001490 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001491
1492 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001493 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001494 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1495 pSMB->Reserved4 = 0;
1496 pSMB->hdr.smb_buf_length += byte_count;
1497 pSMB->ByteCount = cpu_to_le16(byte_count);
1498 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1500 if (rc) {
1501 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001502 } else if (get_flag) {
1503 /* lock structure can be returned on get */
1504 __u16 data_offset;
1505 __u16 data_count;
1506 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001507
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001508 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1509 rc = -EIO; /* bad smb */
1510 goto plk_err_exit;
1511 }
1512 if(pLockData == NULL) {
1513 rc = -EINVAL;
1514 goto plk_err_exit;
1515 }
1516 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1517 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1518 if(data_count < sizeof(struct cifs_posix_lock)) {
1519 rc = -EIO;
1520 goto plk_err_exit;
1521 }
1522 parm_data = (struct cifs_posix_lock *)
1523 ((char *)&pSMBr->hdr.Protocol + data_offset);
1524 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1525 pLockData->fl_type = F_UNLCK;
1526 }
1527
1528plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001529 if (pSMB)
1530 cifs_small_buf_release(pSMB);
1531
1532 /* Note: On -EAGAIN error only caller can retry on handle based calls
1533 since file handle passed in no longer valid */
1534
1535 return rc;
1536}
1537
1538
1539int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1541{
1542 int rc = 0;
1543 CLOSE_REQ *pSMB = NULL;
1544 CLOSE_RSP *pSMBr = NULL;
1545 int bytes_returned;
1546 cFYI(1, ("In CIFSSMBClose"));
1547
1548/* do not retry on dead session on close */
1549 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1550 if(rc == -EAGAIN)
1551 return 0;
1552 if (rc)
1553 return rc;
1554
1555 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1556
1557 pSMB->FileID = (__u16) smb_file_id;
1558 pSMB->LastWriteTime = 0;
1559 pSMB->ByteCount = 0;
1560 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1561 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001562 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 if (rc) {
1564 if(rc!=-EINTR) {
1565 /* EINTR is expected when user ctl-c to kill app */
1566 cERROR(1, ("Send error in Close = %d", rc));
1567 }
1568 }
1569
1570 cifs_small_buf_release(pSMB);
1571
1572 /* Since session is dead, file will be closed on server already */
1573 if(rc == -EAGAIN)
1574 rc = 0;
1575
1576 return rc;
1577}
1578
1579int
1580CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1581 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001582 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583{
1584 int rc = 0;
1585 RENAME_REQ *pSMB = NULL;
1586 RENAME_RSP *pSMBr = NULL;
1587 int bytes_returned;
1588 int name_len, name_len2;
1589 __u16 count;
1590
1591 cFYI(1, ("In CIFSSMBRename"));
1592renameRetry:
1593 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1594 (void **) &pSMBr);
1595 if (rc)
1596 return rc;
1597
1598 pSMB->BufferFormat = 0x04;
1599 pSMB->SearchAttributes =
1600 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1601 ATTR_DIRECTORY);
1602
1603 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1604 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001605 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001606 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 name_len++; /* trailing null */
1608 name_len *= 2;
1609 pSMB->OldFileName[name_len] = 0x04; /* pad */
1610 /* protocol requires ASCII signature byte on Unicode string */
1611 pSMB->OldFileName[name_len + 1] = 0x00;
1612 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001613 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001614 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1616 name_len2 *= 2; /* convert to bytes */
1617 } else { /* BB improve the check for buffer overruns BB */
1618 name_len = strnlen(fromName, PATH_MAX);
1619 name_len++; /* trailing null */
1620 strncpy(pSMB->OldFileName, fromName, name_len);
1621 name_len2 = strnlen(toName, PATH_MAX);
1622 name_len2++; /* trailing null */
1623 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1624 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1625 name_len2++; /* trailing null */
1626 name_len2++; /* signature byte */
1627 }
1628
1629 count = 1 /* 1st signature byte */ + name_len + name_len2;
1630 pSMB->hdr.smb_buf_length += count;
1631 pSMB->ByteCount = cpu_to_le16(count);
1632
1633 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1634 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001635 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 if (rc) {
1637 cFYI(1, ("Send error in rename = %d", rc));
1638 }
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 cifs_buf_release(pSMB);
1641
1642 if (rc == -EAGAIN)
1643 goto renameRetry;
1644
1645 return rc;
1646}
1647
1648int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001649 int netfid, char * target_name,
1650 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651{
1652 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1653 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1654 struct set_file_rename * rename_info;
1655 char *data_offset;
1656 char dummy_string[30];
1657 int rc = 0;
1658 int bytes_returned = 0;
1659 int len_of_str;
1660 __u16 params, param_offset, offset, count, byte_count;
1661
1662 cFYI(1, ("Rename to File by handle"));
1663 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1664 (void **) &pSMBr);
1665 if (rc)
1666 return rc;
1667
1668 params = 6;
1669 pSMB->MaxSetupCount = 0;
1670 pSMB->Reserved = 0;
1671 pSMB->Flags = 0;
1672 pSMB->Timeout = 0;
1673 pSMB->Reserved2 = 0;
1674 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1675 offset = param_offset + params;
1676
1677 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1678 rename_info = (struct set_file_rename *) data_offset;
1679 pSMB->MaxParameterCount = cpu_to_le16(2);
1680 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1681 pSMB->SetupCount = 1;
1682 pSMB->Reserved3 = 0;
1683 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1684 byte_count = 3 /* pad */ + params;
1685 pSMB->ParameterCount = cpu_to_le16(params);
1686 pSMB->TotalParameterCount = pSMB->ParameterCount;
1687 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1688 pSMB->DataOffset = cpu_to_le16(offset);
1689 /* construct random name ".cifs_tmp<inodenum><mid>" */
1690 rename_info->overwrite = cpu_to_le32(1);
1691 rename_info->root_fid = 0;
1692 /* unicode only call */
1693 if(target_name == NULL) {
1694 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001695 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001696 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001698 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001699 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 }
1701 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1702 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1703 byte_count += count;
1704 pSMB->DataCount = cpu_to_le16(count);
1705 pSMB->TotalDataCount = pSMB->DataCount;
1706 pSMB->Fid = netfid;
1707 pSMB->InformationLevel =
1708 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1709 pSMB->Reserved4 = 0;
1710 pSMB->hdr.smb_buf_length += byte_count;
1711 pSMB->ByteCount = cpu_to_le16(byte_count);
1712 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1713 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001714 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 if (rc) {
1716 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1717 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 cifs_buf_release(pSMB);
1720
1721 /* Note: On -EAGAIN error only caller can retry on handle based calls
1722 since file handle passed in no longer valid */
1723
1724 return rc;
1725}
1726
1727int
1728CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1729 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001730 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
1732 int rc = 0;
1733 COPY_REQ *pSMB = NULL;
1734 COPY_RSP *pSMBr = NULL;
1735 int bytes_returned;
1736 int name_len, name_len2;
1737 __u16 count;
1738
1739 cFYI(1, ("In CIFSSMBCopy"));
1740copyRetry:
1741 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1742 (void **) &pSMBr);
1743 if (rc)
1744 return rc;
1745
1746 pSMB->BufferFormat = 0x04;
1747 pSMB->Tid2 = target_tid;
1748
1749 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1750
1751 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001752 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001753 fromName, PATH_MAX, nls_codepage,
1754 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 name_len++; /* trailing null */
1756 name_len *= 2;
1757 pSMB->OldFileName[name_len] = 0x04; /* pad */
1758 /* protocol requires ASCII signature byte on Unicode string */
1759 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001760 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001761 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1763 name_len2 *= 2; /* convert to bytes */
1764 } else { /* BB improve the check for buffer overruns BB */
1765 name_len = strnlen(fromName, PATH_MAX);
1766 name_len++; /* trailing null */
1767 strncpy(pSMB->OldFileName, fromName, name_len);
1768 name_len2 = strnlen(toName, PATH_MAX);
1769 name_len2++; /* trailing null */
1770 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1771 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1772 name_len2++; /* trailing null */
1773 name_len2++; /* signature byte */
1774 }
1775
1776 count = 1 /* 1st signature byte */ + name_len + name_len2;
1777 pSMB->hdr.smb_buf_length += count;
1778 pSMB->ByteCount = cpu_to_le16(count);
1779
1780 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1781 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1782 if (rc) {
1783 cFYI(1, ("Send error in copy = %d with %d files copied",
1784 rc, le16_to_cpu(pSMBr->CopyCount)));
1785 }
1786 if (pSMB)
1787 cifs_buf_release(pSMB);
1788
1789 if (rc == -EAGAIN)
1790 goto copyRetry;
1791
1792 return rc;
1793}
1794
1795int
1796CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1797 const char *fromName, const char *toName,
1798 const struct nls_table *nls_codepage)
1799{
1800 TRANSACTION2_SPI_REQ *pSMB = NULL;
1801 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1802 char *data_offset;
1803 int name_len;
1804 int name_len_target;
1805 int rc = 0;
1806 int bytes_returned = 0;
1807 __u16 params, param_offset, offset, byte_count;
1808
1809 cFYI(1, ("In Symlink Unix style"));
1810createSymLinkRetry:
1811 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1812 (void **) &pSMBr);
1813 if (rc)
1814 return rc;
1815
1816 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1817 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001818 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 /* find define for this maxpathcomponent */
1820 , nls_codepage);
1821 name_len++; /* trailing null */
1822 name_len *= 2;
1823
1824 } else { /* BB improve the check for buffer overruns BB */
1825 name_len = strnlen(fromName, PATH_MAX);
1826 name_len++; /* trailing null */
1827 strncpy(pSMB->FileName, fromName, name_len);
1828 }
1829 params = 6 + name_len;
1830 pSMB->MaxSetupCount = 0;
1831 pSMB->Reserved = 0;
1832 pSMB->Flags = 0;
1833 pSMB->Timeout = 0;
1834 pSMB->Reserved2 = 0;
1835 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1836 InformationLevel) - 4;
1837 offset = param_offset + params;
1838
1839 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1841 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001842 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 /* find define for this maxpathcomponent */
1844 , nls_codepage);
1845 name_len_target++; /* trailing null */
1846 name_len_target *= 2;
1847 } else { /* BB improve the check for buffer overruns BB */
1848 name_len_target = strnlen(toName, PATH_MAX);
1849 name_len_target++; /* trailing null */
1850 strncpy(data_offset, toName, name_len_target);
1851 }
1852
1853 pSMB->MaxParameterCount = cpu_to_le16(2);
1854 /* BB find exact max on data count below from sess */
1855 pSMB->MaxDataCount = cpu_to_le16(1000);
1856 pSMB->SetupCount = 1;
1857 pSMB->Reserved3 = 0;
1858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1859 byte_count = 3 /* pad */ + params + name_len_target;
1860 pSMB->DataCount = cpu_to_le16(name_len_target);
1861 pSMB->ParameterCount = cpu_to_le16(params);
1862 pSMB->TotalDataCount = pSMB->DataCount;
1863 pSMB->TotalParameterCount = pSMB->ParameterCount;
1864 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1865 pSMB->DataOffset = cpu_to_le16(offset);
1866 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1867 pSMB->Reserved4 = 0;
1868 pSMB->hdr.smb_buf_length += byte_count;
1869 pSMB->ByteCount = cpu_to_le16(byte_count);
1870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001872 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (rc) {
1874 cFYI(1,
1875 ("Send error in SetPathInfo (create symlink) = %d",
1876 rc));
1877 }
1878
1879 if (pSMB)
1880 cifs_buf_release(pSMB);
1881
1882 if (rc == -EAGAIN)
1883 goto createSymLinkRetry;
1884
1885 return rc;
1886}
1887
1888int
1889CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1890 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001891 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892{
1893 TRANSACTION2_SPI_REQ *pSMB = NULL;
1894 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1895 char *data_offset;
1896 int name_len;
1897 int name_len_target;
1898 int rc = 0;
1899 int bytes_returned = 0;
1900 __u16 params, param_offset, offset, byte_count;
1901
1902 cFYI(1, ("In Create Hard link Unix style"));
1903createHardLinkRetry:
1904 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1905 (void **) &pSMBr);
1906 if (rc)
1907 return rc;
1908
1909 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001910 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001911 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 name_len++; /* trailing null */
1913 name_len *= 2;
1914
1915 } else { /* BB improve the check for buffer overruns BB */
1916 name_len = strnlen(toName, PATH_MAX);
1917 name_len++; /* trailing null */
1918 strncpy(pSMB->FileName, toName, name_len);
1919 }
1920 params = 6 + name_len;
1921 pSMB->MaxSetupCount = 0;
1922 pSMB->Reserved = 0;
1923 pSMB->Flags = 0;
1924 pSMB->Timeout = 0;
1925 pSMB->Reserved2 = 0;
1926 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1927 InformationLevel) - 4;
1928 offset = param_offset + params;
1929
1930 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1931 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1932 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001933 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001934 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 name_len_target++; /* trailing null */
1936 name_len_target *= 2;
1937 } else { /* BB improve the check for buffer overruns BB */
1938 name_len_target = strnlen(fromName, PATH_MAX);
1939 name_len_target++; /* trailing null */
1940 strncpy(data_offset, fromName, name_len_target);
1941 }
1942
1943 pSMB->MaxParameterCount = cpu_to_le16(2);
1944 /* BB find exact max on data count below from sess*/
1945 pSMB->MaxDataCount = cpu_to_le16(1000);
1946 pSMB->SetupCount = 1;
1947 pSMB->Reserved3 = 0;
1948 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1949 byte_count = 3 /* pad */ + params + name_len_target;
1950 pSMB->ParameterCount = cpu_to_le16(params);
1951 pSMB->TotalParameterCount = pSMB->ParameterCount;
1952 pSMB->DataCount = cpu_to_le16(name_len_target);
1953 pSMB->TotalDataCount = pSMB->DataCount;
1954 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1955 pSMB->DataOffset = cpu_to_le16(offset);
1956 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1957 pSMB->Reserved4 = 0;
1958 pSMB->hdr.smb_buf_length += byte_count;
1959 pSMB->ByteCount = cpu_to_le16(byte_count);
1960 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1961 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001962 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (rc) {
1964 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1965 }
1966
1967 cifs_buf_release(pSMB);
1968 if (rc == -EAGAIN)
1969 goto createHardLinkRetry;
1970
1971 return rc;
1972}
1973
1974int
1975CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1976 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001977 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978{
1979 int rc = 0;
1980 NT_RENAME_REQ *pSMB = NULL;
1981 RENAME_RSP *pSMBr = NULL;
1982 int bytes_returned;
1983 int name_len, name_len2;
1984 __u16 count;
1985
1986 cFYI(1, ("In CIFSCreateHardLink"));
1987winCreateHardLinkRetry:
1988
1989 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1990 (void **) &pSMBr);
1991 if (rc)
1992 return rc;
1993
1994 pSMB->SearchAttributes =
1995 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1996 ATTR_DIRECTORY);
1997 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1998 pSMB->ClusterCount = 0;
1999
2000 pSMB->BufferFormat = 0x04;
2001
2002 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2003 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002004 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002005 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 name_len++; /* trailing null */
2007 name_len *= 2;
2008 pSMB->OldFileName[name_len] = 0; /* pad */
2009 pSMB->OldFileName[name_len + 1] = 0x04;
2010 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002011 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002012 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2014 name_len2 *= 2; /* convert to bytes */
2015 } else { /* BB improve the check for buffer overruns BB */
2016 name_len = strnlen(fromName, PATH_MAX);
2017 name_len++; /* trailing null */
2018 strncpy(pSMB->OldFileName, fromName, name_len);
2019 name_len2 = strnlen(toName, PATH_MAX);
2020 name_len2++; /* trailing null */
2021 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2022 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2023 name_len2++; /* trailing null */
2024 name_len2++; /* signature byte */
2025 }
2026
2027 count = 1 /* string type byte */ + name_len + name_len2;
2028 pSMB->hdr.smb_buf_length += count;
2029 pSMB->ByteCount = cpu_to_le16(count);
2030
2031 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002033 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 if (rc) {
2035 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2036 }
2037 cifs_buf_release(pSMB);
2038 if (rc == -EAGAIN)
2039 goto winCreateHardLinkRetry;
2040
2041 return rc;
2042}
2043
2044int
2045CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2046 const unsigned char *searchName,
2047 char *symlinkinfo, const int buflen,
2048 const struct nls_table *nls_codepage)
2049{
2050/* SMB_QUERY_FILE_UNIX_LINK */
2051 TRANSACTION2_QPI_REQ *pSMB = NULL;
2052 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2053 int rc = 0;
2054 int bytes_returned;
2055 int name_len;
2056 __u16 params, byte_count;
2057
2058 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2059
2060querySymLinkRetry:
2061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2062 (void **) &pSMBr);
2063 if (rc)
2064 return rc;
2065
2066 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2067 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002068 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 /* find define for this maxpathcomponent */
2070 , nls_codepage);
2071 name_len++; /* trailing null */
2072 name_len *= 2;
2073 } else { /* BB improve the check for buffer overruns BB */
2074 name_len = strnlen(searchName, PATH_MAX);
2075 name_len++; /* trailing null */
2076 strncpy(pSMB->FileName, searchName, name_len);
2077 }
2078
2079 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2080 pSMB->TotalDataCount = 0;
2081 pSMB->MaxParameterCount = cpu_to_le16(2);
2082 /* BB find exact max data count below from sess structure BB */
2083 pSMB->MaxDataCount = cpu_to_le16(4000);
2084 pSMB->MaxSetupCount = 0;
2085 pSMB->Reserved = 0;
2086 pSMB->Flags = 0;
2087 pSMB->Timeout = 0;
2088 pSMB->Reserved2 = 0;
2089 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2090 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2091 pSMB->DataCount = 0;
2092 pSMB->DataOffset = 0;
2093 pSMB->SetupCount = 1;
2094 pSMB->Reserved3 = 0;
2095 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2096 byte_count = params + 1 /* pad */ ;
2097 pSMB->TotalParameterCount = cpu_to_le16(params);
2098 pSMB->ParameterCount = pSMB->TotalParameterCount;
2099 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2100 pSMB->Reserved4 = 0;
2101 pSMB->hdr.smb_buf_length += byte_count;
2102 pSMB->ByteCount = cpu_to_le16(byte_count);
2103
2104 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2106 if (rc) {
2107 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2108 } else {
2109 /* decode response */
2110
2111 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2112 if (rc || (pSMBr->ByteCount < 2))
2113 /* BB also check enough total bytes returned */
2114 rc = -EIO; /* bad smb */
2115 else {
2116 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2117 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2118
2119 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2120 name_len = UniStrnlen((wchar_t *) ((char *)
2121 &pSMBr->hdr.Protocol +data_offset),
2122 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002123 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002125 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 data_offset),
2127 name_len, nls_codepage);
2128 } else {
2129 strncpy(symlinkinfo,
2130 (char *) &pSMBr->hdr.Protocol +
2131 data_offset,
2132 min_t(const int, buflen, count));
2133 }
2134 symlinkinfo[buflen] = 0;
2135 /* just in case so calling code does not go off the end of buffer */
2136 }
2137 }
2138 cifs_buf_release(pSMB);
2139 if (rc == -EAGAIN)
2140 goto querySymLinkRetry;
2141 return rc;
2142}
2143
Steve French0a4b92c2006-01-12 15:44:21 -08002144/* Initialize NT TRANSACT SMB into small smb request buffer.
2145 This assumes that all NT TRANSACTS that we init here have
2146 total parm and data under about 400 bytes (to fit in small cifs
2147 buffer size), which is the case so far, it easily fits. NB:
2148 Setup words themselves and ByteCount
2149 MaxSetupCount (size of returned setup area) and
2150 MaxParameterCount (returned parms size) must be set by caller */
2151static int
2152smb_init_ntransact(const __u16 sub_command, const int setup_count,
2153 const int parm_len, struct cifsTconInfo *tcon,
2154 void ** ret_buf)
2155{
2156 int rc;
2157 __u32 temp_offset;
2158 struct smb_com_ntransact_req * pSMB;
2159
2160 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2161 (void **)&pSMB);
2162 if (rc)
2163 return rc;
2164 *ret_buf = (void *)pSMB;
2165 pSMB->Reserved = 0;
2166 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2167 pSMB->TotalDataCount = 0;
2168 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2169 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2170 pSMB->ParameterCount = pSMB->TotalParameterCount;
2171 pSMB->DataCount = pSMB->TotalDataCount;
2172 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2173 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2174 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2175 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2176 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2177 pSMB->SubCommand = cpu_to_le16(sub_command);
2178 return 0;
2179}
2180
2181static int
2182validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2183 int * pdatalen, int * pparmlen)
2184{
2185 char * end_of_smb;
2186 __u32 data_count, data_offset, parm_count, parm_offset;
2187 struct smb_com_ntransact_rsp * pSMBr;
2188
2189 if(buf == NULL)
2190 return -EINVAL;
2191
2192 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2193
2194 /* ByteCount was converted from little endian in SendReceive */
2195 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2196 (char *)&pSMBr->ByteCount;
2197
2198
2199 data_offset = le32_to_cpu(pSMBr->DataOffset);
2200 data_count = le32_to_cpu(pSMBr->DataCount);
2201 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2202 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2203
2204 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2205 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2206
2207 /* should we also check that parm and data areas do not overlap? */
2208 if(*ppparm > end_of_smb) {
2209 cFYI(1,("parms start after end of smb"));
2210 return -EINVAL;
2211 } else if(parm_count + *ppparm > end_of_smb) {
2212 cFYI(1,("parm end after end of smb"));
2213 return -EINVAL;
2214 } else if(*ppdata > end_of_smb) {
2215 cFYI(1,("data starts after end of smb"));
2216 return -EINVAL;
2217 } else if(data_count + *ppdata > end_of_smb) {
2218 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2219 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2220 return -EINVAL;
2221 } else if(parm_count + data_count > pSMBr->ByteCount) {
2222 cFYI(1,("parm count and data count larger than SMB"));
2223 return -EINVAL;
2224 }
2225 return 0;
2226}
2227
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228int
2229CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2230 const unsigned char *searchName,
2231 char *symlinkinfo, const int buflen,__u16 fid,
2232 const struct nls_table *nls_codepage)
2233{
2234 int rc = 0;
2235 int bytes_returned;
2236 int name_len;
2237 struct smb_com_transaction_ioctl_req * pSMB;
2238 struct smb_com_transaction_ioctl_rsp * pSMBr;
2239
2240 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2241 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2242 (void **) &pSMBr);
2243 if (rc)
2244 return rc;
2245
2246 pSMB->TotalParameterCount = 0 ;
2247 pSMB->TotalDataCount = 0;
2248 pSMB->MaxParameterCount = cpu_to_le32(2);
2249 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002250 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2251 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 pSMB->MaxSetupCount = 4;
2253 pSMB->Reserved = 0;
2254 pSMB->ParameterOffset = 0;
2255 pSMB->DataCount = 0;
2256 pSMB->DataOffset = 0;
2257 pSMB->SetupCount = 4;
2258 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2259 pSMB->ParameterCount = pSMB->TotalParameterCount;
2260 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2261 pSMB->IsFsctl = 1; /* FSCTL */
2262 pSMB->IsRootFlag = 0;
2263 pSMB->Fid = fid; /* file handle always le */
2264 pSMB->ByteCount = 0;
2265
2266 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2267 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2268 if (rc) {
2269 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2270 } else { /* decode response */
2271 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2272 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2273 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2274 /* BB also check enough total bytes returned */
2275 rc = -EIO; /* bad smb */
2276 else {
2277 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002278 char * end_of_smb = 2 /* sizeof byte count */ +
2279 pSMBr->ByteCount +
2280 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281
2282 struct reparse_data * reparse_buf = (struct reparse_data *)
2283 ((char *)&pSMBr->hdr.Protocol + data_offset);
2284 if((char*)reparse_buf >= end_of_smb) {
2285 rc = -EIO;
2286 goto qreparse_out;
2287 }
2288 if((reparse_buf->LinkNamesBuf +
2289 reparse_buf->TargetNameOffset +
2290 reparse_buf->TargetNameLen) >
2291 end_of_smb) {
2292 cFYI(1,("reparse buf extended beyond SMB"));
2293 rc = -EIO;
2294 goto qreparse_out;
2295 }
2296
2297 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2298 name_len = UniStrnlen((wchar_t *)
2299 (reparse_buf->LinkNamesBuf +
2300 reparse_buf->TargetNameOffset),
2301 min(buflen/2, reparse_buf->TargetNameLen / 2));
2302 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002303 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 reparse_buf->TargetNameOffset),
2305 name_len, nls_codepage);
2306 } else { /* ASCII names */
2307 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2308 reparse_buf->TargetNameOffset,
2309 min_t(const int, buflen, reparse_buf->TargetNameLen));
2310 }
2311 } else {
2312 rc = -EIO;
2313 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2314 }
2315 symlinkinfo[buflen] = 0; /* just in case so the caller
2316 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002317 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 }
2319 }
2320qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002321 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
2323 /* Note: On -EAGAIN error only caller can retry on handle based calls
2324 since file handle passed in no longer valid */
2325
2326 return rc;
2327}
2328
2329#ifdef CONFIG_CIFS_POSIX
2330
2331/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2332static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2333{
2334 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002335 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2336 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2337 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2339
2340 return;
2341}
2342
2343/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002344static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2345 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346{
2347 int size = 0;
2348 int i;
2349 __u16 count;
2350 struct cifs_posix_ace * pACE;
2351 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2352 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2353
2354 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2355 return -EOPNOTSUPP;
2356
2357 if(acl_type & ACL_TYPE_ACCESS) {
2358 count = le16_to_cpu(cifs_acl->access_entry_count);
2359 pACE = &cifs_acl->ace_array[0];
2360 size = sizeof(struct cifs_posix_acl);
2361 size += sizeof(struct cifs_posix_ace) * count;
2362 /* check if we would go beyond end of SMB */
2363 if(size_of_data_area < size) {
2364 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2365 return -EINVAL;
2366 }
2367 } else if(acl_type & ACL_TYPE_DEFAULT) {
2368 count = le16_to_cpu(cifs_acl->access_entry_count);
2369 size = sizeof(struct cifs_posix_acl);
2370 size += sizeof(struct cifs_posix_ace) * count;
2371/* skip past access ACEs to get to default ACEs */
2372 pACE = &cifs_acl->ace_array[count];
2373 count = le16_to_cpu(cifs_acl->default_entry_count);
2374 size += sizeof(struct cifs_posix_ace) * count;
2375 /* check if we would go beyond end of SMB */
2376 if(size_of_data_area < size)
2377 return -EINVAL;
2378 } else {
2379 /* illegal type */
2380 return -EINVAL;
2381 }
2382
2383 size = posix_acl_xattr_size(count);
2384 if((buflen == 0) || (local_acl == NULL)) {
2385 /* used to query ACL EA size */
2386 } else if(size > buflen) {
2387 return -ERANGE;
2388 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002389 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 for(i = 0;i < count ;i++) {
2391 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2392 pACE ++;
2393 }
2394 }
2395 return size;
2396}
2397
2398static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2399 const posix_acl_xattr_entry * local_ace)
2400{
2401 __u16 rc = 0; /* 0 = ACL converted ok */
2402
Steve Frenchff7feac2005-11-15 16:45:16 -08002403 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2404 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002406 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 /* Probably no need to le convert -1 on any arch but can not hurt */
2408 cifs_ace->cifs_uid = cpu_to_le64(-1);
2409 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002410 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2412 return rc;
2413}
2414
2415/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2416static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2417 const int acl_type)
2418{
2419 __u16 rc = 0;
2420 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2421 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2422 int count;
2423 int i;
2424
2425 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2426 return 0;
2427
2428 count = posix_acl_xattr_count((size_t)buflen);
2429 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002430 count, buflen, le32_to_cpu(local_acl->a_version)));
2431 if(le32_to_cpu(local_acl->a_version) != 2) {
2432 cFYI(1,("unknown POSIX ACL version %d",
2433 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 return 0;
2435 }
2436 cifs_acl->version = cpu_to_le16(1);
2437 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002438 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002440 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 else {
2442 cFYI(1,("unknown ACL type %d",acl_type));
2443 return 0;
2444 }
2445 for(i=0;i<count;i++) {
2446 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2447 &local_acl->a_entries[i]);
2448 if(rc != 0) {
2449 /* ACE not converted */
2450 break;
2451 }
2452 }
2453 if(rc == 0) {
2454 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2455 rc += sizeof(struct cifs_posix_acl);
2456 /* BB add check to make sure ACL does not overflow SMB */
2457 }
2458 return rc;
2459}
2460
2461int
2462CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2463 const unsigned char *searchName,
2464 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002465 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466{
2467/* SMB_QUERY_POSIX_ACL */
2468 TRANSACTION2_QPI_REQ *pSMB = NULL;
2469 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2470 int rc = 0;
2471 int bytes_returned;
2472 int name_len;
2473 __u16 params, byte_count;
2474
2475 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2476
2477queryAclRetry:
2478 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2479 (void **) &pSMBr);
2480 if (rc)
2481 return rc;
2482
2483 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2484 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002485 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002486 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 name_len++; /* trailing null */
2488 name_len *= 2;
2489 pSMB->FileName[name_len] = 0;
2490 pSMB->FileName[name_len+1] = 0;
2491 } else { /* BB improve the check for buffer overruns BB */
2492 name_len = strnlen(searchName, PATH_MAX);
2493 name_len++; /* trailing null */
2494 strncpy(pSMB->FileName, searchName, name_len);
2495 }
2496
2497 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2498 pSMB->TotalDataCount = 0;
2499 pSMB->MaxParameterCount = cpu_to_le16(2);
2500 /* BB find exact max data count below from sess structure BB */
2501 pSMB->MaxDataCount = cpu_to_le16(4000);
2502 pSMB->MaxSetupCount = 0;
2503 pSMB->Reserved = 0;
2504 pSMB->Flags = 0;
2505 pSMB->Timeout = 0;
2506 pSMB->Reserved2 = 0;
2507 pSMB->ParameterOffset = cpu_to_le16(
2508 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2509 pSMB->DataCount = 0;
2510 pSMB->DataOffset = 0;
2511 pSMB->SetupCount = 1;
2512 pSMB->Reserved3 = 0;
2513 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2514 byte_count = params + 1 /* pad */ ;
2515 pSMB->TotalParameterCount = cpu_to_le16(params);
2516 pSMB->ParameterCount = pSMB->TotalParameterCount;
2517 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2518 pSMB->Reserved4 = 0;
2519 pSMB->hdr.smb_buf_length += byte_count;
2520 pSMB->ByteCount = cpu_to_le16(byte_count);
2521
2522 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2523 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002524 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 if (rc) {
2526 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2527 } else {
2528 /* decode response */
2529
2530 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2531 if (rc || (pSMBr->ByteCount < 2))
2532 /* BB also check enough total bytes returned */
2533 rc = -EIO; /* bad smb */
2534 else {
2535 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2536 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2537 rc = cifs_copy_posix_acl(acl_inf,
2538 (char *)&pSMBr->hdr.Protocol+data_offset,
2539 buflen,acl_type,count);
2540 }
2541 }
2542 cifs_buf_release(pSMB);
2543 if (rc == -EAGAIN)
2544 goto queryAclRetry;
2545 return rc;
2546}
2547
2548int
2549CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2550 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002551 const char *local_acl, const int buflen,
2552 const int acl_type,
2553 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554{
2555 struct smb_com_transaction2_spi_req *pSMB = NULL;
2556 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2557 char *parm_data;
2558 int name_len;
2559 int rc = 0;
2560 int bytes_returned = 0;
2561 __u16 params, byte_count, data_count, param_offset, offset;
2562
2563 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2564setAclRetry:
2565 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2566 (void **) &pSMBr);
2567 if (rc)
2568 return rc;
2569 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2570 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002571 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002572 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 name_len++; /* trailing null */
2574 name_len *= 2;
2575 } else { /* BB improve the check for buffer overruns BB */
2576 name_len = strnlen(fileName, PATH_MAX);
2577 name_len++; /* trailing null */
2578 strncpy(pSMB->FileName, fileName, name_len);
2579 }
2580 params = 6 + name_len;
2581 pSMB->MaxParameterCount = cpu_to_le16(2);
2582 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2583 pSMB->MaxSetupCount = 0;
2584 pSMB->Reserved = 0;
2585 pSMB->Flags = 0;
2586 pSMB->Timeout = 0;
2587 pSMB->Reserved2 = 0;
2588 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2589 InformationLevel) - 4;
2590 offset = param_offset + params;
2591 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2592 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2593
2594 /* convert to on the wire format for POSIX ACL */
2595 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2596
2597 if(data_count == 0) {
2598 rc = -EOPNOTSUPP;
2599 goto setACLerrorExit;
2600 }
2601 pSMB->DataOffset = cpu_to_le16(offset);
2602 pSMB->SetupCount = 1;
2603 pSMB->Reserved3 = 0;
2604 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2605 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2606 byte_count = 3 /* pad */ + params + data_count;
2607 pSMB->DataCount = cpu_to_le16(data_count);
2608 pSMB->TotalDataCount = pSMB->DataCount;
2609 pSMB->ParameterCount = cpu_to_le16(params);
2610 pSMB->TotalParameterCount = pSMB->ParameterCount;
2611 pSMB->Reserved4 = 0;
2612 pSMB->hdr.smb_buf_length += byte_count;
2613 pSMB->ByteCount = cpu_to_le16(byte_count);
2614 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2616 if (rc) {
2617 cFYI(1, ("Set POSIX ACL returned %d", rc));
2618 }
2619
2620setACLerrorExit:
2621 cifs_buf_release(pSMB);
2622 if (rc == -EAGAIN)
2623 goto setAclRetry;
2624 return rc;
2625}
2626
Steve Frenchf654bac2005-04-28 22:41:04 -07002627/* BB fix tabs in this function FIXME BB */
2628int
2629CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2630 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2631{
2632 int rc = 0;
2633 struct smb_t2_qfi_req *pSMB = NULL;
2634 struct smb_t2_qfi_rsp *pSMBr = NULL;
2635 int bytes_returned;
2636 __u16 params, byte_count;
2637
2638 cFYI(1,("In GetExtAttr"));
2639 if(tcon == NULL)
2640 return -ENODEV;
2641
2642GetExtAttrRetry:
2643 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2644 (void **) &pSMBr);
2645 if (rc)
2646 return rc;
2647
Steve Frenchc67593a2005-04-28 22:41:04 -07002648 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002649 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002650 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002651 /* BB find exact max data count below from sess structure BB */
2652 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2653 pSMB->t2.MaxSetupCount = 0;
2654 pSMB->t2.Reserved = 0;
2655 pSMB->t2.Flags = 0;
2656 pSMB->t2.Timeout = 0;
2657 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002658 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2659 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002660 pSMB->t2.DataCount = 0;
2661 pSMB->t2.DataOffset = 0;
2662 pSMB->t2.SetupCount = 1;
2663 pSMB->t2.Reserved3 = 0;
2664 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002665 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002666 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2667 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2668 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002669 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002670 pSMB->Fid = netfid;
2671 pSMB->hdr.smb_buf_length += byte_count;
2672 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2673
2674 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2675 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2676 if (rc) {
2677 cFYI(1, ("error %d in GetExtAttr", rc));
2678 } else {
2679 /* decode response */
2680 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2681 if (rc || (pSMBr->ByteCount < 2))
2682 /* BB also check enough total bytes returned */
2683 /* If rc should we check for EOPNOSUPP and
2684 disable the srvino flag? or in caller? */
2685 rc = -EIO; /* bad smb */
2686 else {
2687 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2688 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2689 struct file_chattr_info * pfinfo;
2690 /* BB Do we need a cast or hash here ? */
2691 if(count != 16) {
2692 cFYI(1, ("Illegal size ret in GetExtAttr"));
2693 rc = -EIO;
2694 goto GetExtAttrOut;
2695 }
2696 pfinfo = (struct file_chattr_info *)
2697 (data_offset + (char *) &pSMBr->hdr.Protocol);
2698 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2699 *pMask = le64_to_cpu(pfinfo->mask);
2700 }
2701 }
2702GetExtAttrOut:
2703 cifs_buf_release(pSMB);
2704 if (rc == -EAGAIN)
2705 goto GetExtAttrRetry;
2706 return rc;
2707}
2708
2709
2710#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
Steve Frencheeac8042006-01-13 21:34:58 -08002712
2713/* security id for everyone */
2714const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2715/* group users */
2716const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2717
Steve French0a4b92c2006-01-12 15:44:21 -08002718/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002719static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002720{
Steve French0a4b92c2006-01-12 15:44:21 -08002721 return 0;
2722}
2723
2724/* Get Security Descriptor (by handle) from remote server for a file or dir */
2725int
2726CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2727 /* BB fix up return info */ char *acl_inf, const int buflen,
2728 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2729{
2730 int rc = 0;
2731 int buf_type = 0;
2732 QUERY_SEC_DESC_REQ * pSMB;
2733 struct kvec iov[1];
2734
2735 cFYI(1, ("GetCifsACL"));
2736
2737 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2738 8 /* parm len */, tcon, (void **) &pSMB);
2739 if (rc)
2740 return rc;
2741
2742 pSMB->MaxParameterCount = cpu_to_le32(4);
2743 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2744 pSMB->MaxSetupCount = 0;
2745 pSMB->Fid = fid; /* file handle always le */
2746 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2747 CIFS_ACL_DACL);
2748 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2749 pSMB->hdr.smb_buf_length += 11;
2750 iov[0].iov_base = (char *)pSMB;
2751 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2752
2753 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2754 cifs_stats_inc(&tcon->num_acl_get);
2755 if (rc) {
2756 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2757 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002758 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002759 __le32 * parm;
2760 int parm_len;
2761 int data_len;
2762 int acl_len;
2763 struct smb_com_ntransact_rsp * pSMBr;
2764
2765/* validate_nttransact */
2766 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2767 (char **)&psec_desc,
2768 &parm_len, &data_len);
2769
2770 if(rc)
2771 goto qsec_out;
2772 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2773
2774 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2775
2776 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2777 rc = -EIO; /* bad smb */
2778 goto qsec_out;
2779 }
2780
2781/* BB check that data area is minimum length and as big as acl_len */
2782
2783 acl_len = le32_to_cpu(*(__le32 *)parm);
2784 /* BB check if(acl_len > bufsize) */
2785
2786 parse_sec_desc(psec_desc, acl_len);
2787 }
2788qsec_out:
2789 if(buf_type == CIFS_SMALL_BUFFER)
2790 cifs_small_buf_release(iov[0].iov_base);
2791 else if(buf_type == CIFS_LARGE_BUFFER)
2792 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002793/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002794 return rc;
2795}
2796
2797
Steve French6b8edfe2005-08-23 20:26:03 -07002798/* Legacy Query Path Information call for lookup to old servers such
2799 as Win9x/WinME */
2800int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2801 const unsigned char *searchName,
2802 FILE_ALL_INFO * pFinfo,
2803 const struct nls_table *nls_codepage, int remap)
2804{
2805 QUERY_INFORMATION_REQ * pSMB;
2806 QUERY_INFORMATION_RSP * pSMBr;
2807 int rc = 0;
2808 int bytes_returned;
2809 int name_len;
2810
2811 cFYI(1, ("In SMBQPath path %s", searchName));
2812QInfRetry:
2813 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2814 (void **) &pSMBr);
2815 if (rc)
2816 return rc;
2817
2818 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2819 name_len =
2820 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2821 PATH_MAX, nls_codepage, remap);
2822 name_len++; /* trailing null */
2823 name_len *= 2;
2824 } else {
2825 name_len = strnlen(searchName, PATH_MAX);
2826 name_len++; /* trailing null */
2827 strncpy(pSMB->FileName, searchName, name_len);
2828 }
2829 pSMB->BufferFormat = 0x04;
2830 name_len++; /* account for buffer type byte */
2831 pSMB->hdr.smb_buf_length += (__u16) name_len;
2832 pSMB->ByteCount = cpu_to_le16(name_len);
2833
2834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2836 if (rc) {
2837 cFYI(1, ("Send error in QueryInfo = %d", rc));
2838 } else if (pFinfo) { /* decode response */
2839 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002840 pFinfo->AllocationSize =
2841 cpu_to_le64(le32_to_cpu(pSMBr->size));
2842 pFinfo->EndOfFile = pFinfo->AllocationSize;
2843 pFinfo->Attributes =
2844 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002845 } else
2846 rc = -EIO; /* bad buffer passed in */
2847
2848 cifs_buf_release(pSMB);
2849
2850 if (rc == -EAGAIN)
2851 goto QInfRetry;
2852
2853 return rc;
2854}
2855
2856
2857
2858
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859int
2860CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2861 const unsigned char *searchName,
2862 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002863 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864{
2865/* level 263 SMB_QUERY_FILE_ALL_INFO */
2866 TRANSACTION2_QPI_REQ *pSMB = NULL;
2867 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2868 int rc = 0;
2869 int bytes_returned;
2870 int name_len;
2871 __u16 params, byte_count;
2872
2873/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2874QPathInfoRetry:
2875 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2876 (void **) &pSMBr);
2877 if (rc)
2878 return rc;
2879
2880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2881 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002882 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002883 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 name_len++; /* trailing null */
2885 name_len *= 2;
2886 } else { /* BB improve the check for buffer overruns BB */
2887 name_len = strnlen(searchName, PATH_MAX);
2888 name_len++; /* trailing null */
2889 strncpy(pSMB->FileName, searchName, name_len);
2890 }
2891
2892 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2893 pSMB->TotalDataCount = 0;
2894 pSMB->MaxParameterCount = cpu_to_le16(2);
2895 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2896 pSMB->MaxSetupCount = 0;
2897 pSMB->Reserved = 0;
2898 pSMB->Flags = 0;
2899 pSMB->Timeout = 0;
2900 pSMB->Reserved2 = 0;
2901 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2902 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2903 pSMB->DataCount = 0;
2904 pSMB->DataOffset = 0;
2905 pSMB->SetupCount = 1;
2906 pSMB->Reserved3 = 0;
2907 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2908 byte_count = params + 1 /* pad */ ;
2909 pSMB->TotalParameterCount = cpu_to_le16(params);
2910 pSMB->ParameterCount = pSMB->TotalParameterCount;
2911 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2912 pSMB->Reserved4 = 0;
2913 pSMB->hdr.smb_buf_length += byte_count;
2914 pSMB->ByteCount = cpu_to_le16(byte_count);
2915
2916 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2917 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2918 if (rc) {
2919 cFYI(1, ("Send error in QPathInfo = %d", rc));
2920 } else { /* decode response */
2921 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2922
2923 if (rc || (pSMBr->ByteCount < 40))
2924 rc = -EIO; /* bad smb */
2925 else if (pFindData){
2926 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2927 memcpy((char *) pFindData,
2928 (char *) &pSMBr->hdr.Protocol +
2929 data_offset, sizeof (FILE_ALL_INFO));
2930 } else
2931 rc = -ENOMEM;
2932 }
2933 cifs_buf_release(pSMB);
2934 if (rc == -EAGAIN)
2935 goto QPathInfoRetry;
2936
2937 return rc;
2938}
2939
2940int
2941CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2942 const unsigned char *searchName,
2943 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002944 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945{
2946/* SMB_QUERY_FILE_UNIX_BASIC */
2947 TRANSACTION2_QPI_REQ *pSMB = NULL;
2948 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2949 int rc = 0;
2950 int bytes_returned = 0;
2951 int name_len;
2952 __u16 params, byte_count;
2953
2954 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2955UnixQPathInfoRetry:
2956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2957 (void **) &pSMBr);
2958 if (rc)
2959 return rc;
2960
2961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2962 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002963 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002964 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 name_len++; /* trailing null */
2966 name_len *= 2;
2967 } else { /* BB improve the check for buffer overruns BB */
2968 name_len = strnlen(searchName, PATH_MAX);
2969 name_len++; /* trailing null */
2970 strncpy(pSMB->FileName, searchName, name_len);
2971 }
2972
2973 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2974 pSMB->TotalDataCount = 0;
2975 pSMB->MaxParameterCount = cpu_to_le16(2);
2976 /* BB find exact max SMB PDU from sess structure BB */
2977 pSMB->MaxDataCount = cpu_to_le16(4000);
2978 pSMB->MaxSetupCount = 0;
2979 pSMB->Reserved = 0;
2980 pSMB->Flags = 0;
2981 pSMB->Timeout = 0;
2982 pSMB->Reserved2 = 0;
2983 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2984 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2985 pSMB->DataCount = 0;
2986 pSMB->DataOffset = 0;
2987 pSMB->SetupCount = 1;
2988 pSMB->Reserved3 = 0;
2989 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2990 byte_count = params + 1 /* pad */ ;
2991 pSMB->TotalParameterCount = cpu_to_le16(params);
2992 pSMB->ParameterCount = pSMB->TotalParameterCount;
2993 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2994 pSMB->Reserved4 = 0;
2995 pSMB->hdr.smb_buf_length += byte_count;
2996 pSMB->ByteCount = cpu_to_le16(byte_count);
2997
2998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3000 if (rc) {
3001 cFYI(1, ("Send error in QPathInfo = %d", rc));
3002 } else { /* decode response */
3003 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3004
3005 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3006 rc = -EIO; /* bad smb */
3007 } else {
3008 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3009 memcpy((char *) pFindData,
3010 (char *) &pSMBr->hdr.Protocol +
3011 data_offset,
3012 sizeof (FILE_UNIX_BASIC_INFO));
3013 }
3014 }
3015 cifs_buf_release(pSMB);
3016 if (rc == -EAGAIN)
3017 goto UnixQPathInfoRetry;
3018
3019 return rc;
3020}
3021
3022#if 0 /* function unused at present */
3023int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3024 const char *searchName, FILE_ALL_INFO * findData,
3025 const struct nls_table *nls_codepage)
3026{
3027/* level 257 SMB_ */
3028 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3029 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3030 int rc = 0;
3031 int bytes_returned;
3032 int name_len;
3033 __u16 params, byte_count;
3034
3035 cFYI(1, ("In FindUnique"));
3036findUniqueRetry:
3037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3038 (void **) &pSMBr);
3039 if (rc)
3040 return rc;
3041
3042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3043 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003044 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 /* find define for this maxpathcomponent */
3046 , nls_codepage);
3047 name_len++; /* trailing null */
3048 name_len *= 2;
3049 } else { /* BB improve the check for buffer overruns BB */
3050 name_len = strnlen(searchName, PATH_MAX);
3051 name_len++; /* trailing null */
3052 strncpy(pSMB->FileName, searchName, name_len);
3053 }
3054
3055 params = 12 + name_len /* includes null */ ;
3056 pSMB->TotalDataCount = 0; /* no EAs */
3057 pSMB->MaxParameterCount = cpu_to_le16(2);
3058 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3059 pSMB->MaxSetupCount = 0;
3060 pSMB->Reserved = 0;
3061 pSMB->Flags = 0;
3062 pSMB->Timeout = 0;
3063 pSMB->Reserved2 = 0;
3064 pSMB->ParameterOffset = cpu_to_le16(
3065 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3066 pSMB->DataCount = 0;
3067 pSMB->DataOffset = 0;
3068 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3069 pSMB->Reserved3 = 0;
3070 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3071 byte_count = params + 1 /* pad */ ;
3072 pSMB->TotalParameterCount = cpu_to_le16(params);
3073 pSMB->ParameterCount = pSMB->TotalParameterCount;
3074 pSMB->SearchAttributes =
3075 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3076 ATTR_DIRECTORY);
3077 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3078 pSMB->SearchFlags = cpu_to_le16(1);
3079 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3080 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3081 pSMB->hdr.smb_buf_length += byte_count;
3082 pSMB->ByteCount = cpu_to_le16(byte_count);
3083
3084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3086
3087 if (rc) {
3088 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3089 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003090 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 /* BB fill in */
3092 }
3093
3094 cifs_buf_release(pSMB);
3095 if (rc == -EAGAIN)
3096 goto findUniqueRetry;
3097
3098 return rc;
3099}
3100#endif /* end unused (temporarily) function */
3101
3102/* xid, tcon, searchName and codepage are input parms, rest are returned */
3103int
3104CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3105 const char *searchName,
3106 const struct nls_table *nls_codepage,
3107 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003108 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109{
3110/* level 257 SMB_ */
3111 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3112 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3113 T2_FFIRST_RSP_PARMS * parms;
3114 int rc = 0;
3115 int bytes_returned = 0;
3116 int name_len;
3117 __u16 params, byte_count;
3118
Steve French737b7582005-04-28 22:41:06 -07003119 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120
3121findFirstRetry:
3122 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3123 (void **) &pSMBr);
3124 if (rc)
3125 return rc;
3126
3127 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3128 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003129 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003130 PATH_MAX, nls_codepage, remap);
3131 /* We can not add the asterik earlier in case
3132 it got remapped to 0xF03A as if it were part of the
3133 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003135 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003136 pSMB->FileName[name_len+1] = 0;
3137 pSMB->FileName[name_len+2] = '*';
3138 pSMB->FileName[name_len+3] = 0;
3139 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3141 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003142 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 } else { /* BB add check for overrun of SMB buf BB */
3144 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145/* BB fix here and in unicode clause above ie
3146 if(name_len > buffersize-header)
3147 free buffer exit; BB */
3148 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003149 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003150 pSMB->FileName[name_len+1] = '*';
3151 pSMB->FileName[name_len+2] = 0;
3152 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 }
3154
3155 params = 12 + name_len /* includes null */ ;
3156 pSMB->TotalDataCount = 0; /* no EAs */
3157 pSMB->MaxParameterCount = cpu_to_le16(10);
3158 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3159 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3160 pSMB->MaxSetupCount = 0;
3161 pSMB->Reserved = 0;
3162 pSMB->Flags = 0;
3163 pSMB->Timeout = 0;
3164 pSMB->Reserved2 = 0;
3165 byte_count = params + 1 /* pad */ ;
3166 pSMB->TotalParameterCount = cpu_to_le16(params);
3167 pSMB->ParameterCount = pSMB->TotalParameterCount;
3168 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003169 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3170 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 pSMB->DataCount = 0;
3172 pSMB->DataOffset = 0;
3173 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3174 pSMB->Reserved3 = 0;
3175 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3176 pSMB->SearchAttributes =
3177 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3178 ATTR_DIRECTORY);
3179 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3180 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3181 CIFS_SEARCH_RETURN_RESUME);
3182 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3183
3184 /* BB what should we set StorageType to? Does it matter? BB */
3185 pSMB->SearchStorageType = 0;
3186 pSMB->hdr.smb_buf_length += byte_count;
3187 pSMB->ByteCount = cpu_to_le16(byte_count);
3188
3189 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3190 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003191 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
Steve French88274812006-03-09 22:21:45 +00003193 if (rc) {/* BB add logic to retry regular search if Unix search
3194 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 /* BB Add code to handle unsupported level rc */
3196 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003197
Steve French88274812006-03-09 22:21:45 +00003198 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
3200 /* BB eventually could optimize out free and realloc of buf */
3201 /* for this case */
3202 if (rc == -EAGAIN)
3203 goto findFirstRetry;
3204 } else { /* decode response */
3205 /* BB remember to free buffer if error BB */
3206 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3207 if(rc == 0) {
3208 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3209 psrch_inf->unicode = TRUE;
3210 else
3211 psrch_inf->unicode = FALSE;
3212
3213 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003214 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 psrch_inf->srch_entries_start =
3216 (char *) &pSMBr->hdr.Protocol +
3217 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3219 le16_to_cpu(pSMBr->t2.ParameterOffset));
3220
3221 if(parms->EndofSearch)
3222 psrch_inf->endOfSearch = TRUE;
3223 else
3224 psrch_inf->endOfSearch = FALSE;
3225
3226 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003227 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 *pnetfid = parms->SearchHandle;
3230 } else {
3231 cifs_buf_release(pSMB);
3232 }
3233 }
3234
3235 return rc;
3236}
3237
3238int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3239 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3240{
3241 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3242 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3243 T2_FNEXT_RSP_PARMS * parms;
3244 char *response_data;
3245 int rc = 0;
3246 int bytes_returned, name_len;
3247 __u16 params, byte_count;
3248
3249 cFYI(1, ("In FindNext"));
3250
3251 if(psrch_inf->endOfSearch == TRUE)
3252 return -ENOENT;
3253
3254 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3255 (void **) &pSMBr);
3256 if (rc)
3257 return rc;
3258
3259 params = 14; /* includes 2 bytes of null string, converted to LE below */
3260 byte_count = 0;
3261 pSMB->TotalDataCount = 0; /* no EAs */
3262 pSMB->MaxParameterCount = cpu_to_le16(8);
3263 pSMB->MaxDataCount =
3264 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3265 pSMB->MaxSetupCount = 0;
3266 pSMB->Reserved = 0;
3267 pSMB->Flags = 0;
3268 pSMB->Timeout = 0;
3269 pSMB->Reserved2 = 0;
3270 pSMB->ParameterOffset = cpu_to_le16(
3271 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3272 pSMB->DataCount = 0;
3273 pSMB->DataOffset = 0;
3274 pSMB->SetupCount = 1;
3275 pSMB->Reserved3 = 0;
3276 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3277 pSMB->SearchHandle = searchHandle; /* always kept as le */
3278 pSMB->SearchCount =
3279 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3280 /* test for Unix extensions */
3281/* if (tcon->ses->capabilities & CAP_UNIX) {
3282 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3283 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3284 } else {
3285 pSMB->InformationLevel =
3286 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3287 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3288 } */
3289 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3290 pSMB->ResumeKey = psrch_inf->resume_key;
3291 pSMB->SearchFlags =
3292 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3293
3294 name_len = psrch_inf->resume_name_len;
3295 params += name_len;
3296 if(name_len < PATH_MAX) {
3297 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3298 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003299 /* 14 byte parm len above enough for 2 byte null terminator */
3300 pSMB->ResumeFileName[name_len] = 0;
3301 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 } else {
3303 rc = -EINVAL;
3304 goto FNext2_err_exit;
3305 }
3306 byte_count = params + 1 /* pad */ ;
3307 pSMB->TotalParameterCount = cpu_to_le16(params);
3308 pSMB->ParameterCount = pSMB->TotalParameterCount;
3309 pSMB->hdr.smb_buf_length += byte_count;
3310 pSMB->ByteCount = cpu_to_le16(byte_count);
3311
3312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003314 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 if (rc) {
3316 if (rc == -EBADF) {
3317 psrch_inf->endOfSearch = TRUE;
3318 rc = 0; /* search probably was closed at end of search above */
3319 } else
3320 cFYI(1, ("FindNext returned = %d", rc));
3321 } else { /* decode response */
3322 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3323
3324 if(rc == 0) {
3325 /* BB fixme add lock for file (srch_info) struct here */
3326 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3327 psrch_inf->unicode = TRUE;
3328 else
3329 psrch_inf->unicode = FALSE;
3330 response_data = (char *) &pSMBr->hdr.Protocol +
3331 le16_to_cpu(pSMBr->t2.ParameterOffset);
3332 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3333 response_data = (char *)&pSMBr->hdr.Protocol +
3334 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003335 if(psrch_inf->smallBuf)
3336 cifs_small_buf_release(
3337 psrch_inf->ntwrk_buf_start);
3338 else
3339 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 psrch_inf->srch_entries_start = response_data;
3341 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003342 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 if(parms->EndofSearch)
3344 psrch_inf->endOfSearch = TRUE;
3345 else
3346 psrch_inf->endOfSearch = FALSE;
3347
3348 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3349 psrch_inf->index_of_last_entry +=
3350 psrch_inf->entries_in_buffer;
3351/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3352
3353 /* BB fixme add unlock here */
3354 }
3355
3356 }
3357
3358 /* BB On error, should we leave previous search buf (and count and
3359 last entry fields) intact or free the previous one? */
3360
3361 /* Note: On -EAGAIN error only caller can retry on handle based calls
3362 since file handle passed in no longer valid */
3363FNext2_err_exit:
3364 if (rc != 0)
3365 cifs_buf_release(pSMB);
3366
3367 return rc;
3368}
3369
3370int
3371CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3372{
3373 int rc = 0;
3374 FINDCLOSE_REQ *pSMB = NULL;
3375 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3376 int bytes_returned;
3377
3378 cFYI(1, ("In CIFSSMBFindClose"));
3379 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3380
3381 /* no sense returning error if session restarted
3382 as file handle has been closed */
3383 if(rc == -EAGAIN)
3384 return 0;
3385 if (rc)
3386 return rc;
3387
3388 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3389 pSMB->FileID = searchHandle;
3390 pSMB->ByteCount = 0;
3391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3392 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3393 if (rc) {
3394 cERROR(1, ("Send error in FindClose = %d", rc));
3395 }
Steve Frencha4544342005-08-24 13:59:35 -07003396 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 cifs_small_buf_release(pSMB);
3398
3399 /* Since session is dead, search handle closed on server already */
3400 if (rc == -EAGAIN)
3401 rc = 0;
3402
3403 return rc;
3404}
3405
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406int
3407CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3408 const unsigned char *searchName,
3409 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003410 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411{
3412 int rc = 0;
3413 TRANSACTION2_QPI_REQ *pSMB = NULL;
3414 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3415 int name_len, bytes_returned;
3416 __u16 params, byte_count;
3417
3418 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3419 if(tcon == NULL)
3420 return -ENODEV;
3421
3422GetInodeNumberRetry:
3423 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3424 (void **) &pSMBr);
3425 if (rc)
3426 return rc;
3427
3428
3429 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3430 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003431 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003432 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 name_len++; /* trailing null */
3434 name_len *= 2;
3435 } else { /* BB improve the check for buffer overruns BB */
3436 name_len = strnlen(searchName, PATH_MAX);
3437 name_len++; /* trailing null */
3438 strncpy(pSMB->FileName, searchName, name_len);
3439 }
3440
3441 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3442 pSMB->TotalDataCount = 0;
3443 pSMB->MaxParameterCount = cpu_to_le16(2);
3444 /* BB find exact max data count below from sess structure BB */
3445 pSMB->MaxDataCount = cpu_to_le16(4000);
3446 pSMB->MaxSetupCount = 0;
3447 pSMB->Reserved = 0;
3448 pSMB->Flags = 0;
3449 pSMB->Timeout = 0;
3450 pSMB->Reserved2 = 0;
3451 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3452 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3453 pSMB->DataCount = 0;
3454 pSMB->DataOffset = 0;
3455 pSMB->SetupCount = 1;
3456 pSMB->Reserved3 = 0;
3457 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3458 byte_count = params + 1 /* pad */ ;
3459 pSMB->TotalParameterCount = cpu_to_le16(params);
3460 pSMB->ParameterCount = pSMB->TotalParameterCount;
3461 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3462 pSMB->Reserved4 = 0;
3463 pSMB->hdr.smb_buf_length += byte_count;
3464 pSMB->ByteCount = cpu_to_le16(byte_count);
3465
3466 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3467 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3468 if (rc) {
3469 cFYI(1, ("error %d in QueryInternalInfo", rc));
3470 } else {
3471 /* decode response */
3472 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3473 if (rc || (pSMBr->ByteCount < 2))
3474 /* BB also check enough total bytes returned */
3475 /* If rc should we check for EOPNOSUPP and
3476 disable the srvino flag? or in caller? */
3477 rc = -EIO; /* bad smb */
3478 else {
3479 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3480 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3481 struct file_internal_info * pfinfo;
3482 /* BB Do we need a cast or hash here ? */
3483 if(count < 8) {
3484 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3485 rc = -EIO;
3486 goto GetInodeNumOut;
3487 }
3488 pfinfo = (struct file_internal_info *)
3489 (data_offset + (char *) &pSMBr->hdr.Protocol);
3490 *inode_number = pfinfo->UniqueId;
3491 }
3492 }
3493GetInodeNumOut:
3494 cifs_buf_release(pSMB);
3495 if (rc == -EAGAIN)
3496 goto GetInodeNumberRetry;
3497 return rc;
3498}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
3500int
3501CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3502 const unsigned char *searchName,
3503 unsigned char **targetUNCs,
3504 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003505 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506{
3507/* TRANS2_GET_DFS_REFERRAL */
3508 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3509 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3510 struct dfs_referral_level_3 * referrals = NULL;
3511 int rc = 0;
3512 int bytes_returned;
3513 int name_len;
3514 unsigned int i;
3515 char * temp;
3516 __u16 params, byte_count;
3517 *number_of_UNC_in_array = 0;
3518 *targetUNCs = NULL;
3519
3520 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3521 if (ses == NULL)
3522 return -ENODEV;
3523getDFSRetry:
3524 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3525 (void **) &pSMBr);
3526 if (rc)
3527 return rc;
Steve French1982c342005-08-17 12:38:22 -07003528
3529 /* server pointer checked in called function,
3530 but should never be null here anyway */
3531 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 pSMB->hdr.Tid = ses->ipc_tid;
3533 pSMB->hdr.Uid = ses->Suid;
3534 if (ses->capabilities & CAP_STATUS32) {
3535 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3536 }
3537 if (ses->capabilities & CAP_DFS) {
3538 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3539 }
3540
3541 if (ses->capabilities & CAP_UNICODE) {
3542 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3543 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003544 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003545 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 name_len++; /* trailing null */
3547 name_len *= 2;
3548 } else { /* BB improve the check for buffer overruns BB */
3549 name_len = strnlen(searchName, PATH_MAX);
3550 name_len++; /* trailing null */
3551 strncpy(pSMB->RequestFileName, searchName, name_len);
3552 }
3553
3554 params = 2 /* level */ + name_len /*includes null */ ;
3555 pSMB->TotalDataCount = 0;
3556 pSMB->DataCount = 0;
3557 pSMB->DataOffset = 0;
3558 pSMB->MaxParameterCount = 0;
3559 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3560 pSMB->MaxSetupCount = 0;
3561 pSMB->Reserved = 0;
3562 pSMB->Flags = 0;
3563 pSMB->Timeout = 0;
3564 pSMB->Reserved2 = 0;
3565 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3566 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3567 pSMB->SetupCount = 1;
3568 pSMB->Reserved3 = 0;
3569 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3570 byte_count = params + 3 /* pad */ ;
3571 pSMB->ParameterCount = cpu_to_le16(params);
3572 pSMB->TotalParameterCount = pSMB->ParameterCount;
3573 pSMB->MaxReferralLevel = cpu_to_le16(3);
3574 pSMB->hdr.smb_buf_length += byte_count;
3575 pSMB->ByteCount = cpu_to_le16(byte_count);
3576
3577 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3578 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3579 if (rc) {
3580 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3581 } else { /* decode response */
3582/* BB Add logic to parse referrals here */
3583 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3584
3585 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3586 rc = -EIO; /* bad smb */
3587 else {
3588 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3589 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3590
3591 cFYI(1,
3592 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3593 pSMBr->ByteCount, data_offset));
3594 referrals =
3595 (struct dfs_referral_level_3 *)
3596 (8 /* sizeof start of data block */ +
3597 data_offset +
3598 (char *) &pSMBr->hdr.Protocol);
3599 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",
3600 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)));
3601 /* BB This field is actually two bytes in from start of
3602 data block so we could do safety check that DataBlock
3603 begins at address of pSMBr->NumberOfReferrals */
3604 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3605
3606 /* BB Fix below so can return more than one referral */
3607 if(*number_of_UNC_in_array > 1)
3608 *number_of_UNC_in_array = 1;
3609
3610 /* get the length of the strings describing refs */
3611 name_len = 0;
3612 for(i=0;i<*number_of_UNC_in_array;i++) {
3613 /* make sure that DfsPathOffset not past end */
3614 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3615 if (offset > data_count) {
3616 /* if invalid referral, stop here and do
3617 not try to copy any more */
3618 *number_of_UNC_in_array = i;
3619 break;
3620 }
3621 temp = ((char *)referrals) + offset;
3622
3623 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3624 name_len += UniStrnlen((wchar_t *)temp,data_count);
3625 } else {
3626 name_len += strnlen(temp,data_count);
3627 }
3628 referrals++;
3629 /* BB add check that referral pointer does not fall off end PDU */
3630
3631 }
3632 /* BB add check for name_len bigger than bcc */
3633 *targetUNCs =
3634 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3635 if(*targetUNCs == NULL) {
3636 rc = -ENOMEM;
3637 goto GetDFSRefExit;
3638 }
3639 /* copy the ref strings */
3640 referrals =
3641 (struct dfs_referral_level_3 *)
3642 (8 /* sizeof data hdr */ +
3643 data_offset +
3644 (char *) &pSMBr->hdr.Protocol);
3645
3646 for(i=0;i<*number_of_UNC_in_array;i++) {
3647 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3648 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3649 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003650 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 } else {
3652 strncpy(*targetUNCs,temp,name_len);
3653 }
3654 /* BB update target_uncs pointers */
3655 referrals++;
3656 }
3657 temp = *targetUNCs;
3658 temp[name_len] = 0;
3659 }
3660
3661 }
3662GetDFSRefExit:
3663 if (pSMB)
3664 cifs_buf_release(pSMB);
3665
3666 if (rc == -EAGAIN)
3667 goto getDFSRetry;
3668
3669 return rc;
3670}
3671
Steve French20962432005-09-21 22:05:57 -07003672/* Query File System Info such as free space to old servers such as Win 9x */
3673int
3674SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3675{
3676/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3677 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3678 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3679 FILE_SYSTEM_ALLOC_INFO *response_data;
3680 int rc = 0;
3681 int bytes_returned = 0;
3682 __u16 params, byte_count;
3683
3684 cFYI(1, ("OldQFSInfo"));
3685oldQFSInfoRetry:
3686 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3687 (void **) &pSMBr);
3688 if (rc)
3689 return rc;
3690 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3691 (void **) &pSMBr);
3692 if (rc)
3693 return rc;
3694
3695 params = 2; /* level */
3696 pSMB->TotalDataCount = 0;
3697 pSMB->MaxParameterCount = cpu_to_le16(2);
3698 pSMB->MaxDataCount = cpu_to_le16(1000);
3699 pSMB->MaxSetupCount = 0;
3700 pSMB->Reserved = 0;
3701 pSMB->Flags = 0;
3702 pSMB->Timeout = 0;
3703 pSMB->Reserved2 = 0;
3704 byte_count = params + 1 /* pad */ ;
3705 pSMB->TotalParameterCount = cpu_to_le16(params);
3706 pSMB->ParameterCount = pSMB->TotalParameterCount;
3707 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3708 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3709 pSMB->DataCount = 0;
3710 pSMB->DataOffset = 0;
3711 pSMB->SetupCount = 1;
3712 pSMB->Reserved3 = 0;
3713 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3714 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3715 pSMB->hdr.smb_buf_length += byte_count;
3716 pSMB->ByteCount = cpu_to_le16(byte_count);
3717
3718 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3719 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3720 if (rc) {
3721 cFYI(1, ("Send error in QFSInfo = %d", rc));
3722 } else { /* decode response */
3723 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3724
3725 if (rc || (pSMBr->ByteCount < 18))
3726 rc = -EIO; /* bad smb */
3727 else {
3728 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3729 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3730 pSMBr->ByteCount, data_offset));
3731
3732 response_data =
3733 (FILE_SYSTEM_ALLOC_INFO *)
3734 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3735 FSData->f_bsize =
3736 le16_to_cpu(response_data->BytesPerSector) *
3737 le32_to_cpu(response_data->
3738 SectorsPerAllocationUnit);
3739 FSData->f_blocks =
3740 le32_to_cpu(response_data->TotalAllocationUnits);
3741 FSData->f_bfree = FSData->f_bavail =
3742 le32_to_cpu(response_data->FreeAllocationUnits);
3743 cFYI(1,
3744 ("Blocks: %lld Free: %lld Block size %ld",
3745 (unsigned long long)FSData->f_blocks,
3746 (unsigned long long)FSData->f_bfree,
3747 FSData->f_bsize));
3748 }
3749 }
3750 cifs_buf_release(pSMB);
3751
3752 if (rc == -EAGAIN)
3753 goto oldQFSInfoRetry;
3754
3755 return rc;
3756}
3757
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758int
Steve French737b7582005-04-28 22:41:06 -07003759CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760{
3761/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3762 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3763 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3764 FILE_SYSTEM_INFO *response_data;
3765 int rc = 0;
3766 int bytes_returned = 0;
3767 __u16 params, byte_count;
3768
3769 cFYI(1, ("In QFSInfo"));
3770QFSInfoRetry:
3771 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3772 (void **) &pSMBr);
3773 if (rc)
3774 return rc;
3775
3776 params = 2; /* level */
3777 pSMB->TotalDataCount = 0;
3778 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003779 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 pSMB->MaxSetupCount = 0;
3781 pSMB->Reserved = 0;
3782 pSMB->Flags = 0;
3783 pSMB->Timeout = 0;
3784 pSMB->Reserved2 = 0;
3785 byte_count = params + 1 /* pad */ ;
3786 pSMB->TotalParameterCount = cpu_to_le16(params);
3787 pSMB->ParameterCount = pSMB->TotalParameterCount;
3788 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3789 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3790 pSMB->DataCount = 0;
3791 pSMB->DataOffset = 0;
3792 pSMB->SetupCount = 1;
3793 pSMB->Reserved3 = 0;
3794 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3795 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3796 pSMB->hdr.smb_buf_length += byte_count;
3797 pSMB->ByteCount = cpu_to_le16(byte_count);
3798
3799 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3800 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3801 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003802 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 } else { /* decode response */
3804 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3805
Steve French20962432005-09-21 22:05:57 -07003806 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 rc = -EIO; /* bad smb */
3808 else {
3809 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
3811 response_data =
3812 (FILE_SYSTEM_INFO
3813 *) (((char *) &pSMBr->hdr.Protocol) +
3814 data_offset);
3815 FSData->f_bsize =
3816 le32_to_cpu(response_data->BytesPerSector) *
3817 le32_to_cpu(response_data->
3818 SectorsPerAllocationUnit);
3819 FSData->f_blocks =
3820 le64_to_cpu(response_data->TotalAllocationUnits);
3821 FSData->f_bfree = FSData->f_bavail =
3822 le64_to_cpu(response_data->FreeAllocationUnits);
3823 cFYI(1,
3824 ("Blocks: %lld Free: %lld Block size %ld",
3825 (unsigned long long)FSData->f_blocks,
3826 (unsigned long long)FSData->f_bfree,
3827 FSData->f_bsize));
3828 }
3829 }
3830 cifs_buf_release(pSMB);
3831
3832 if (rc == -EAGAIN)
3833 goto QFSInfoRetry;
3834
3835 return rc;
3836}
3837
3838int
Steve French737b7582005-04-28 22:41:06 -07003839CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840{
3841/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3842 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3843 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3844 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3845 int rc = 0;
3846 int bytes_returned = 0;
3847 __u16 params, byte_count;
3848
3849 cFYI(1, ("In QFSAttributeInfo"));
3850QFSAttributeRetry:
3851 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3852 (void **) &pSMBr);
3853 if (rc)
3854 return rc;
3855
3856 params = 2; /* level */
3857 pSMB->TotalDataCount = 0;
3858 pSMB->MaxParameterCount = cpu_to_le16(2);
3859 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3860 pSMB->MaxSetupCount = 0;
3861 pSMB->Reserved = 0;
3862 pSMB->Flags = 0;
3863 pSMB->Timeout = 0;
3864 pSMB->Reserved2 = 0;
3865 byte_count = params + 1 /* pad */ ;
3866 pSMB->TotalParameterCount = cpu_to_le16(params);
3867 pSMB->ParameterCount = pSMB->TotalParameterCount;
3868 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3869 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3870 pSMB->DataCount = 0;
3871 pSMB->DataOffset = 0;
3872 pSMB->SetupCount = 1;
3873 pSMB->Reserved3 = 0;
3874 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3875 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3876 pSMB->hdr.smb_buf_length += byte_count;
3877 pSMB->ByteCount = cpu_to_le16(byte_count);
3878
3879 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3880 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3881 if (rc) {
3882 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3883 } else { /* decode response */
3884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3885
3886 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3887 rc = -EIO; /* bad smb */
3888 } else {
3889 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3890 response_data =
3891 (FILE_SYSTEM_ATTRIBUTE_INFO
3892 *) (((char *) &pSMBr->hdr.Protocol) +
3893 data_offset);
3894 memcpy(&tcon->fsAttrInfo, response_data,
3895 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3896 }
3897 }
3898 cifs_buf_release(pSMB);
3899
3900 if (rc == -EAGAIN)
3901 goto QFSAttributeRetry;
3902
3903 return rc;
3904}
3905
3906int
Steve French737b7582005-04-28 22:41:06 -07003907CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908{
3909/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3910 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3911 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3912 FILE_SYSTEM_DEVICE_INFO *response_data;
3913 int rc = 0;
3914 int bytes_returned = 0;
3915 __u16 params, byte_count;
3916
3917 cFYI(1, ("In QFSDeviceInfo"));
3918QFSDeviceRetry:
3919 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3920 (void **) &pSMBr);
3921 if (rc)
3922 return rc;
3923
3924 params = 2; /* level */
3925 pSMB->TotalDataCount = 0;
3926 pSMB->MaxParameterCount = cpu_to_le16(2);
3927 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3928 pSMB->MaxSetupCount = 0;
3929 pSMB->Reserved = 0;
3930 pSMB->Flags = 0;
3931 pSMB->Timeout = 0;
3932 pSMB->Reserved2 = 0;
3933 byte_count = params + 1 /* pad */ ;
3934 pSMB->TotalParameterCount = cpu_to_le16(params);
3935 pSMB->ParameterCount = pSMB->TotalParameterCount;
3936 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3937 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3938
3939 pSMB->DataCount = 0;
3940 pSMB->DataOffset = 0;
3941 pSMB->SetupCount = 1;
3942 pSMB->Reserved3 = 0;
3943 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3944 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3945 pSMB->hdr.smb_buf_length += byte_count;
3946 pSMB->ByteCount = cpu_to_le16(byte_count);
3947
3948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3950 if (rc) {
3951 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3952 } else { /* decode response */
3953 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3954
3955 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3956 rc = -EIO; /* bad smb */
3957 else {
3958 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3959 response_data =
Steve French737b7582005-04-28 22:41:06 -07003960 (FILE_SYSTEM_DEVICE_INFO *)
3961 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 data_offset);
3963 memcpy(&tcon->fsDevInfo, response_data,
3964 sizeof (FILE_SYSTEM_DEVICE_INFO));
3965 }
3966 }
3967 cifs_buf_release(pSMB);
3968
3969 if (rc == -EAGAIN)
3970 goto QFSDeviceRetry;
3971
3972 return rc;
3973}
3974
3975int
Steve French737b7582005-04-28 22:41:06 -07003976CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977{
3978/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3979 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3980 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3981 FILE_SYSTEM_UNIX_INFO *response_data;
3982 int rc = 0;
3983 int bytes_returned = 0;
3984 __u16 params, byte_count;
3985
3986 cFYI(1, ("In QFSUnixInfo"));
3987QFSUnixRetry:
3988 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3989 (void **) &pSMBr);
3990 if (rc)
3991 return rc;
3992
3993 params = 2; /* level */
3994 pSMB->TotalDataCount = 0;
3995 pSMB->DataCount = 0;
3996 pSMB->DataOffset = 0;
3997 pSMB->MaxParameterCount = cpu_to_le16(2);
3998 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3999 pSMB->MaxSetupCount = 0;
4000 pSMB->Reserved = 0;
4001 pSMB->Flags = 0;
4002 pSMB->Timeout = 0;
4003 pSMB->Reserved2 = 0;
4004 byte_count = params + 1 /* pad */ ;
4005 pSMB->ParameterCount = cpu_to_le16(params);
4006 pSMB->TotalParameterCount = pSMB->ParameterCount;
4007 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4008 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4009 pSMB->SetupCount = 1;
4010 pSMB->Reserved3 = 0;
4011 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4012 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4013 pSMB->hdr.smb_buf_length += byte_count;
4014 pSMB->ByteCount = cpu_to_le16(byte_count);
4015
4016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4018 if (rc) {
4019 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4020 } else { /* decode response */
4021 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4022
4023 if (rc || (pSMBr->ByteCount < 13)) {
4024 rc = -EIO; /* bad smb */
4025 } else {
4026 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4027 response_data =
4028 (FILE_SYSTEM_UNIX_INFO
4029 *) (((char *) &pSMBr->hdr.Protocol) +
4030 data_offset);
4031 memcpy(&tcon->fsUnixInfo, response_data,
4032 sizeof (FILE_SYSTEM_UNIX_INFO));
4033 }
4034 }
4035 cifs_buf_release(pSMB);
4036
4037 if (rc == -EAGAIN)
4038 goto QFSUnixRetry;
4039
4040
4041 return rc;
4042}
4043
Jeremy Allisonac670552005-06-22 17:26:35 -07004044int
Steve French45abc6e2005-06-23 13:42:03 -05004045CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004046{
4047/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4048 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4049 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4050 int rc = 0;
4051 int bytes_returned = 0;
4052 __u16 params, param_offset, offset, byte_count;
4053
4054 cFYI(1, ("In SETFSUnixInfo"));
4055SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004056 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4058 (void **) &pSMBr);
4059 if (rc)
4060 return rc;
4061
4062 params = 4; /* 2 bytes zero followed by info level. */
4063 pSMB->MaxSetupCount = 0;
4064 pSMB->Reserved = 0;
4065 pSMB->Flags = 0;
4066 pSMB->Timeout = 0;
4067 pSMB->Reserved2 = 0;
4068 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4069 offset = param_offset + params;
4070
4071 pSMB->MaxParameterCount = cpu_to_le16(4);
4072 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4073 pSMB->SetupCount = 1;
4074 pSMB->Reserved3 = 0;
4075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4076 byte_count = 1 /* pad */ + params + 12;
4077
4078 pSMB->DataCount = cpu_to_le16(12);
4079 pSMB->ParameterCount = cpu_to_le16(params);
4080 pSMB->TotalDataCount = pSMB->DataCount;
4081 pSMB->TotalParameterCount = pSMB->ParameterCount;
4082 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4083 pSMB->DataOffset = cpu_to_le16(offset);
4084
4085 /* Params. */
4086 pSMB->FileNum = 0;
4087 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4088
4089 /* Data. */
4090 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4091 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4092 pSMB->ClientUnixCap = cpu_to_le64(cap);
4093
4094 pSMB->hdr.smb_buf_length += byte_count;
4095 pSMB->ByteCount = cpu_to_le16(byte_count);
4096
4097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4099 if (rc) {
4100 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4101 } else { /* decode response */
4102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4103 if (rc) {
4104 rc = -EIO; /* bad smb */
4105 }
4106 }
4107 cifs_buf_release(pSMB);
4108
4109 if (rc == -EAGAIN)
4110 goto SETFSUnixRetry;
4111
4112 return rc;
4113}
4114
4115
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116
4117int
4118CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004119 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120{
4121/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4122 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4123 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4124 FILE_SYSTEM_POSIX_INFO *response_data;
4125 int rc = 0;
4126 int bytes_returned = 0;
4127 __u16 params, byte_count;
4128
4129 cFYI(1, ("In QFSPosixInfo"));
4130QFSPosixRetry:
4131 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4132 (void **) &pSMBr);
4133 if (rc)
4134 return rc;
4135
4136 params = 2; /* level */
4137 pSMB->TotalDataCount = 0;
4138 pSMB->DataCount = 0;
4139 pSMB->DataOffset = 0;
4140 pSMB->MaxParameterCount = cpu_to_le16(2);
4141 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4142 pSMB->MaxSetupCount = 0;
4143 pSMB->Reserved = 0;
4144 pSMB->Flags = 0;
4145 pSMB->Timeout = 0;
4146 pSMB->Reserved2 = 0;
4147 byte_count = params + 1 /* pad */ ;
4148 pSMB->ParameterCount = cpu_to_le16(params);
4149 pSMB->TotalParameterCount = pSMB->ParameterCount;
4150 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4151 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4152 pSMB->SetupCount = 1;
4153 pSMB->Reserved3 = 0;
4154 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4155 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4156 pSMB->hdr.smb_buf_length += byte_count;
4157 pSMB->ByteCount = cpu_to_le16(byte_count);
4158
4159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4161 if (rc) {
4162 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4163 } else { /* decode response */
4164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4165
4166 if (rc || (pSMBr->ByteCount < 13)) {
4167 rc = -EIO; /* bad smb */
4168 } else {
4169 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4170 response_data =
4171 (FILE_SYSTEM_POSIX_INFO
4172 *) (((char *) &pSMBr->hdr.Protocol) +
4173 data_offset);
4174 FSData->f_bsize =
4175 le32_to_cpu(response_data->BlockSize);
4176 FSData->f_blocks =
4177 le64_to_cpu(response_data->TotalBlocks);
4178 FSData->f_bfree =
4179 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004180 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 FSData->f_bavail = FSData->f_bfree;
4182 } else {
4183 FSData->f_bavail =
4184 le64_to_cpu(response_data->UserBlocksAvail);
4185 }
Steve French70ca7342005-09-22 16:32:06 -07004186 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 FSData->f_files =
4188 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004189 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 FSData->f_ffree =
4191 le64_to_cpu(response_data->FreeFileNodes);
4192 }
4193 }
4194 cifs_buf_release(pSMB);
4195
4196 if (rc == -EAGAIN)
4197 goto QFSPosixRetry;
4198
4199 return rc;
4200}
4201
4202
4203/* We can not use write of zero bytes trick to
4204 set file size due to need for large file support. Also note that
4205 this SetPathInfo is preferred to SetFileInfo based method in next
4206 routine which is only needed to work around a sharing violation bug
4207 in Samba which this routine can run into */
4208
4209int
4210CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004211 __u64 size, int SetAllocation,
4212 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213{
4214 struct smb_com_transaction2_spi_req *pSMB = NULL;
4215 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4216 struct file_end_of_file_info *parm_data;
4217 int name_len;
4218 int rc = 0;
4219 int bytes_returned = 0;
4220 __u16 params, byte_count, data_count, param_offset, offset;
4221
4222 cFYI(1, ("In SetEOF"));
4223SetEOFRetry:
4224 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4225 (void **) &pSMBr);
4226 if (rc)
4227 return rc;
4228
4229 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4230 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004231 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004232 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 name_len++; /* trailing null */
4234 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004235 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 name_len = strnlen(fileName, PATH_MAX);
4237 name_len++; /* trailing null */
4238 strncpy(pSMB->FileName, fileName, name_len);
4239 }
4240 params = 6 + name_len;
4241 data_count = sizeof (struct file_end_of_file_info);
4242 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004243 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 pSMB->MaxSetupCount = 0;
4245 pSMB->Reserved = 0;
4246 pSMB->Flags = 0;
4247 pSMB->Timeout = 0;
4248 pSMB->Reserved2 = 0;
4249 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4250 InformationLevel) - 4;
4251 offset = param_offset + params;
4252 if(SetAllocation) {
4253 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4254 pSMB->InformationLevel =
4255 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4256 else
4257 pSMB->InformationLevel =
4258 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4259 } else /* Set File Size */ {
4260 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4261 pSMB->InformationLevel =
4262 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4263 else
4264 pSMB->InformationLevel =
4265 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4266 }
4267
4268 parm_data =
4269 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4270 offset);
4271 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4272 pSMB->DataOffset = cpu_to_le16(offset);
4273 pSMB->SetupCount = 1;
4274 pSMB->Reserved3 = 0;
4275 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4276 byte_count = 3 /* pad */ + params + data_count;
4277 pSMB->DataCount = cpu_to_le16(data_count);
4278 pSMB->TotalDataCount = pSMB->DataCount;
4279 pSMB->ParameterCount = cpu_to_le16(params);
4280 pSMB->TotalParameterCount = pSMB->ParameterCount;
4281 pSMB->Reserved4 = 0;
4282 pSMB->hdr.smb_buf_length += byte_count;
4283 parm_data->FileSize = cpu_to_le64(size);
4284 pSMB->ByteCount = cpu_to_le16(byte_count);
4285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4287 if (rc) {
4288 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4289 }
4290
4291 cifs_buf_release(pSMB);
4292
4293 if (rc == -EAGAIN)
4294 goto SetEOFRetry;
4295
4296 return rc;
4297}
4298
4299int
4300CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4301 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4302{
4303 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4304 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4305 char *data_offset;
4306 struct file_end_of_file_info *parm_data;
4307 int rc = 0;
4308 int bytes_returned = 0;
4309 __u16 params, param_offset, offset, byte_count, count;
4310
4311 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4312 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004313 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4314
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 if (rc)
4316 return rc;
4317
Steve Frenchcd634992005-04-28 22:41:10 -07004318 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4319
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4321 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4322
4323 params = 6;
4324 pSMB->MaxSetupCount = 0;
4325 pSMB->Reserved = 0;
4326 pSMB->Flags = 0;
4327 pSMB->Timeout = 0;
4328 pSMB->Reserved2 = 0;
4329 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4330 offset = param_offset + params;
4331
4332 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4333
4334 count = sizeof(struct file_end_of_file_info);
4335 pSMB->MaxParameterCount = cpu_to_le16(2);
4336 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4337 pSMB->SetupCount = 1;
4338 pSMB->Reserved3 = 0;
4339 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4340 byte_count = 3 /* pad */ + params + count;
4341 pSMB->DataCount = cpu_to_le16(count);
4342 pSMB->ParameterCount = cpu_to_le16(params);
4343 pSMB->TotalDataCount = pSMB->DataCount;
4344 pSMB->TotalParameterCount = pSMB->ParameterCount;
4345 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4346 parm_data =
4347 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4348 offset);
4349 pSMB->DataOffset = cpu_to_le16(offset);
4350 parm_data->FileSize = cpu_to_le64(size);
4351 pSMB->Fid = fid;
4352 if(SetAllocation) {
4353 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4354 pSMB->InformationLevel =
4355 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4356 else
4357 pSMB->InformationLevel =
4358 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4359 } else /* Set File Size */ {
4360 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4361 pSMB->InformationLevel =
4362 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4363 else
4364 pSMB->InformationLevel =
4365 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4366 }
4367 pSMB->Reserved4 = 0;
4368 pSMB->hdr.smb_buf_length += byte_count;
4369 pSMB->ByteCount = cpu_to_le16(byte_count);
4370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4371 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4372 if (rc) {
4373 cFYI(1,
4374 ("Send error in SetFileInfo (SetFileSize) = %d",
4375 rc));
4376 }
4377
4378 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004379 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
4381 /* Note: On -EAGAIN error only caller can retry on handle based calls
4382 since file handle passed in no longer valid */
4383
4384 return rc;
4385}
4386
4387/* Some legacy servers such as NT4 require that the file times be set on
4388 an open handle, rather than by pathname - this is awkward due to
4389 potential access conflicts on the open, but it is unavoidable for these
4390 old servers since the only other choice is to go from 100 nanosecond DCE
4391 time and resort to the original setpathinfo level which takes the ancient
4392 DOS time format with 2 second granularity */
4393int
4394CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4395 __u16 fid)
4396{
4397 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4398 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4399 char *data_offset;
4400 int rc = 0;
4401 int bytes_returned = 0;
4402 __u16 params, param_offset, offset, byte_count, count;
4403
4404 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004405 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4406
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 if (rc)
4408 return rc;
4409
Steve Frenchcd634992005-04-28 22:41:10 -07004410 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4411
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 /* At this point there is no need to override the current pid
4413 with the pid of the opener, but that could change if we someday
4414 use an existing handle (rather than opening one on the fly) */
4415 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4416 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4417
4418 params = 6;
4419 pSMB->MaxSetupCount = 0;
4420 pSMB->Reserved = 0;
4421 pSMB->Flags = 0;
4422 pSMB->Timeout = 0;
4423 pSMB->Reserved2 = 0;
4424 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4425 offset = param_offset + params;
4426
4427 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4428
4429 count = sizeof (FILE_BASIC_INFO);
4430 pSMB->MaxParameterCount = cpu_to_le16(2);
4431 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4432 pSMB->SetupCount = 1;
4433 pSMB->Reserved3 = 0;
4434 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4435 byte_count = 3 /* pad */ + params + count;
4436 pSMB->DataCount = cpu_to_le16(count);
4437 pSMB->ParameterCount = cpu_to_le16(params);
4438 pSMB->TotalDataCount = pSMB->DataCount;
4439 pSMB->TotalParameterCount = pSMB->ParameterCount;
4440 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4441 pSMB->DataOffset = cpu_to_le16(offset);
4442 pSMB->Fid = fid;
4443 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4444 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4445 else
4446 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4447 pSMB->Reserved4 = 0;
4448 pSMB->hdr.smb_buf_length += byte_count;
4449 pSMB->ByteCount = cpu_to_le16(byte_count);
4450 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4451 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4452 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4453 if (rc) {
4454 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4455 }
4456
Steve Frenchcd634992005-04-28 22:41:10 -07004457 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
4459 /* Note: On -EAGAIN error only caller can retry on handle based calls
4460 since file handle passed in no longer valid */
4461
4462 return rc;
4463}
4464
4465
4466int
4467CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4468 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004469 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470{
4471 TRANSACTION2_SPI_REQ *pSMB = NULL;
4472 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4473 int name_len;
4474 int rc = 0;
4475 int bytes_returned = 0;
4476 char *data_offset;
4477 __u16 params, param_offset, offset, byte_count, count;
4478
4479 cFYI(1, ("In SetTimes"));
4480
4481SetTimesRetry:
4482 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4483 (void **) &pSMBr);
4484 if (rc)
4485 return rc;
4486
4487 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4488 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004489 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004490 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 name_len++; /* trailing null */
4492 name_len *= 2;
4493 } else { /* BB improve the check for buffer overruns BB */
4494 name_len = strnlen(fileName, PATH_MAX);
4495 name_len++; /* trailing null */
4496 strncpy(pSMB->FileName, fileName, name_len);
4497 }
4498
4499 params = 6 + name_len;
4500 count = sizeof (FILE_BASIC_INFO);
4501 pSMB->MaxParameterCount = cpu_to_le16(2);
4502 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4503 pSMB->MaxSetupCount = 0;
4504 pSMB->Reserved = 0;
4505 pSMB->Flags = 0;
4506 pSMB->Timeout = 0;
4507 pSMB->Reserved2 = 0;
4508 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4509 InformationLevel) - 4;
4510 offset = param_offset + params;
4511 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4512 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4513 pSMB->DataOffset = cpu_to_le16(offset);
4514 pSMB->SetupCount = 1;
4515 pSMB->Reserved3 = 0;
4516 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4517 byte_count = 3 /* pad */ + params + count;
4518
4519 pSMB->DataCount = cpu_to_le16(count);
4520 pSMB->ParameterCount = cpu_to_le16(params);
4521 pSMB->TotalDataCount = pSMB->DataCount;
4522 pSMB->TotalParameterCount = pSMB->ParameterCount;
4523 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4524 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4525 else
4526 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4527 pSMB->Reserved4 = 0;
4528 pSMB->hdr.smb_buf_length += byte_count;
4529 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4530 pSMB->ByteCount = cpu_to_le16(byte_count);
4531 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4532 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4533 if (rc) {
4534 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4535 }
4536
4537 cifs_buf_release(pSMB);
4538
4539 if (rc == -EAGAIN)
4540 goto SetTimesRetry;
4541
4542 return rc;
4543}
4544
4545/* Can not be used to set time stamps yet (due to old DOS time format) */
4546/* Can be used to set attributes */
4547#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4548 handling it anyway and NT4 was what we thought it would be needed for
4549 Do not delete it until we prove whether needed for Win9x though */
4550int
4551CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4552 __u16 dos_attrs, const struct nls_table *nls_codepage)
4553{
4554 SETATTR_REQ *pSMB = NULL;
4555 SETATTR_RSP *pSMBr = NULL;
4556 int rc = 0;
4557 int bytes_returned;
4558 int name_len;
4559
4560 cFYI(1, ("In SetAttrLegacy"));
4561
4562SetAttrLgcyRetry:
4563 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4564 (void **) &pSMBr);
4565 if (rc)
4566 return rc;
4567
4568 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4569 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004570 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 PATH_MAX, nls_codepage);
4572 name_len++; /* trailing null */
4573 name_len *= 2;
4574 } else { /* BB improve the check for buffer overruns BB */
4575 name_len = strnlen(fileName, PATH_MAX);
4576 name_len++; /* trailing null */
4577 strncpy(pSMB->fileName, fileName, name_len);
4578 }
4579 pSMB->attr = cpu_to_le16(dos_attrs);
4580 pSMB->BufferFormat = 0x04;
4581 pSMB->hdr.smb_buf_length += name_len + 1;
4582 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4585 if (rc) {
4586 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4587 }
4588
4589 cifs_buf_release(pSMB);
4590
4591 if (rc == -EAGAIN)
4592 goto SetAttrLgcyRetry;
4593
4594 return rc;
4595}
4596#endif /* temporarily unneeded SetAttr legacy function */
4597
4598int
4599CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004600 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4601 dev_t device, const struct nls_table *nls_codepage,
4602 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603{
4604 TRANSACTION2_SPI_REQ *pSMB = NULL;
4605 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4606 int name_len;
4607 int rc = 0;
4608 int bytes_returned = 0;
4609 FILE_UNIX_BASIC_INFO *data_offset;
4610 __u16 params, param_offset, offset, count, byte_count;
4611
4612 cFYI(1, ("In SetUID/GID/Mode"));
4613setPermsRetry:
4614 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4615 (void **) &pSMBr);
4616 if (rc)
4617 return rc;
4618
4619 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4620 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004621 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004622 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 name_len++; /* trailing null */
4624 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004625 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 name_len = strnlen(fileName, PATH_MAX);
4627 name_len++; /* trailing null */
4628 strncpy(pSMB->FileName, fileName, name_len);
4629 }
4630
4631 params = 6 + name_len;
4632 count = sizeof (FILE_UNIX_BASIC_INFO);
4633 pSMB->MaxParameterCount = cpu_to_le16(2);
4634 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4635 pSMB->MaxSetupCount = 0;
4636 pSMB->Reserved = 0;
4637 pSMB->Flags = 0;
4638 pSMB->Timeout = 0;
4639 pSMB->Reserved2 = 0;
4640 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4641 InformationLevel) - 4;
4642 offset = param_offset + params;
4643 data_offset =
4644 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4645 offset);
4646 memset(data_offset, 0, count);
4647 pSMB->DataOffset = cpu_to_le16(offset);
4648 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4649 pSMB->SetupCount = 1;
4650 pSMB->Reserved3 = 0;
4651 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4652 byte_count = 3 /* pad */ + params + count;
4653 pSMB->ParameterCount = cpu_to_le16(params);
4654 pSMB->DataCount = cpu_to_le16(count);
4655 pSMB->TotalParameterCount = pSMB->ParameterCount;
4656 pSMB->TotalDataCount = pSMB->DataCount;
4657 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4658 pSMB->Reserved4 = 0;
4659 pSMB->hdr.smb_buf_length += byte_count;
4660 data_offset->Uid = cpu_to_le64(uid);
4661 data_offset->Gid = cpu_to_le64(gid);
4662 /* better to leave device as zero when it is */
4663 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4664 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4665 data_offset->Permissions = cpu_to_le64(mode);
4666
4667 if(S_ISREG(mode))
4668 data_offset->Type = cpu_to_le32(UNIX_FILE);
4669 else if(S_ISDIR(mode))
4670 data_offset->Type = cpu_to_le32(UNIX_DIR);
4671 else if(S_ISLNK(mode))
4672 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4673 else if(S_ISCHR(mode))
4674 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4675 else if(S_ISBLK(mode))
4676 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4677 else if(S_ISFIFO(mode))
4678 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4679 else if(S_ISSOCK(mode))
4680 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4681
4682
4683 pSMB->ByteCount = cpu_to_le16(byte_count);
4684 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4685 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4686 if (rc) {
4687 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4688 }
4689
4690 if (pSMB)
4691 cifs_buf_release(pSMB);
4692 if (rc == -EAGAIN)
4693 goto setPermsRetry;
4694 return rc;
4695}
4696
4697int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004698 const int notify_subdirs, const __u16 netfid,
4699 __u32 filter, struct file * pfile, int multishot,
4700 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701{
4702 int rc = 0;
4703 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004704 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004705 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 int bytes_returned;
4707
4708 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4709 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4710 (void **) &pSMBr);
4711 if (rc)
4712 return rc;
4713
4714 pSMB->TotalParameterCount = 0 ;
4715 pSMB->TotalDataCount = 0;
4716 pSMB->MaxParameterCount = cpu_to_le32(2);
4717 /* BB find exact data count max from sess structure BB */
4718 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004719/* BB VERIFY verify which is correct for above BB */
4720 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4721 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4722
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 pSMB->MaxSetupCount = 4;
4724 pSMB->Reserved = 0;
4725 pSMB->ParameterOffset = 0;
4726 pSMB->DataCount = 0;
4727 pSMB->DataOffset = 0;
4728 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4729 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4730 pSMB->ParameterCount = pSMB->TotalParameterCount;
4731 if(notify_subdirs)
4732 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4733 pSMB->Reserved2 = 0;
4734 pSMB->CompletionFilter = cpu_to_le32(filter);
4735 pSMB->Fid = netfid; /* file handle always le */
4736 pSMB->ByteCount = 0;
4737
4738 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4739 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4740 if (rc) {
4741 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004742 } else {
4743 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004744 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004745 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004746 sizeof(struct dir_notify_req),
4747 GFP_KERNEL);
4748 if(dnotify_req) {
4749 dnotify_req->Pid = pSMB->hdr.Pid;
4750 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4751 dnotify_req->Mid = pSMB->hdr.Mid;
4752 dnotify_req->Tid = pSMB->hdr.Tid;
4753 dnotify_req->Uid = pSMB->hdr.Uid;
4754 dnotify_req->netfid = netfid;
4755 dnotify_req->pfile = pfile;
4756 dnotify_req->filter = filter;
4757 dnotify_req->multishot = multishot;
4758 spin_lock(&GlobalMid_Lock);
4759 list_add_tail(&dnotify_req->lhead,
4760 &GlobalDnotifyReqList);
4761 spin_unlock(&GlobalMid_Lock);
4762 } else
4763 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 }
4765 cifs_buf_release(pSMB);
4766 return rc;
4767}
4768#ifdef CONFIG_CIFS_XATTR
4769ssize_t
4770CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4771 const unsigned char *searchName,
4772 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004773 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774{
4775 /* BB assumes one setup word */
4776 TRANSACTION2_QPI_REQ *pSMB = NULL;
4777 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4778 int rc = 0;
4779 int bytes_returned;
4780 int name_len;
4781 struct fea * temp_fea;
4782 char * temp_ptr;
4783 __u16 params, byte_count;
4784
4785 cFYI(1, ("In Query All EAs path %s", searchName));
4786QAllEAsRetry:
4787 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4788 (void **) &pSMBr);
4789 if (rc)
4790 return rc;
4791
4792 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4793 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004794 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004795 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 name_len++; /* trailing null */
4797 name_len *= 2;
4798 } else { /* BB improve the check for buffer overruns BB */
4799 name_len = strnlen(searchName, PATH_MAX);
4800 name_len++; /* trailing null */
4801 strncpy(pSMB->FileName, searchName, name_len);
4802 }
4803
4804 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4805 pSMB->TotalDataCount = 0;
4806 pSMB->MaxParameterCount = cpu_to_le16(2);
4807 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4808 pSMB->MaxSetupCount = 0;
4809 pSMB->Reserved = 0;
4810 pSMB->Flags = 0;
4811 pSMB->Timeout = 0;
4812 pSMB->Reserved2 = 0;
4813 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4814 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4815 pSMB->DataCount = 0;
4816 pSMB->DataOffset = 0;
4817 pSMB->SetupCount = 1;
4818 pSMB->Reserved3 = 0;
4819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4820 byte_count = params + 1 /* pad */ ;
4821 pSMB->TotalParameterCount = cpu_to_le16(params);
4822 pSMB->ParameterCount = pSMB->TotalParameterCount;
4823 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4824 pSMB->Reserved4 = 0;
4825 pSMB->hdr.smb_buf_length += byte_count;
4826 pSMB->ByteCount = cpu_to_le16(byte_count);
4827
4828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4830 if (rc) {
4831 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4832 } else { /* decode response */
4833 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4834
4835 /* BB also check enough total bytes returned */
4836 /* BB we need to improve the validity checking
4837 of these trans2 responses */
4838 if (rc || (pSMBr->ByteCount < 4))
4839 rc = -EIO; /* bad smb */
4840 /* else if (pFindData){
4841 memcpy((char *) pFindData,
4842 (char *) &pSMBr->hdr.Protocol +
4843 data_offset, kl);
4844 }*/ else {
4845 /* check that length of list is not more than bcc */
4846 /* check that each entry does not go beyond length
4847 of list */
4848 /* check that each element of each entry does not
4849 go beyond end of list */
4850 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4851 struct fealist * ea_response_data;
4852 rc = 0;
4853 /* validate_trans2_offsets() */
4854 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4855 ea_response_data = (struct fealist *)
4856 (((char *) &pSMBr->hdr.Protocol) +
4857 data_offset);
4858 name_len = le32_to_cpu(ea_response_data->list_len);
4859 cFYI(1,("ea length %d", name_len));
4860 if(name_len <= 8) {
4861 /* returned EA size zeroed at top of function */
4862 cFYI(1,("empty EA list returned from server"));
4863 } else {
4864 /* account for ea list len */
4865 name_len -= 4;
4866 temp_fea = ea_response_data->list;
4867 temp_ptr = (char *)temp_fea;
4868 while(name_len > 0) {
4869 __u16 value_len;
4870 name_len -= 4;
4871 temp_ptr += 4;
4872 rc += temp_fea->name_len;
4873 /* account for prefix user. and trailing null */
4874 rc = rc + 5 + 1;
4875 if(rc<(int)buf_size) {
4876 memcpy(EAData,"user.",5);
4877 EAData+=5;
4878 memcpy(EAData,temp_ptr,temp_fea->name_len);
4879 EAData+=temp_fea->name_len;
4880 /* null terminate name */
4881 *EAData = 0;
4882 EAData = EAData + 1;
4883 } else if(buf_size == 0) {
4884 /* skip copy - calc size only */
4885 } else {
4886 /* stop before overrun buffer */
4887 rc = -ERANGE;
4888 break;
4889 }
4890 name_len -= temp_fea->name_len;
4891 temp_ptr += temp_fea->name_len;
4892 /* account for trailing null */
4893 name_len--;
4894 temp_ptr++;
4895 value_len = le16_to_cpu(temp_fea->value_len);
4896 name_len -= value_len;
4897 temp_ptr += value_len;
4898 /* BB check that temp_ptr is still within smb BB*/
4899 /* no trailing null to account for in value len */
4900 /* go on to next EA */
4901 temp_fea = (struct fea *)temp_ptr;
4902 }
4903 }
4904 }
4905 }
4906 if (pSMB)
4907 cifs_buf_release(pSMB);
4908 if (rc == -EAGAIN)
4909 goto QAllEAsRetry;
4910
4911 return (ssize_t)rc;
4912}
4913
4914ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4915 const unsigned char * searchName,const unsigned char * ea_name,
4916 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004917 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918{
4919 TRANSACTION2_QPI_REQ *pSMB = NULL;
4920 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4921 int rc = 0;
4922 int bytes_returned;
4923 int name_len;
4924 struct fea * temp_fea;
4925 char * temp_ptr;
4926 __u16 params, byte_count;
4927
4928 cFYI(1, ("In Query EA path %s", searchName));
4929QEARetry:
4930 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4931 (void **) &pSMBr);
4932 if (rc)
4933 return rc;
4934
4935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4936 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004937 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004938 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 name_len++; /* trailing null */
4940 name_len *= 2;
4941 } else { /* BB improve the check for buffer overruns BB */
4942 name_len = strnlen(searchName, PATH_MAX);
4943 name_len++; /* trailing null */
4944 strncpy(pSMB->FileName, searchName, name_len);
4945 }
4946
4947 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4948 pSMB->TotalDataCount = 0;
4949 pSMB->MaxParameterCount = cpu_to_le16(2);
4950 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4951 pSMB->MaxSetupCount = 0;
4952 pSMB->Reserved = 0;
4953 pSMB->Flags = 0;
4954 pSMB->Timeout = 0;
4955 pSMB->Reserved2 = 0;
4956 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4957 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4958 pSMB->DataCount = 0;
4959 pSMB->DataOffset = 0;
4960 pSMB->SetupCount = 1;
4961 pSMB->Reserved3 = 0;
4962 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4963 byte_count = params + 1 /* pad */ ;
4964 pSMB->TotalParameterCount = cpu_to_le16(params);
4965 pSMB->ParameterCount = pSMB->TotalParameterCount;
4966 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4967 pSMB->Reserved4 = 0;
4968 pSMB->hdr.smb_buf_length += byte_count;
4969 pSMB->ByteCount = cpu_to_le16(byte_count);
4970
4971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4973 if (rc) {
4974 cFYI(1, ("Send error in Query EA = %d", rc));
4975 } else { /* decode response */
4976 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4977
4978 /* BB also check enough total bytes returned */
4979 /* BB we need to improve the validity checking
4980 of these trans2 responses */
4981 if (rc || (pSMBr->ByteCount < 4))
4982 rc = -EIO; /* bad smb */
4983 /* else if (pFindData){
4984 memcpy((char *) pFindData,
4985 (char *) &pSMBr->hdr.Protocol +
4986 data_offset, kl);
4987 }*/ else {
4988 /* check that length of list is not more than bcc */
4989 /* check that each entry does not go beyond length
4990 of list */
4991 /* check that each element of each entry does not
4992 go beyond end of list */
4993 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4994 struct fealist * ea_response_data;
4995 rc = -ENODATA;
4996 /* validate_trans2_offsets() */
4997 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4998 ea_response_data = (struct fealist *)
4999 (((char *) &pSMBr->hdr.Protocol) +
5000 data_offset);
5001 name_len = le32_to_cpu(ea_response_data->list_len);
5002 cFYI(1,("ea length %d", name_len));
5003 if(name_len <= 8) {
5004 /* returned EA size zeroed at top of function */
5005 cFYI(1,("empty EA list returned from server"));
5006 } else {
5007 /* account for ea list len */
5008 name_len -= 4;
5009 temp_fea = ea_response_data->list;
5010 temp_ptr = (char *)temp_fea;
5011 /* loop through checking if we have a matching
5012 name and then return the associated value */
5013 while(name_len > 0) {
5014 __u16 value_len;
5015 name_len -= 4;
5016 temp_ptr += 4;
5017 value_len = le16_to_cpu(temp_fea->value_len);
5018 /* BB validate that value_len falls within SMB,
5019 even though maximum for name_len is 255 */
5020 if(memcmp(temp_fea->name,ea_name,
5021 temp_fea->name_len) == 0) {
5022 /* found a match */
5023 rc = value_len;
5024 /* account for prefix user. and trailing null */
5025 if(rc<=(int)buf_size) {
5026 memcpy(ea_value,
5027 temp_fea->name+temp_fea->name_len+1,
5028 rc);
5029 /* ea values, unlike ea names,
5030 are not null terminated */
5031 } else if(buf_size == 0) {
5032 /* skip copy - calc size only */
5033 } else {
5034 /* stop before overrun buffer */
5035 rc = -ERANGE;
5036 }
5037 break;
5038 }
5039 name_len -= temp_fea->name_len;
5040 temp_ptr += temp_fea->name_len;
5041 /* account for trailing null */
5042 name_len--;
5043 temp_ptr++;
5044 name_len -= value_len;
5045 temp_ptr += value_len;
5046 /* no trailing null to account for in value len */
5047 /* go on to next EA */
5048 temp_fea = (struct fea *)temp_ptr;
5049 }
5050 }
5051 }
5052 }
5053 if (pSMB)
5054 cifs_buf_release(pSMB);
5055 if (rc == -EAGAIN)
5056 goto QEARetry;
5057
5058 return (ssize_t)rc;
5059}
5060
5061int
5062CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5063 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005064 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5065 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066{
5067 struct smb_com_transaction2_spi_req *pSMB = NULL;
5068 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5069 struct fealist *parm_data;
5070 int name_len;
5071 int rc = 0;
5072 int bytes_returned = 0;
5073 __u16 params, param_offset, byte_count, offset, count;
5074
5075 cFYI(1, ("In SetEA"));
5076SetEARetry:
5077 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5078 (void **) &pSMBr);
5079 if (rc)
5080 return rc;
5081
5082 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5083 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005084 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005085 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 name_len++; /* trailing null */
5087 name_len *= 2;
5088 } else { /* BB improve the check for buffer overruns BB */
5089 name_len = strnlen(fileName, PATH_MAX);
5090 name_len++; /* trailing null */
5091 strncpy(pSMB->FileName, fileName, name_len);
5092 }
5093
5094 params = 6 + name_len;
5095
5096 /* done calculating parms using name_len of file name,
5097 now use name_len to calculate length of ea name
5098 we are going to create in the inode xattrs */
5099 if(ea_name == NULL)
5100 name_len = 0;
5101 else
5102 name_len = strnlen(ea_name,255);
5103
5104 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5105 pSMB->MaxParameterCount = cpu_to_le16(2);
5106 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5107 pSMB->MaxSetupCount = 0;
5108 pSMB->Reserved = 0;
5109 pSMB->Flags = 0;
5110 pSMB->Timeout = 0;
5111 pSMB->Reserved2 = 0;
5112 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5113 InformationLevel) - 4;
5114 offset = param_offset + params;
5115 pSMB->InformationLevel =
5116 cpu_to_le16(SMB_SET_FILE_EA);
5117
5118 parm_data =
5119 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5120 offset);
5121 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5122 pSMB->DataOffset = cpu_to_le16(offset);
5123 pSMB->SetupCount = 1;
5124 pSMB->Reserved3 = 0;
5125 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5126 byte_count = 3 /* pad */ + params + count;
5127 pSMB->DataCount = cpu_to_le16(count);
5128 parm_data->list_len = cpu_to_le32(count);
5129 parm_data->list[0].EA_flags = 0;
5130 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005131 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 /* EA names are always ASCII */
5133 if(ea_name)
5134 strncpy(parm_data->list[0].name,ea_name,name_len);
5135 parm_data->list[0].name[name_len] = 0;
5136 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5137 /* caller ensures that ea_value_len is less than 64K but
5138 we need to ensure that it fits within the smb */
5139
5140 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5141 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5142 if(ea_value_len)
5143 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5144
5145 pSMB->TotalDataCount = pSMB->DataCount;
5146 pSMB->ParameterCount = cpu_to_le16(params);
5147 pSMB->TotalParameterCount = pSMB->ParameterCount;
5148 pSMB->Reserved4 = 0;
5149 pSMB->hdr.smb_buf_length += byte_count;
5150 pSMB->ByteCount = cpu_to_le16(byte_count);
5151 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5152 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5153 if (rc) {
5154 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5155 }
5156
5157 cifs_buf_release(pSMB);
5158
5159 if (rc == -EAGAIN)
5160 goto SetEARetry;
5161
5162 return rc;
5163}
5164
5165#endif