blob: 6f50f2bc8870e418fb9df8b4bb70ba8027bfc3e9 [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"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 {CIFS_PROT, "\2NT LM 0.12"},
65 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
87static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
88{
89 struct cifsFileInfo *open_file = NULL;
90 struct list_head * tmp;
91 struct list_head * tmp1;
92
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
96 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
97 if(open_file) {
98 open_file->invalidHandle = TRUE;
99 }
100 }
101 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700102 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105
106/* If the return code is zero, this function must fill in request_buf pointer */
107static int
108small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
109 void **request_buf /* returned */)
110{
111 int rc = 0;
112
113 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
114 check for tcp and smb session status done differently
115 for those three - in the calling routine */
116 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 if(tcon->tidStatus == CifsExiting) {
118 /* only tree disconnect, open, and write,
119 (and ulogoff which does not have tcon)
120 are allowed as we start force umount */
121 if((smb_command != SMB_COM_WRITE_ANDX) &&
122 (smb_command != SMB_COM_OPEN_ANDX) &&
123 (smb_command != SMB_COM_TREE_DISCONNECT)) {
124 cFYI(1,("can not send cmd %d while umounting",
125 smb_command));
126 return -ENODEV;
127 }
128 }
Steve French31ca3bc2005-04-28 22:41:11 -0700129 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
130 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 struct nls_table *nls_codepage;
132 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700133 reconnect, should be greater than cifs socket
134 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
137 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
138 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
139 /* on "soft" mounts we wait once */
140 if((tcon->retry == FALSE) ||
141 (tcon->ses->status == CifsExiting)) {
142 cFYI(1,("gave up waiting on reconnect in smb_init"));
143 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700144 } /* else "hard" mount - keep retrying
145 until process is killed or server
146 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 } else /* TCP session is reestablished now */
148 break;
149
150 }
151
152 nls_codepage = load_nls_default();
153 /* need to prevent multiple threads trying to
154 simultaneously reconnect the same SMB session */
155 down(&tcon->ses->sesSem);
156 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700157 rc = cifs_setup_session(0, tcon->ses,
158 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
160 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700161 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
162 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700164 /* BB FIXME add code to check if wsize needs
165 update due to negotiated smb buffer size
166 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 if(rc == 0)
168 atomic_inc(&tconInfoReconnectCount);
169
170 cFYI(1, ("reconnect tcon rc = %d", rc));
171 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700172 it is safer (and faster) to reopen files
173 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700176 know whether we can continue or not without
177 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 switch(smb_command) {
179 case SMB_COM_READ_ANDX:
180 case SMB_COM_WRITE_ANDX:
181 case SMB_COM_CLOSE:
182 case SMB_COM_FIND_CLOSE2:
183 case SMB_COM_LOCKING_ANDX: {
184 unload_nls(nls_codepage);
185 return -EAGAIN;
186 }
187 }
188 } else {
189 up(&tcon->ses->sesSem);
190 }
191 unload_nls(nls_codepage);
192
193 } else {
194 return -EIO;
195 }
196 }
197 if(rc)
198 return rc;
199
200 *request_buf = cifs_small_buf_get();
201 if (*request_buf == NULL) {
202 /* BB should we add a retry in here if not a writepage? */
203 return -ENOMEM;
204 }
205
206 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
207
Steve Frencha4544342005-08-24 13:59:35 -0700208 if(tcon != NULL)
209 cifs_stats_inc(&tcon->num_smbs_sent);
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000212}
213
Steve French12b3b8f2006-02-09 21:12:47 +0000214int
Steve French5815449d2006-02-14 01:36:20 +0000215small_smb_init_no_tc(const int smb_command, const int wct,
216 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000217{
218 int rc;
219 struct smb_hdr * buffer;
220
Steve French5815449d2006-02-14 01:36:20 +0000221 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000222 if(rc)
223 return rc;
224
Steve French04fdabe2006-02-10 05:52:50 +0000225 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000226 buffer->Mid = GetNextMid(ses->server);
227 if (ses->capabilities & CAP_UNICODE)
228 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000229 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000230 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
231
232 /* uid, tid can stay at zero as set in header assemble */
233
234 /* BB add support for turning on the signing when
235 this function is used after 1st of session setup requests */
236
237 return rc;
238}
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;
Steve French750d1152006-06-27 06:28:30 +0000401 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
403 if(ses->server)
404 server = ses->server;
405 else {
406 rc = -EIO;
407 return rc;
408 }
409 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
410 (void **) &pSMB, (void **) &pSMBr);
411 if (rc)
412 return rc;
Steve French750d1152006-06-27 06:28:30 +0000413
414 /* if any of auth flags (ie not sign or seal) are overriden use them */
415 if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
416 secFlags = ses->overrideSecFlg;
417 else /* if override flags set only sign/seal OR them with global auth */
418 secFlags = extended_security | ses->overrideSecFlg;
419
Steve Frenchf40c5622006-06-28 00:13:38 +0000420 cFYI(1,("secFlags 0x%x",secFlags));
421
Steve French1982c342005-08-17 12:38:22 -0700422 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French750d1152006-06-27 06:28:30 +0000424 if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000425 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000426
427 count = 0;
428 for(i=0;i<CIFS_NUM_PROT;i++) {
429 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
430 count += strlen(protocols[i].name) + 1;
431 /* null at end of source and target buffers anyway */
432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 pSMB->hdr.smb_buf_length += count;
434 pSMB->ByteCount = cpu_to_le16(count);
435
436 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
437 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000438 if (rc != 0)
439 goto neg_err_exit;
440
441 cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
442 /* Check wct = 1 error case */
443 if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
444 /* core returns wct = 1, but we do not ask for core - otherwise
445 small wct just comes when dialect index is -1 indicating we
446 could not negotiate a common dialect */
447 rc = -EOPNOTSUPP;
448 goto neg_err_exit;
449#ifdef CONFIG_CIFS_WEAK_PW_HASH
450 } else if((pSMBr->hdr.WordCount == 13)
Steve French9ac00b72006-09-30 04:13:17 +0000451 && ((pSMBr->DialectIndex == LANMAN_PROT)
452 || (pSMBr->DialectIndex == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000453 __s16 tmp;
Steve French254e55e2006-06-04 05:53:15 +0000454 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
455
Steve French750d1152006-06-27 06:28:30 +0000456 if((secFlags & CIFSSEC_MAY_LANMAN) ||
457 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000458 server->secType = LANMAN;
459 else {
460 cERROR(1, ("mount failed weak security disabled"
461 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000462 rc = -EOPNOTSUPP;
463 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000464 }
465 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
466 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
467 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000468 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000469 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
470 /* even though we do not use raw we might as well set this
471 accurately, in case we ever find a need for it */
472 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
473 server->maxRw = 0xFF00;
474 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
475 } else {
476 server->maxRw = 0;/* we do not need to use raw anyway */
477 server->capabilities = CAP_MPX_MODE;
478 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000479 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000480 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000481 /* OS/2 often does not set timezone therefore
482 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000483 * Could deviate slightly from the right zone.
484 * Smallest defined timezone difference is 15 minutes
485 * (i.e. Nepal). Rounding up/down is done to match
486 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000487 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000489 struct timespec ts, utc;
490 utc = CURRENT_TIME;
491 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
492 le16_to_cpu(rsp->SrvTime.Time));
493 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
494 (int)ts.tv_sec, (int)utc.tv_sec,
495 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000496 val = (int)(utc.tv_sec - ts.tv_sec);
497 seconds = val < 0 ? -val : val;
Steve French947a5062006-10-02 05:55:25 +0000498 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000499 remain = seconds % MIN_TZ_ADJ;
500 if(remain >= (MIN_TZ_ADJ / 2))
501 result += MIN_TZ_ADJ;
502 if(val < 0)
503 result = - result;
504 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000505 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000506 server->timeAdj = (int)tmp;
507 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000508 }
Steve French175ec9e2006-09-30 01:07:38 +0000509 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000510
Steve French39798772006-05-31 22:40:51 +0000511
Steve French254e55e2006-06-04 05:53:15 +0000512 /* BB get server time for time conversions and add
513 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000514
Steve French25ee4a92006-09-30 00:54:23 +0000515 if (rsp->EncryptionKeyLength ==
516 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000517 memcpy(server->cryptKey, rsp->EncryptionKey,
518 CIFS_CRYPTO_KEY_SIZE);
519 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
520 rc = -EIO; /* need cryptkey unless plain text */
521 goto neg_err_exit;
522 }
Steve French39798772006-05-31 22:40:51 +0000523
Steve French254e55e2006-06-04 05:53:15 +0000524 cFYI(1,("LANMAN negotiated"));
525 /* we will not end up setting signing flags - as no signing
526 was in LANMAN and server did not return the flags on */
527 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000528#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000529 } else if(pSMBr->hdr.WordCount == 13) {
530 cERROR(1,("mount failed, cifs module not built "
531 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000532 rc = -EOPNOTSUPP;
533#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000534 goto neg_err_exit;
535 } else if(pSMBr->hdr.WordCount != 17) {
536 /* unknown wct */
537 rc = -EOPNOTSUPP;
538 goto neg_err_exit;
539 }
540 /* else wct == 17 NTLM */
541 server->secMode = pSMBr->SecurityMode;
542 if((server->secMode & SECMODE_USER) == 0)
543 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000544
Steve French254e55e2006-06-04 05:53:15 +0000545 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000546#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000547 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000548#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000549 cERROR(1,("Server requests plain text password"
550 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000551
Steve Frenchf40c5622006-06-28 00:13:38 +0000552 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000553 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000554 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000555 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000556 else if(secFlags & CIFSSEC_MAY_NTLMV2)
557 server->secType = NTLMv2;
558 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000559
Steve French254e55e2006-06-04 05:53:15 +0000560 /* one byte, so no need to convert this or EncryptionKeyLen from
561 little endian */
562 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
563 /* probably no need to store and check maxvcs */
564 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000566 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
567 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
568 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
569 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000570 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
571 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000572 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
573 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
574 CIFS_CRYPTO_KEY_SIZE);
575 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
576 && (pSMBr->EncryptionKeyLength == 0)) {
577 /* decode security blob */
578 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
579 rc = -EIO; /* no crypt key only if plain text pwd */
580 goto neg_err_exit;
581 }
582
583 /* BB might be helpful to save off the domain of server here */
584
585 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
586 (server->capabilities & CAP_EXTENDED_SECURITY)) {
587 count = pSMBr->ByteCount;
588 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000590 else if (count == 16) {
591 server->secType = RawNTLMSSP;
592 if (server->socketUseCount.counter > 1) {
593 if (memcmp(server->server_GUID,
594 pSMBr->u.extended_response.
595 GUID, 16) != 0) {
596 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000598 pSMBr->u.extended_response.GUID,
599 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 }
Steve French254e55e2006-06-04 05:53:15 +0000601 } else
602 memcpy(server->server_GUID,
603 pSMBr->u.extended_response.GUID, 16);
604 } else {
605 rc = decode_negTokenInit(pSMBr->u.extended_response.
606 SecurityBlob,
607 count - 16,
608 &server->secType);
609 if(rc == 1) {
610 /* BB Need to fill struct for sessetup here */
611 rc = -EOPNOTSUPP;
612 } else {
613 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
Steve French254e55e2006-06-04 05:53:15 +0000616 } else
617 server->capabilities &= ~CAP_EXTENDED_SECURITY;
618
Steve French6344a422006-06-12 04:18:35 +0000619#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000620signing_check:
Steve French6344a422006-06-12 04:18:35 +0000621#endif
Steve French254e55e2006-06-04 05:53:15 +0000622 if(sign_CIFS_PDUs == FALSE) {
623 if(server->secMode & SECMODE_SIGN_REQUIRED)
624 cERROR(1,("Server requires "
625 "/proc/fs/cifs/PacketSigningEnabled to be on"));
626 server->secMode &=
627 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
628 } else if(sign_CIFS_PDUs == 1) {
629 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
630 server->secMode &=
631 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
632 } else if(sign_CIFS_PDUs == 2) {
633 if((server->secMode &
634 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
635 cERROR(1,("signing required but server lacks support"));
636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 }
Steve French39798772006-05-31 22:40:51 +0000638neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700639 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000640
641 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return rc;
643}
644
645int
646CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
647{
648 struct smb_hdr *smb_buffer;
649 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
650 int rc = 0;
651 int length;
652
653 cFYI(1, ("In tree disconnect"));
654 /*
655 * If last user of the connection and
656 * connection alive - disconnect it
657 * If this is the last connection on the server session disconnect it
658 * (and inside session disconnect we should check if tcp socket needs
659 * to be freed and kernel thread woken up).
660 */
661 if (tcon)
662 down(&tcon->tconSem);
663 else
664 return -EIO;
665
666 atomic_dec(&tcon->useCount);
667 if (atomic_read(&tcon->useCount) > 0) {
668 up(&tcon->tconSem);
669 return -EBUSY;
670 }
671
672 /* No need to return error on this operation if tid invalidated and
673 closed on server already e.g. due to tcp session crashing */
674 if(tcon->tidStatus == CifsNeedReconnect) {
675 up(&tcon->tconSem);
676 return 0;
677 }
678
679 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
680 up(&tcon->tconSem);
681 return -EIO;
682 }
Steve French09d1db52005-04-28 22:41:08 -0700683 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
684 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (rc) {
686 up(&tcon->tconSem);
687 return rc;
688 } else {
689 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
692 &length, 0);
693 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700694 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696 if (smb_buffer)
697 cifs_small_buf_release(smb_buffer);
698 up(&tcon->tconSem);
699
700 /* No need to return error on this operation if tid invalidated and
701 closed on server already e.g. due to tcp session crashing */
702 if (rc == -EAGAIN)
703 rc = 0;
704
705 return rc;
706}
707
708int
709CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
710{
711 struct smb_hdr *smb_buffer_response;
712 LOGOFF_ANDX_REQ *pSMB;
713 int rc = 0;
714 int length;
715
716 cFYI(1, ("In SMBLogoff for session disconnect"));
717 if (ses)
718 down(&ses->sesSem);
719 else
720 return -EIO;
721
722 atomic_dec(&ses->inUse);
723 if (atomic_read(&ses->inUse) > 0) {
724 up(&ses->sesSem);
725 return -EBUSY;
726 }
727 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
728 if (rc) {
729 up(&ses->sesSem);
730 return rc;
731 }
732
733 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
734
735 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700736 pSMB->hdr.Mid = GetNextMid(ses->server);
737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if(ses->server->secMode &
739 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
740 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
741 }
742
743 pSMB->hdr.Uid = ses->Suid;
744
745 pSMB->AndXCommand = 0xFF;
746 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
747 smb_buffer_response, &length, 0);
748 if (ses->server) {
749 atomic_dec(&ses->server->socketUseCount);
750 if (atomic_read(&ses->server->socketUseCount) == 0) {
751 spin_lock(&GlobalMid_Lock);
752 ses->server->tcpStatus = CifsExiting;
753 spin_unlock(&GlobalMid_Lock);
754 rc = -ESHUTDOWN;
755 }
756 }
Steve Frencha59c6582005-08-17 12:12:19 -0700757 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700758 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
760 /* if session dead then we do not need to do ulogoff,
761 since server closed smb session, no sense reporting
762 error */
763 if (rc == -EAGAIN)
764 rc = 0;
765 return rc;
766}
767
768int
Steve French737b7582005-04-28 22:41:06 -0700769CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
770 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771{
772 DELETE_FILE_REQ *pSMB = NULL;
773 DELETE_FILE_RSP *pSMBr = NULL;
774 int rc = 0;
775 int bytes_returned;
776 int name_len;
777
778DelFileRetry:
779 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
780 (void **) &pSMBr);
781 if (rc)
782 return rc;
783
784 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
785 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500786 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700787 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 name_len++; /* trailing null */
789 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700790 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 name_len = strnlen(fileName, PATH_MAX);
792 name_len++; /* trailing null */
793 strncpy(pSMB->fileName, fileName, name_len);
794 }
795 pSMB->SearchAttributes =
796 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
797 pSMB->BufferFormat = 0x04;
798 pSMB->hdr.smb_buf_length += name_len + 1;
799 pSMB->ByteCount = cpu_to_le16(name_len + 1);
800 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
801 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700802 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (rc) {
804 cFYI(1, ("Error in RMFile = %d", rc));
805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807 cifs_buf_release(pSMB);
808 if (rc == -EAGAIN)
809 goto DelFileRetry;
810
811 return rc;
812}
813
814int
Steve French737b7582005-04-28 22:41:06 -0700815CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
816 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
818 DELETE_DIRECTORY_REQ *pSMB = NULL;
819 DELETE_DIRECTORY_RSP *pSMBr = NULL;
820 int rc = 0;
821 int bytes_returned;
822 int name_len;
823
824 cFYI(1, ("In CIFSSMBRmDir"));
825RmDirRetry:
826 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
827 (void **) &pSMBr);
828 if (rc)
829 return rc;
830
831 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700832 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
833 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 name_len++; /* trailing null */
835 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700836 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 name_len = strnlen(dirName, PATH_MAX);
838 name_len++; /* trailing null */
839 strncpy(pSMB->DirName, dirName, name_len);
840 }
841
842 pSMB->BufferFormat = 0x04;
843 pSMB->hdr.smb_buf_length += name_len + 1;
844 pSMB->ByteCount = cpu_to_le16(name_len + 1);
845 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
846 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700847 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (rc) {
849 cFYI(1, ("Error in RMDir = %d", rc));
850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
852 cifs_buf_release(pSMB);
853 if (rc == -EAGAIN)
854 goto RmDirRetry;
855 return rc;
856}
857
858int
859CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700860 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
862 int rc = 0;
863 CREATE_DIRECTORY_REQ *pSMB = NULL;
864 CREATE_DIRECTORY_RSP *pSMBr = NULL;
865 int bytes_returned;
866 int name_len;
867
868 cFYI(1, ("In CIFSSMBMkDir"));
869MkDirRetry:
870 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
871 (void **) &pSMBr);
872 if (rc)
873 return rc;
874
875 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500876 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700877 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 name_len++; /* trailing null */
879 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700880 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 name_len = strnlen(name, PATH_MAX);
882 name_len++; /* trailing null */
883 strncpy(pSMB->DirName, name, name_len);
884 }
885
886 pSMB->BufferFormat = 0x04;
887 pSMB->hdr.smb_buf_length += name_len + 1;
888 pSMB->ByteCount = cpu_to_le16(name_len + 1);
889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
890 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700891 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (rc) {
893 cFYI(1, ("Error in Mkdir = %d", rc));
894 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700895
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 cifs_buf_release(pSMB);
897 if (rc == -EAGAIN)
898 goto MkDirRetry;
899 return rc;
900}
901
Steve Frencha9d02ad2005-08-24 23:06:05 -0700902static __u16 convert_disposition(int disposition)
903{
904 __u16 ofun = 0;
905
906 switch (disposition) {
907 case FILE_SUPERSEDE:
908 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
909 break;
910 case FILE_OPEN:
911 ofun = SMBOPEN_OAPPEND;
912 break;
913 case FILE_CREATE:
914 ofun = SMBOPEN_OCREATE;
915 break;
916 case FILE_OPEN_IF:
917 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
918 break;
919 case FILE_OVERWRITE:
920 ofun = SMBOPEN_OTRUNC;
921 break;
922 case FILE_OVERWRITE_IF:
923 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
924 break;
925 default:
926 cFYI(1,("unknown disposition %d",disposition));
927 ofun = SMBOPEN_OAPPEND; /* regular open */
928 }
929 return ofun;
930}
931
932int
933SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
934 const char *fileName, const int openDisposition,
935 const int access_flags, const int create_options, __u16 * netfid,
936 int *pOplock, FILE_ALL_INFO * pfile_info,
937 const struct nls_table *nls_codepage, int remap)
938{
939 int rc = -EACCES;
940 OPENX_REQ *pSMB = NULL;
941 OPENX_RSP *pSMBr = NULL;
942 int bytes_returned;
943 int name_len;
944 __u16 count;
945
946OldOpenRetry:
947 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
948 (void **) &pSMBr);
949 if (rc)
950 return rc;
951
952 pSMB->AndXCommand = 0xFF; /* none */
953
954 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
955 count = 1; /* account for one byte pad to word boundary */
956 name_len =
957 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
958 fileName, PATH_MAX, nls_codepage, remap);
959 name_len++; /* trailing null */
960 name_len *= 2;
961 } else { /* BB improve check for buffer overruns BB */
962 count = 0; /* no pad */
963 name_len = strnlen(fileName, PATH_MAX);
964 name_len++; /* trailing null */
965 strncpy(pSMB->fileName, fileName, name_len);
966 }
967 if (*pOplock & REQ_OPLOCK)
968 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
969 else if (*pOplock & REQ_BATCHOPLOCK) {
970 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
971 }
972 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
973 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
974 /* 0 = read
975 1 = write
976 2 = rw
977 3 = execute
978 */
979 pSMB->Mode = cpu_to_le16(2);
980 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
981 /* set file as system file if special file such
982 as fifo and server expecting SFU style and
983 no Unix extensions */
984
985 if(create_options & CREATE_OPTION_SPECIAL)
986 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
987 else
Steve French3e87d802005-09-18 20:49:21 -0700988 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700989
990 /* if ((omode & S_IWUGO) == 0)
991 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
992 /* Above line causes problems due to vfs splitting create into two
993 pieces - need to set mode after file created not while it is
994 being created */
995
996 /* BB FIXME BB */
997/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
998 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700999
1000 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001001 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001002 count += name_len;
1003 pSMB->hdr.smb_buf_length += count;
1004
1005 pSMB->ByteCount = cpu_to_le16(count);
1006 /* long_op set to 1 to allow for oplock break timeouts */
1007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1008 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1009 cifs_stats_inc(&tcon->num_opens);
1010 if (rc) {
1011 cFYI(1, ("Error in Open = %d", rc));
1012 } else {
1013 /* BB verify if wct == 15 */
1014
1015/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1016
1017 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1018 /* Let caller know file was created so we can set the mode. */
1019 /* Do we care about the CreateAction in any other cases? */
1020 /* BB FIXME BB */
1021/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1022 *pOplock |= CIFS_CREATE_ACTION; */
1023 /* BB FIXME END */
1024
1025 if(pfile_info) {
1026 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1027 pfile_info->LastAccessTime = 0; /* BB fixme */
1028 pfile_info->LastWriteTime = 0; /* BB fixme */
1029 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001030 pfile_info->Attributes =
1031 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001032 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001033 pfile_info->AllocationSize =
1034 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1035 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001036 pfile_info->NumberOfLinks = cpu_to_le32(1);
1037 }
1038 }
1039
1040 cifs_buf_release(pSMB);
1041 if (rc == -EAGAIN)
1042 goto OldOpenRetry;
1043 return rc;
1044}
1045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046int
1047CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1048 const char *fileName, const int openDisposition,
1049 const int access_flags, const int create_options, __u16 * netfid,
1050 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001051 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052{
1053 int rc = -EACCES;
1054 OPEN_REQ *pSMB = NULL;
1055 OPEN_RSP *pSMBr = NULL;
1056 int bytes_returned;
1057 int name_len;
1058 __u16 count;
1059
1060openRetry:
1061 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1062 (void **) &pSMBr);
1063 if (rc)
1064 return rc;
1065
1066 pSMB->AndXCommand = 0xFF; /* none */
1067
1068 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1069 count = 1; /* account for one byte pad to word boundary */
1070 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001071 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001072 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 name_len++; /* trailing null */
1074 name_len *= 2;
1075 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001076 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 count = 0; /* no pad */
1078 name_len = strnlen(fileName, PATH_MAX);
1079 name_len++; /* trailing null */
1080 pSMB->NameLength = cpu_to_le16(name_len);
1081 strncpy(pSMB->fileName, fileName, name_len);
1082 }
1083 if (*pOplock & REQ_OPLOCK)
1084 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1085 else if (*pOplock & REQ_BATCHOPLOCK) {
1086 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1087 }
1088 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1089 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001090 /* set file as system file if special file such
1091 as fifo and server expecting SFU style and
1092 no Unix extensions */
1093 if(create_options & CREATE_OPTION_SPECIAL)
1094 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1095 else
1096 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 /* XP does not handle ATTR_POSIX_SEMANTICS */
1098 /* but it helps speed up case sensitive checks for other
1099 servers such as Samba */
1100 if (tcon->ses->capabilities & CAP_UNIX)
1101 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1102
1103 /* if ((omode & S_IWUGO) == 0)
1104 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1105 /* Above line causes problems due to vfs splitting create into two
1106 pieces - need to set mode after file created not while it is
1107 being created */
1108 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1109 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001110 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001111 /* BB Expirement with various impersonation levels and verify */
1112 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 pSMB->SecurityFlags =
1114 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1115
1116 count += name_len;
1117 pSMB->hdr.smb_buf_length += count;
1118
1119 pSMB->ByteCount = cpu_to_le16(count);
1120 /* long_op set to 1 to allow for oplock break timeouts */
1121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1122 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001123 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 if (rc) {
1125 cFYI(1, ("Error in Open = %d", rc));
1126 } else {
Steve French09d1db52005-04-28 22:41:08 -07001127 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1129 /* Let caller know file was created so we can set the mode. */
1130 /* Do we care about the CreateAction in any other cases? */
1131 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1132 *pOplock |= CIFS_CREATE_ACTION;
1133 if(pfile_info) {
1134 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1135 36 /* CreationTime to Attributes */);
1136 /* the file_info buf is endian converted by caller */
1137 pfile_info->AllocationSize = pSMBr->AllocationSize;
1138 pfile_info->EndOfFile = pSMBr->EndOfFile;
1139 pfile_info->NumberOfLinks = cpu_to_le32(1);
1140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 cifs_buf_release(pSMB);
1144 if (rc == -EAGAIN)
1145 goto openRetry;
1146 return rc;
1147}
1148
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149int
1150CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001151 const int netfid, const unsigned int count,
1152 const __u64 lseek, unsigned int *nbytes, char **buf,
1153 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
1155 int rc = -EACCES;
1156 READ_REQ *pSMB = NULL;
1157 READ_RSP *pSMBr = NULL;
1158 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001159 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001160 int resp_buf_type = 0;
1161 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
1163 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001164 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1165 wct = 12;
1166 else
1167 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001170 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (rc)
1172 return rc;
1173
1174 /* tcon and ses pointer are checked in smb_init */
1175 if (tcon->ses->server == NULL)
1176 return -ECONNABORTED;
1177
Steve Frenchec637e32005-12-12 20:53:18 -08001178 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 pSMB->Fid = netfid;
1180 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001181 if(wct == 12)
1182 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001183 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1184 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 pSMB->Remaining = 0;
1187 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1188 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001189 if(wct == 12)
1190 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1191 else {
1192 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001193 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001194 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001195 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001196 }
Steve Frenchec637e32005-12-12 20:53:18 -08001197
1198 iov[0].iov_base = (char *)pSMB;
1199 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1200 rc = SendReceive2(xid, tcon->ses, iov,
1201 1 /* num iovecs */,
1202 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001203 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001204 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 if (rc) {
1206 cERROR(1, ("Send error in read = %d", rc));
1207 } else {
1208 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1209 data_length = data_length << 16;
1210 data_length += le16_to_cpu(pSMBr->DataLength);
1211 *nbytes = data_length;
1212
1213 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001214 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 || (data_length > count)) {
1216 cFYI(1,("bad length %d for count %d",data_length,count));
1217 rc = -EIO;
1218 *nbytes = 0;
1219 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001220 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001222/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1223 cERROR(1,("Faulting on read rc = %d",rc));
1224 rc = -EFAULT;
1225 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001227 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 }
1229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Steve French4b8f9302006-02-26 16:41:18 +00001231/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001232 if(*buf) {
1233 if(resp_buf_type == CIFS_SMALL_BUFFER)
1234 cifs_small_buf_release(iov[0].iov_base);
1235 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1236 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001237 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1238 /* return buffer to caller to free */
1239 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001240 if(resp_buf_type == CIFS_SMALL_BUFFER)
1241 *pbuf_type = CIFS_SMALL_BUFFER;
1242 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1243 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001244 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001245
1246 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 since file handle passed in no longer valid */
1248 return rc;
1249}
1250
Steve Frenchec637e32005-12-12 20:53:18 -08001251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252int
1253CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1254 const int netfid, const unsigned int count,
1255 const __u64 offset, unsigned int *nbytes, const char *buf,
1256 const char __user * ubuf, const int long_op)
1257{
1258 int rc = -EACCES;
1259 WRITE_REQ *pSMB = NULL;
1260 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001261 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 __u32 bytes_sent;
1263 __u16 byte_count;
1264
1265 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001266 if(tcon->ses == NULL)
1267 return -ECONNABORTED;
1268
1269 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1270 wct = 14;
1271 else
1272 wct = 12;
1273
1274 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 (void **) &pSMBr);
1276 if (rc)
1277 return rc;
1278 /* tcon and ses pointer are checked in smb_init */
1279 if (tcon->ses->server == NULL)
1280 return -ECONNABORTED;
1281
1282 pSMB->AndXCommand = 0xFF; /* none */
1283 pSMB->Fid = netfid;
1284 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001285 if(wct == 14)
1286 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1287 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1288 return -EIO;
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 pSMB->Reserved = 0xFFFFFFFF;
1291 pSMB->WriteMode = 0;
1292 pSMB->Remaining = 0;
1293
1294 /* Can increase buffer size if buffer is big enough in some cases - ie we
1295 can send more if LARGE_WRITE_X capability returned by the server and if
1296 our buffer is big enough or if we convert to iovecs on socket writes
1297 and eliminate the copy to the CIFS buffer */
1298 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1299 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1300 } else {
1301 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1302 & ~0xFF;
1303 }
1304
1305 if (bytes_sent > count)
1306 bytes_sent = count;
1307 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001308 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 if(buf)
1310 memcpy(pSMB->Data,buf,bytes_sent);
1311 else if(ubuf) {
1312 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1313 cifs_buf_release(pSMB);
1314 return -EFAULT;
1315 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001316 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 /* No buffer */
1318 cifs_buf_release(pSMB);
1319 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001320 } /* else setting file size with write of zero bytes */
1321 if(wct == 14)
1322 byte_count = bytes_sent + 1; /* pad */
1323 else /* wct == 12 */ {
1324 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1327 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001328 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001329
1330 if(wct == 14)
1331 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001332 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001333 struct smb_com_writex_req * pSMBW =
1334 (struct smb_com_writex_req *)pSMB;
1335 pSMBW->ByteCount = cpu_to_le16(byte_count);
1336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1339 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001340 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 if (rc) {
1342 cFYI(1, ("Send error in write = %d", rc));
1343 *nbytes = 0;
1344 } else {
1345 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1346 *nbytes = (*nbytes) << 16;
1347 *nbytes += le16_to_cpu(pSMBr->Count);
1348 }
1349
1350 cifs_buf_release(pSMB);
1351
1352 /* Note: On -EAGAIN error only caller can retry on handle based calls
1353 since file handle passed in no longer valid */
1354
1355 return rc;
1356}
1357
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001358int
1359CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001361 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1362 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363{
1364 int rc = -EACCES;
1365 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001366 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001367 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001368 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
Steve Frenchff7feac2005-11-15 16:45:16 -08001370 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1371
Steve French8cc64c62005-10-03 13:49:43 -07001372 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1373 wct = 14;
1374 else
1375 wct = 12;
1376 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 if (rc)
1378 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 /* tcon and ses pointer are checked in smb_init */
1380 if (tcon->ses->server == NULL)
1381 return -ECONNABORTED;
1382
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001383 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 pSMB->Fid = netfid;
1385 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001386 if(wct == 14)
1387 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1388 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1389 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 pSMB->Reserved = 0xFFFFFFFF;
1391 pSMB->WriteMode = 0;
1392 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 pSMB->DataOffset =
1395 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1396
Steve French3e844692005-10-03 13:37:24 -07001397 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1398 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001399 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001400 if(wct == 14)
1401 pSMB->hdr.smb_buf_length += count+1;
1402 else /* wct == 12 */
1403 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1404 if(wct == 14)
1405 pSMB->ByteCount = cpu_to_le16(count + 1);
1406 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1407 struct smb_com_writex_req * pSMBW =
1408 (struct smb_com_writex_req *)pSMB;
1409 pSMBW->ByteCount = cpu_to_le16(count + 5);
1410 }
Steve French3e844692005-10-03 13:37:24 -07001411 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001412 if(wct == 14)
1413 iov[0].iov_len = smb_hdr_len + 4;
1414 else /* wct == 12 pad bigger by four bytes */
1415 iov[0].iov_len = smb_hdr_len + 8;
1416
Steve French3e844692005-10-03 13:37:24 -07001417
Steve Frenchec637e32005-12-12 20:53:18 -08001418 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001419 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001420 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001422 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001424 } else if(resp_buf_type == 0) {
1425 /* presumably this can not happen, but best to be safe */
1426 rc = -EIO;
1427 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001428 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001429 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001430 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1431 *nbytes = (*nbytes) << 16;
1432 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Steve French4b8f9302006-02-26 16:41:18 +00001435/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001436 if(resp_buf_type == CIFS_SMALL_BUFFER)
1437 cifs_small_buf_release(iov[0].iov_base);
1438 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1439 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440
1441 /* Note: On -EAGAIN error only caller can retry on handle based calls
1442 since file handle passed in no longer valid */
1443
1444 return rc;
1445}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001446
1447
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448int
1449CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1450 const __u16 smb_file_id, const __u64 len,
1451 const __u64 offset, const __u32 numUnlock,
1452 const __u32 numLock, const __u8 lockType, const int waitFlag)
1453{
1454 int rc = 0;
1455 LOCK_REQ *pSMB = NULL;
1456 LOCK_RSP *pSMBr = NULL;
1457 int bytes_returned;
1458 int timeout = 0;
1459 __u16 count;
1460
1461 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001462 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1463
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 if (rc)
1465 return rc;
1466
Steve French46810cb2005-04-28 22:41:09 -07001467 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1468
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1470 timeout = -1; /* no response expected */
1471 pSMB->Timeout = 0;
1472 } else if (waitFlag == TRUE) {
1473 timeout = 3; /* blocking operation, no timeout */
1474 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1475 } else {
1476 pSMB->Timeout = 0;
1477 }
1478
1479 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1480 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1481 pSMB->LockType = lockType;
1482 pSMB->AndXCommand = 0xFF; /* none */
1483 pSMB->Fid = smb_file_id; /* netfid stays le */
1484
1485 if((numLock != 0) || (numUnlock != 0)) {
1486 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1487 /* BB where to store pid high? */
1488 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1489 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1490 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1491 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1492 count = sizeof(LOCKING_ANDX_RANGE);
1493 } else {
1494 /* oplock break */
1495 count = 0;
1496 }
1497 pSMB->hdr.smb_buf_length += count;
1498 pSMB->ByteCount = cpu_to_le16(count);
1499
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001500 if (waitFlag) {
1501 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1502 (struct smb_hdr *) pSMBr, &bytes_returned);
1503 } else {
1504 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001506 }
Steve Frencha4544342005-08-24 13:59:35 -07001507 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 if (rc) {
1509 cFYI(1, ("Send error in Lock = %d", rc));
1510 }
Steve French46810cb2005-04-28 22:41:09 -07001511 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
1513 /* Note: On -EAGAIN error only caller can retry on handle based calls
1514 since file handle passed in no longer valid */
1515 return rc;
1516}
1517
1518int
Steve French08547b02006-02-28 22:39:25 +00001519CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1520 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001521 struct file_lock *pLockData, const __u16 lock_type,
1522 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001523{
1524 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1525 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1526 char *data_offset;
1527 struct cifs_posix_lock *parm_data;
1528 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001529 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001530 int bytes_returned = 0;
1531 __u16 params, param_offset, offset, byte_count, count;
1532
1533 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001534
1535 if(pLockData == NULL)
1536 return EINVAL;
1537
Steve French08547b02006-02-28 22:39:25 +00001538 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1539
1540 if (rc)
1541 return rc;
1542
1543 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1544
1545 params = 6;
1546 pSMB->MaxSetupCount = 0;
1547 pSMB->Reserved = 0;
1548 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001549 pSMB->Reserved2 = 0;
1550 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1551 offset = param_offset + params;
1552
1553 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1554
1555 count = sizeof(struct cifs_posix_lock);
1556 pSMB->MaxParameterCount = cpu_to_le16(2);
1557 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1558 pSMB->SetupCount = 1;
1559 pSMB->Reserved3 = 0;
1560 if(get_flag)
1561 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1562 else
1563 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1564 byte_count = 3 /* pad */ + params + count;
1565 pSMB->DataCount = cpu_to_le16(count);
1566 pSMB->ParameterCount = cpu_to_le16(params);
1567 pSMB->TotalDataCount = pSMB->DataCount;
1568 pSMB->TotalParameterCount = pSMB->ParameterCount;
1569 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1570 parm_data = (struct cifs_posix_lock *)
1571 (((char *) &pSMB->hdr.Protocol) + offset);
1572
1573 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001574 if(waitFlag) {
1575 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001576 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001577 pSMB->Timeout = cpu_to_le32(-1);
1578 } else
1579 pSMB->Timeout = 0;
1580
Steve French08547b02006-02-28 22:39:25 +00001581 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001582 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001583 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001584
1585 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001586 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001587 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1588 pSMB->Reserved4 = 0;
1589 pSMB->hdr.smb_buf_length += byte_count;
1590 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001591 if (waitFlag) {
1592 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1593 (struct smb_hdr *) pSMBr, &bytes_returned);
1594 } else {
1595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001596 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001597 }
1598
Steve French08547b02006-02-28 22:39:25 +00001599 if (rc) {
1600 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001601 } else if (get_flag) {
1602 /* lock structure can be returned on get */
1603 __u16 data_offset;
1604 __u16 data_count;
1605 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001606
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001607 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1608 rc = -EIO; /* bad smb */
1609 goto plk_err_exit;
1610 }
1611 if(pLockData == NULL) {
1612 rc = -EINVAL;
1613 goto plk_err_exit;
1614 }
1615 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1616 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1617 if(data_count < sizeof(struct cifs_posix_lock)) {
1618 rc = -EIO;
1619 goto plk_err_exit;
1620 }
1621 parm_data = (struct cifs_posix_lock *)
1622 ((char *)&pSMBr->hdr.Protocol + data_offset);
1623 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1624 pLockData->fl_type = F_UNLCK;
1625 }
1626
1627plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001628 if (pSMB)
1629 cifs_small_buf_release(pSMB);
1630
1631 /* Note: On -EAGAIN error only caller can retry on handle based calls
1632 since file handle passed in no longer valid */
1633
1634 return rc;
1635}
1636
1637
1638int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1640{
1641 int rc = 0;
1642 CLOSE_REQ *pSMB = NULL;
1643 CLOSE_RSP *pSMBr = NULL;
1644 int bytes_returned;
1645 cFYI(1, ("In CIFSSMBClose"));
1646
1647/* do not retry on dead session on close */
1648 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1649 if(rc == -EAGAIN)
1650 return 0;
1651 if (rc)
1652 return rc;
1653
1654 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1655
1656 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001657 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 pSMB->ByteCount = 0;
1659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001661 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 if (rc) {
1663 if(rc!=-EINTR) {
1664 /* EINTR is expected when user ctl-c to kill app */
1665 cERROR(1, ("Send error in Close = %d", rc));
1666 }
1667 }
1668
1669 cifs_small_buf_release(pSMB);
1670
1671 /* Since session is dead, file will be closed on server already */
1672 if(rc == -EAGAIN)
1673 rc = 0;
1674
1675 return rc;
1676}
1677
1678int
1679CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1680 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001681 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682{
1683 int rc = 0;
1684 RENAME_REQ *pSMB = NULL;
1685 RENAME_RSP *pSMBr = NULL;
1686 int bytes_returned;
1687 int name_len, name_len2;
1688 __u16 count;
1689
1690 cFYI(1, ("In CIFSSMBRename"));
1691renameRetry:
1692 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1693 (void **) &pSMBr);
1694 if (rc)
1695 return rc;
1696
1697 pSMB->BufferFormat = 0x04;
1698 pSMB->SearchAttributes =
1699 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1700 ATTR_DIRECTORY);
1701
1702 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1703 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001704 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001705 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 name_len++; /* trailing null */
1707 name_len *= 2;
1708 pSMB->OldFileName[name_len] = 0x04; /* pad */
1709 /* protocol requires ASCII signature byte on Unicode string */
1710 pSMB->OldFileName[name_len + 1] = 0x00;
1711 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001712 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001713 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1715 name_len2 *= 2; /* convert to bytes */
1716 } else { /* BB improve the check for buffer overruns BB */
1717 name_len = strnlen(fromName, PATH_MAX);
1718 name_len++; /* trailing null */
1719 strncpy(pSMB->OldFileName, fromName, name_len);
1720 name_len2 = strnlen(toName, PATH_MAX);
1721 name_len2++; /* trailing null */
1722 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1723 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1724 name_len2++; /* trailing null */
1725 name_len2++; /* signature byte */
1726 }
1727
1728 count = 1 /* 1st signature byte */ + name_len + name_len2;
1729 pSMB->hdr.smb_buf_length += count;
1730 pSMB->ByteCount = cpu_to_le16(count);
1731
1732 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1733 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001734 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 if (rc) {
1736 cFYI(1, ("Send error in rename = %d", rc));
1737 }
1738
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 cifs_buf_release(pSMB);
1740
1741 if (rc == -EAGAIN)
1742 goto renameRetry;
1743
1744 return rc;
1745}
1746
1747int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001748 int netfid, char * target_name,
1749 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750{
1751 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1752 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1753 struct set_file_rename * rename_info;
1754 char *data_offset;
1755 char dummy_string[30];
1756 int rc = 0;
1757 int bytes_returned = 0;
1758 int len_of_str;
1759 __u16 params, param_offset, offset, count, byte_count;
1760
1761 cFYI(1, ("Rename to File by handle"));
1762 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1763 (void **) &pSMBr);
1764 if (rc)
1765 return rc;
1766
1767 params = 6;
1768 pSMB->MaxSetupCount = 0;
1769 pSMB->Reserved = 0;
1770 pSMB->Flags = 0;
1771 pSMB->Timeout = 0;
1772 pSMB->Reserved2 = 0;
1773 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1774 offset = param_offset + params;
1775
1776 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1777 rename_info = (struct set_file_rename *) data_offset;
1778 pSMB->MaxParameterCount = cpu_to_le16(2);
1779 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1780 pSMB->SetupCount = 1;
1781 pSMB->Reserved3 = 0;
1782 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1783 byte_count = 3 /* pad */ + params;
1784 pSMB->ParameterCount = cpu_to_le16(params);
1785 pSMB->TotalParameterCount = pSMB->ParameterCount;
1786 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1787 pSMB->DataOffset = cpu_to_le16(offset);
1788 /* construct random name ".cifs_tmp<inodenum><mid>" */
1789 rename_info->overwrite = cpu_to_le32(1);
1790 rename_info->root_fid = 0;
1791 /* unicode only call */
1792 if(target_name == NULL) {
1793 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001794 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001795 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001797 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001798 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 }
1800 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1801 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1802 byte_count += count;
1803 pSMB->DataCount = cpu_to_le16(count);
1804 pSMB->TotalDataCount = pSMB->DataCount;
1805 pSMB->Fid = netfid;
1806 pSMB->InformationLevel =
1807 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1808 pSMB->Reserved4 = 0;
1809 pSMB->hdr.smb_buf_length += byte_count;
1810 pSMB->ByteCount = cpu_to_le16(byte_count);
1811 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001813 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 if (rc) {
1815 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1816 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 cifs_buf_release(pSMB);
1819
1820 /* Note: On -EAGAIN error only caller can retry on handle based calls
1821 since file handle passed in no longer valid */
1822
1823 return rc;
1824}
1825
1826int
1827CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1828 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001829 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830{
1831 int rc = 0;
1832 COPY_REQ *pSMB = NULL;
1833 COPY_RSP *pSMBr = NULL;
1834 int bytes_returned;
1835 int name_len, name_len2;
1836 __u16 count;
1837
1838 cFYI(1, ("In CIFSSMBCopy"));
1839copyRetry:
1840 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1841 (void **) &pSMBr);
1842 if (rc)
1843 return rc;
1844
1845 pSMB->BufferFormat = 0x04;
1846 pSMB->Tid2 = target_tid;
1847
1848 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1849
1850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001851 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001852 fromName, PATH_MAX, nls_codepage,
1853 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 name_len++; /* trailing null */
1855 name_len *= 2;
1856 pSMB->OldFileName[name_len] = 0x04; /* pad */
1857 /* protocol requires ASCII signature byte on Unicode string */
1858 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001859 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001860 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1862 name_len2 *= 2; /* convert to bytes */
1863 } else { /* BB improve the check for buffer overruns BB */
1864 name_len = strnlen(fromName, PATH_MAX);
1865 name_len++; /* trailing null */
1866 strncpy(pSMB->OldFileName, fromName, name_len);
1867 name_len2 = strnlen(toName, PATH_MAX);
1868 name_len2++; /* trailing null */
1869 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1870 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1871 name_len2++; /* trailing null */
1872 name_len2++; /* signature byte */
1873 }
1874
1875 count = 1 /* 1st signature byte */ + name_len + name_len2;
1876 pSMB->hdr.smb_buf_length += count;
1877 pSMB->ByteCount = cpu_to_le16(count);
1878
1879 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1880 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1881 if (rc) {
1882 cFYI(1, ("Send error in copy = %d with %d files copied",
1883 rc, le16_to_cpu(pSMBr->CopyCount)));
1884 }
1885 if (pSMB)
1886 cifs_buf_release(pSMB);
1887
1888 if (rc == -EAGAIN)
1889 goto copyRetry;
1890
1891 return rc;
1892}
1893
1894int
1895CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1896 const char *fromName, const char *toName,
1897 const struct nls_table *nls_codepage)
1898{
1899 TRANSACTION2_SPI_REQ *pSMB = NULL;
1900 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1901 char *data_offset;
1902 int name_len;
1903 int name_len_target;
1904 int rc = 0;
1905 int bytes_returned = 0;
1906 __u16 params, param_offset, offset, byte_count;
1907
1908 cFYI(1, ("In Symlink Unix style"));
1909createSymLinkRetry:
1910 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1911 (void **) &pSMBr);
1912 if (rc)
1913 return rc;
1914
1915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1916 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001917 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 /* find define for this maxpathcomponent */
1919 , nls_codepage);
1920 name_len++; /* trailing null */
1921 name_len *= 2;
1922
1923 } else { /* BB improve the check for buffer overruns BB */
1924 name_len = strnlen(fromName, PATH_MAX);
1925 name_len++; /* trailing null */
1926 strncpy(pSMB->FileName, fromName, name_len);
1927 }
1928 params = 6 + name_len;
1929 pSMB->MaxSetupCount = 0;
1930 pSMB->Reserved = 0;
1931 pSMB->Flags = 0;
1932 pSMB->Timeout = 0;
1933 pSMB->Reserved2 = 0;
1934 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1935 InformationLevel) - 4;
1936 offset = param_offset + params;
1937
1938 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1940 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001941 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 /* find define for this maxpathcomponent */
1943 , nls_codepage);
1944 name_len_target++; /* trailing null */
1945 name_len_target *= 2;
1946 } else { /* BB improve the check for buffer overruns BB */
1947 name_len_target = strnlen(toName, PATH_MAX);
1948 name_len_target++; /* trailing null */
1949 strncpy(data_offset, toName, name_len_target);
1950 }
1951
1952 pSMB->MaxParameterCount = cpu_to_le16(2);
1953 /* BB find exact max on data count below from sess */
1954 pSMB->MaxDataCount = cpu_to_le16(1000);
1955 pSMB->SetupCount = 1;
1956 pSMB->Reserved3 = 0;
1957 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1958 byte_count = 3 /* pad */ + params + name_len_target;
1959 pSMB->DataCount = cpu_to_le16(name_len_target);
1960 pSMB->ParameterCount = cpu_to_le16(params);
1961 pSMB->TotalDataCount = pSMB->DataCount;
1962 pSMB->TotalParameterCount = pSMB->ParameterCount;
1963 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1964 pSMB->DataOffset = cpu_to_le16(offset);
1965 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1966 pSMB->Reserved4 = 0;
1967 pSMB->hdr.smb_buf_length += byte_count;
1968 pSMB->ByteCount = cpu_to_le16(byte_count);
1969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001971 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 if (rc) {
1973 cFYI(1,
1974 ("Send error in SetPathInfo (create symlink) = %d",
1975 rc));
1976 }
1977
1978 if (pSMB)
1979 cifs_buf_release(pSMB);
1980
1981 if (rc == -EAGAIN)
1982 goto createSymLinkRetry;
1983
1984 return rc;
1985}
1986
1987int
1988CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1989 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001990 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991{
1992 TRANSACTION2_SPI_REQ *pSMB = NULL;
1993 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1994 char *data_offset;
1995 int name_len;
1996 int name_len_target;
1997 int rc = 0;
1998 int bytes_returned = 0;
1999 __u16 params, param_offset, offset, byte_count;
2000
2001 cFYI(1, ("In Create Hard link Unix style"));
2002createHardLinkRetry:
2003 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2004 (void **) &pSMBr);
2005 if (rc)
2006 return rc;
2007
2008 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002009 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002010 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 name_len++; /* trailing null */
2012 name_len *= 2;
2013
2014 } else { /* BB improve the check for buffer overruns BB */
2015 name_len = strnlen(toName, PATH_MAX);
2016 name_len++; /* trailing null */
2017 strncpy(pSMB->FileName, toName, name_len);
2018 }
2019 params = 6 + name_len;
2020 pSMB->MaxSetupCount = 0;
2021 pSMB->Reserved = 0;
2022 pSMB->Flags = 0;
2023 pSMB->Timeout = 0;
2024 pSMB->Reserved2 = 0;
2025 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2026 InformationLevel) - 4;
2027 offset = param_offset + params;
2028
2029 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2030 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2031 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002032 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002033 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 name_len_target++; /* trailing null */
2035 name_len_target *= 2;
2036 } else { /* BB improve the check for buffer overruns BB */
2037 name_len_target = strnlen(fromName, PATH_MAX);
2038 name_len_target++; /* trailing null */
2039 strncpy(data_offset, fromName, name_len_target);
2040 }
2041
2042 pSMB->MaxParameterCount = cpu_to_le16(2);
2043 /* BB find exact max on data count below from sess*/
2044 pSMB->MaxDataCount = cpu_to_le16(1000);
2045 pSMB->SetupCount = 1;
2046 pSMB->Reserved3 = 0;
2047 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2048 byte_count = 3 /* pad */ + params + name_len_target;
2049 pSMB->ParameterCount = cpu_to_le16(params);
2050 pSMB->TotalParameterCount = pSMB->ParameterCount;
2051 pSMB->DataCount = cpu_to_le16(name_len_target);
2052 pSMB->TotalDataCount = pSMB->DataCount;
2053 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2054 pSMB->DataOffset = cpu_to_le16(offset);
2055 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2056 pSMB->Reserved4 = 0;
2057 pSMB->hdr.smb_buf_length += byte_count;
2058 pSMB->ByteCount = cpu_to_le16(byte_count);
2059 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2060 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002061 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (rc) {
2063 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2064 }
2065
2066 cifs_buf_release(pSMB);
2067 if (rc == -EAGAIN)
2068 goto createHardLinkRetry;
2069
2070 return rc;
2071}
2072
2073int
2074CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2075 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002076 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077{
2078 int rc = 0;
2079 NT_RENAME_REQ *pSMB = NULL;
2080 RENAME_RSP *pSMBr = NULL;
2081 int bytes_returned;
2082 int name_len, name_len2;
2083 __u16 count;
2084
2085 cFYI(1, ("In CIFSCreateHardLink"));
2086winCreateHardLinkRetry:
2087
2088 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2089 (void **) &pSMBr);
2090 if (rc)
2091 return rc;
2092
2093 pSMB->SearchAttributes =
2094 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2095 ATTR_DIRECTORY);
2096 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2097 pSMB->ClusterCount = 0;
2098
2099 pSMB->BufferFormat = 0x04;
2100
2101 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2102 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002103 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002104 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 name_len++; /* trailing null */
2106 name_len *= 2;
2107 pSMB->OldFileName[name_len] = 0; /* pad */
2108 pSMB->OldFileName[name_len + 1] = 0x04;
2109 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002110 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002111 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2113 name_len2 *= 2; /* convert to bytes */
2114 } else { /* BB improve the check for buffer overruns BB */
2115 name_len = strnlen(fromName, PATH_MAX);
2116 name_len++; /* trailing null */
2117 strncpy(pSMB->OldFileName, fromName, name_len);
2118 name_len2 = strnlen(toName, PATH_MAX);
2119 name_len2++; /* trailing null */
2120 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2121 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2122 name_len2++; /* trailing null */
2123 name_len2++; /* signature byte */
2124 }
2125
2126 count = 1 /* string type byte */ + name_len + name_len2;
2127 pSMB->hdr.smb_buf_length += count;
2128 pSMB->ByteCount = cpu_to_le16(count);
2129
2130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2131 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002132 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 if (rc) {
2134 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2135 }
2136 cifs_buf_release(pSMB);
2137 if (rc == -EAGAIN)
2138 goto winCreateHardLinkRetry;
2139
2140 return rc;
2141}
2142
2143int
2144CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2145 const unsigned char *searchName,
2146 char *symlinkinfo, const int buflen,
2147 const struct nls_table *nls_codepage)
2148{
2149/* SMB_QUERY_FILE_UNIX_LINK */
2150 TRANSACTION2_QPI_REQ *pSMB = NULL;
2151 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2152 int rc = 0;
2153 int bytes_returned;
2154 int name_len;
2155 __u16 params, byte_count;
2156
2157 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2158
2159querySymLinkRetry:
2160 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2161 (void **) &pSMBr);
2162 if (rc)
2163 return rc;
2164
2165 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2166 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002167 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 /* find define for this maxpathcomponent */
2169 , nls_codepage);
2170 name_len++; /* trailing null */
2171 name_len *= 2;
2172 } else { /* BB improve the check for buffer overruns BB */
2173 name_len = strnlen(searchName, PATH_MAX);
2174 name_len++; /* trailing null */
2175 strncpy(pSMB->FileName, searchName, name_len);
2176 }
2177
2178 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2179 pSMB->TotalDataCount = 0;
2180 pSMB->MaxParameterCount = cpu_to_le16(2);
2181 /* BB find exact max data count below from sess structure BB */
2182 pSMB->MaxDataCount = cpu_to_le16(4000);
2183 pSMB->MaxSetupCount = 0;
2184 pSMB->Reserved = 0;
2185 pSMB->Flags = 0;
2186 pSMB->Timeout = 0;
2187 pSMB->Reserved2 = 0;
2188 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2189 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2190 pSMB->DataCount = 0;
2191 pSMB->DataOffset = 0;
2192 pSMB->SetupCount = 1;
2193 pSMB->Reserved3 = 0;
2194 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2195 byte_count = params + 1 /* pad */ ;
2196 pSMB->TotalParameterCount = cpu_to_le16(params);
2197 pSMB->ParameterCount = pSMB->TotalParameterCount;
2198 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2199 pSMB->Reserved4 = 0;
2200 pSMB->hdr.smb_buf_length += byte_count;
2201 pSMB->ByteCount = cpu_to_le16(byte_count);
2202
2203 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2204 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2205 if (rc) {
2206 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2207 } else {
2208 /* decode response */
2209
2210 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2211 if (rc || (pSMBr->ByteCount < 2))
2212 /* BB also check enough total bytes returned */
2213 rc = -EIO; /* bad smb */
2214 else {
2215 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2216 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2217
2218 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2219 name_len = UniStrnlen((wchar_t *) ((char *)
2220 &pSMBr->hdr.Protocol +data_offset),
2221 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002222 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002224 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 data_offset),
2226 name_len, nls_codepage);
2227 } else {
2228 strncpy(symlinkinfo,
2229 (char *) &pSMBr->hdr.Protocol +
2230 data_offset,
2231 min_t(const int, buflen, count));
2232 }
2233 symlinkinfo[buflen] = 0;
2234 /* just in case so calling code does not go off the end of buffer */
2235 }
2236 }
2237 cifs_buf_release(pSMB);
2238 if (rc == -EAGAIN)
2239 goto querySymLinkRetry;
2240 return rc;
2241}
2242
Steve French0a4b92c2006-01-12 15:44:21 -08002243/* Initialize NT TRANSACT SMB into small smb request buffer.
2244 This assumes that all NT TRANSACTS that we init here have
2245 total parm and data under about 400 bytes (to fit in small cifs
2246 buffer size), which is the case so far, it easily fits. NB:
2247 Setup words themselves and ByteCount
2248 MaxSetupCount (size of returned setup area) and
2249 MaxParameterCount (returned parms size) must be set by caller */
2250static int
2251smb_init_ntransact(const __u16 sub_command, const int setup_count,
2252 const int parm_len, struct cifsTconInfo *tcon,
2253 void ** ret_buf)
2254{
2255 int rc;
2256 __u32 temp_offset;
2257 struct smb_com_ntransact_req * pSMB;
2258
2259 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2260 (void **)&pSMB);
2261 if (rc)
2262 return rc;
2263 *ret_buf = (void *)pSMB;
2264 pSMB->Reserved = 0;
2265 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2266 pSMB->TotalDataCount = 0;
2267 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2268 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2269 pSMB->ParameterCount = pSMB->TotalParameterCount;
2270 pSMB->DataCount = pSMB->TotalDataCount;
2271 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2272 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2273 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2274 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2275 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2276 pSMB->SubCommand = cpu_to_le16(sub_command);
2277 return 0;
2278}
2279
2280static int
2281validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2282 int * pdatalen, int * pparmlen)
2283{
2284 char * end_of_smb;
2285 __u32 data_count, data_offset, parm_count, parm_offset;
2286 struct smb_com_ntransact_rsp * pSMBr;
2287
2288 if(buf == NULL)
2289 return -EINVAL;
2290
2291 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2292
2293 /* ByteCount was converted from little endian in SendReceive */
2294 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2295 (char *)&pSMBr->ByteCount;
2296
2297
2298 data_offset = le32_to_cpu(pSMBr->DataOffset);
2299 data_count = le32_to_cpu(pSMBr->DataCount);
2300 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2301 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2302
2303 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2304 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2305
2306 /* should we also check that parm and data areas do not overlap? */
2307 if(*ppparm > end_of_smb) {
2308 cFYI(1,("parms start after end of smb"));
2309 return -EINVAL;
2310 } else if(parm_count + *ppparm > end_of_smb) {
2311 cFYI(1,("parm end after end of smb"));
2312 return -EINVAL;
2313 } else if(*ppdata > end_of_smb) {
2314 cFYI(1,("data starts after end of smb"));
2315 return -EINVAL;
2316 } else if(data_count + *ppdata > end_of_smb) {
2317 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2318 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2319 return -EINVAL;
2320 } else if(parm_count + data_count > pSMBr->ByteCount) {
2321 cFYI(1,("parm count and data count larger than SMB"));
2322 return -EINVAL;
2323 }
2324 return 0;
2325}
2326
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327int
2328CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2329 const unsigned char *searchName,
2330 char *symlinkinfo, const int buflen,__u16 fid,
2331 const struct nls_table *nls_codepage)
2332{
2333 int rc = 0;
2334 int bytes_returned;
2335 int name_len;
2336 struct smb_com_transaction_ioctl_req * pSMB;
2337 struct smb_com_transaction_ioctl_rsp * pSMBr;
2338
2339 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2340 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2341 (void **) &pSMBr);
2342 if (rc)
2343 return rc;
2344
2345 pSMB->TotalParameterCount = 0 ;
2346 pSMB->TotalDataCount = 0;
2347 pSMB->MaxParameterCount = cpu_to_le32(2);
2348 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002349 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2350 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 pSMB->MaxSetupCount = 4;
2352 pSMB->Reserved = 0;
2353 pSMB->ParameterOffset = 0;
2354 pSMB->DataCount = 0;
2355 pSMB->DataOffset = 0;
2356 pSMB->SetupCount = 4;
2357 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2358 pSMB->ParameterCount = pSMB->TotalParameterCount;
2359 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2360 pSMB->IsFsctl = 1; /* FSCTL */
2361 pSMB->IsRootFlag = 0;
2362 pSMB->Fid = fid; /* file handle always le */
2363 pSMB->ByteCount = 0;
2364
2365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2366 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2367 if (rc) {
2368 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2369 } else { /* decode response */
2370 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2371 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2372 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2373 /* BB also check enough total bytes returned */
2374 rc = -EIO; /* bad smb */
2375 else {
2376 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002377 char * end_of_smb = 2 /* sizeof byte count */ +
2378 pSMBr->ByteCount +
2379 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
2381 struct reparse_data * reparse_buf = (struct reparse_data *)
2382 ((char *)&pSMBr->hdr.Protocol + data_offset);
2383 if((char*)reparse_buf >= end_of_smb) {
2384 rc = -EIO;
2385 goto qreparse_out;
2386 }
2387 if((reparse_buf->LinkNamesBuf +
2388 reparse_buf->TargetNameOffset +
2389 reparse_buf->TargetNameLen) >
2390 end_of_smb) {
2391 cFYI(1,("reparse buf extended beyond SMB"));
2392 rc = -EIO;
2393 goto qreparse_out;
2394 }
2395
2396 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2397 name_len = UniStrnlen((wchar_t *)
2398 (reparse_buf->LinkNamesBuf +
2399 reparse_buf->TargetNameOffset),
2400 min(buflen/2, reparse_buf->TargetNameLen / 2));
2401 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002402 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 reparse_buf->TargetNameOffset),
2404 name_len, nls_codepage);
2405 } else { /* ASCII names */
2406 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2407 reparse_buf->TargetNameOffset,
2408 min_t(const int, buflen, reparse_buf->TargetNameLen));
2409 }
2410 } else {
2411 rc = -EIO;
2412 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2413 }
2414 symlinkinfo[buflen] = 0; /* just in case so the caller
2415 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002416 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 }
2418 }
2419qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002420 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
2422 /* Note: On -EAGAIN error only caller can retry on handle based calls
2423 since file handle passed in no longer valid */
2424
2425 return rc;
2426}
2427
2428#ifdef CONFIG_CIFS_POSIX
2429
2430/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2431static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2432{
2433 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002434 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2435 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2436 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2438
2439 return;
2440}
2441
2442/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002443static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2444 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445{
2446 int size = 0;
2447 int i;
2448 __u16 count;
2449 struct cifs_posix_ace * pACE;
2450 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2451 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2452
2453 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2454 return -EOPNOTSUPP;
2455
2456 if(acl_type & ACL_TYPE_ACCESS) {
2457 count = le16_to_cpu(cifs_acl->access_entry_count);
2458 pACE = &cifs_acl->ace_array[0];
2459 size = sizeof(struct cifs_posix_acl);
2460 size += sizeof(struct cifs_posix_ace) * count;
2461 /* check if we would go beyond end of SMB */
2462 if(size_of_data_area < size) {
2463 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2464 return -EINVAL;
2465 }
2466 } else if(acl_type & ACL_TYPE_DEFAULT) {
2467 count = le16_to_cpu(cifs_acl->access_entry_count);
2468 size = sizeof(struct cifs_posix_acl);
2469 size += sizeof(struct cifs_posix_ace) * count;
2470/* skip past access ACEs to get to default ACEs */
2471 pACE = &cifs_acl->ace_array[count];
2472 count = le16_to_cpu(cifs_acl->default_entry_count);
2473 size += sizeof(struct cifs_posix_ace) * count;
2474 /* check if we would go beyond end of SMB */
2475 if(size_of_data_area < size)
2476 return -EINVAL;
2477 } else {
2478 /* illegal type */
2479 return -EINVAL;
2480 }
2481
2482 size = posix_acl_xattr_size(count);
2483 if((buflen == 0) || (local_acl == NULL)) {
2484 /* used to query ACL EA size */
2485 } else if(size > buflen) {
2486 return -ERANGE;
2487 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002488 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 for(i = 0;i < count ;i++) {
2490 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2491 pACE ++;
2492 }
2493 }
2494 return size;
2495}
2496
2497static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2498 const posix_acl_xattr_entry * local_ace)
2499{
2500 __u16 rc = 0; /* 0 = ACL converted ok */
2501
Steve Frenchff7feac2005-11-15 16:45:16 -08002502 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2503 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002505 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 /* Probably no need to le convert -1 on any arch but can not hurt */
2507 cifs_ace->cifs_uid = cpu_to_le64(-1);
2508 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002509 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2511 return rc;
2512}
2513
2514/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2515static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2516 const int acl_type)
2517{
2518 __u16 rc = 0;
2519 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2520 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2521 int count;
2522 int i;
2523
2524 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2525 return 0;
2526
2527 count = posix_acl_xattr_count((size_t)buflen);
2528 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002529 count, buflen, le32_to_cpu(local_acl->a_version)));
2530 if(le32_to_cpu(local_acl->a_version) != 2) {
2531 cFYI(1,("unknown POSIX ACL version %d",
2532 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 return 0;
2534 }
2535 cifs_acl->version = cpu_to_le16(1);
2536 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002537 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002539 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 else {
2541 cFYI(1,("unknown ACL type %d",acl_type));
2542 return 0;
2543 }
2544 for(i=0;i<count;i++) {
2545 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2546 &local_acl->a_entries[i]);
2547 if(rc != 0) {
2548 /* ACE not converted */
2549 break;
2550 }
2551 }
2552 if(rc == 0) {
2553 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2554 rc += sizeof(struct cifs_posix_acl);
2555 /* BB add check to make sure ACL does not overflow SMB */
2556 }
2557 return rc;
2558}
2559
2560int
2561CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2562 const unsigned char *searchName,
2563 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002564 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565{
2566/* SMB_QUERY_POSIX_ACL */
2567 TRANSACTION2_QPI_REQ *pSMB = NULL;
2568 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2569 int rc = 0;
2570 int bytes_returned;
2571 int name_len;
2572 __u16 params, byte_count;
2573
2574 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2575
2576queryAclRetry:
2577 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2578 (void **) &pSMBr);
2579 if (rc)
2580 return rc;
2581
2582 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2583 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002584 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002585 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 name_len++; /* trailing null */
2587 name_len *= 2;
2588 pSMB->FileName[name_len] = 0;
2589 pSMB->FileName[name_len+1] = 0;
2590 } else { /* BB improve the check for buffer overruns BB */
2591 name_len = strnlen(searchName, PATH_MAX);
2592 name_len++; /* trailing null */
2593 strncpy(pSMB->FileName, searchName, name_len);
2594 }
2595
2596 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2597 pSMB->TotalDataCount = 0;
2598 pSMB->MaxParameterCount = cpu_to_le16(2);
2599 /* BB find exact max data count below from sess structure BB */
2600 pSMB->MaxDataCount = cpu_to_le16(4000);
2601 pSMB->MaxSetupCount = 0;
2602 pSMB->Reserved = 0;
2603 pSMB->Flags = 0;
2604 pSMB->Timeout = 0;
2605 pSMB->Reserved2 = 0;
2606 pSMB->ParameterOffset = cpu_to_le16(
2607 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2608 pSMB->DataCount = 0;
2609 pSMB->DataOffset = 0;
2610 pSMB->SetupCount = 1;
2611 pSMB->Reserved3 = 0;
2612 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2613 byte_count = params + 1 /* pad */ ;
2614 pSMB->TotalParameterCount = cpu_to_le16(params);
2615 pSMB->ParameterCount = pSMB->TotalParameterCount;
2616 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2617 pSMB->Reserved4 = 0;
2618 pSMB->hdr.smb_buf_length += byte_count;
2619 pSMB->ByteCount = cpu_to_le16(byte_count);
2620
2621 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2622 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002623 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 if (rc) {
2625 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2626 } else {
2627 /* decode response */
2628
2629 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2630 if (rc || (pSMBr->ByteCount < 2))
2631 /* BB also check enough total bytes returned */
2632 rc = -EIO; /* bad smb */
2633 else {
2634 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2635 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2636 rc = cifs_copy_posix_acl(acl_inf,
2637 (char *)&pSMBr->hdr.Protocol+data_offset,
2638 buflen,acl_type,count);
2639 }
2640 }
2641 cifs_buf_release(pSMB);
2642 if (rc == -EAGAIN)
2643 goto queryAclRetry;
2644 return rc;
2645}
2646
2647int
2648CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2649 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002650 const char *local_acl, const int buflen,
2651 const int acl_type,
2652 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653{
2654 struct smb_com_transaction2_spi_req *pSMB = NULL;
2655 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2656 char *parm_data;
2657 int name_len;
2658 int rc = 0;
2659 int bytes_returned = 0;
2660 __u16 params, byte_count, data_count, param_offset, offset;
2661
2662 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2663setAclRetry:
2664 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2665 (void **) &pSMBr);
2666 if (rc)
2667 return rc;
2668 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2669 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002670 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002671 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 name_len++; /* trailing null */
2673 name_len *= 2;
2674 } else { /* BB improve the check for buffer overruns BB */
2675 name_len = strnlen(fileName, PATH_MAX);
2676 name_len++; /* trailing null */
2677 strncpy(pSMB->FileName, fileName, name_len);
2678 }
2679 params = 6 + name_len;
2680 pSMB->MaxParameterCount = cpu_to_le16(2);
2681 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2682 pSMB->MaxSetupCount = 0;
2683 pSMB->Reserved = 0;
2684 pSMB->Flags = 0;
2685 pSMB->Timeout = 0;
2686 pSMB->Reserved2 = 0;
2687 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2688 InformationLevel) - 4;
2689 offset = param_offset + params;
2690 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2691 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2692
2693 /* convert to on the wire format for POSIX ACL */
2694 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2695
2696 if(data_count == 0) {
2697 rc = -EOPNOTSUPP;
2698 goto setACLerrorExit;
2699 }
2700 pSMB->DataOffset = cpu_to_le16(offset);
2701 pSMB->SetupCount = 1;
2702 pSMB->Reserved3 = 0;
2703 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2704 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2705 byte_count = 3 /* pad */ + params + data_count;
2706 pSMB->DataCount = cpu_to_le16(data_count);
2707 pSMB->TotalDataCount = pSMB->DataCount;
2708 pSMB->ParameterCount = cpu_to_le16(params);
2709 pSMB->TotalParameterCount = pSMB->ParameterCount;
2710 pSMB->Reserved4 = 0;
2711 pSMB->hdr.smb_buf_length += byte_count;
2712 pSMB->ByteCount = cpu_to_le16(byte_count);
2713 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2714 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2715 if (rc) {
2716 cFYI(1, ("Set POSIX ACL returned %d", rc));
2717 }
2718
2719setACLerrorExit:
2720 cifs_buf_release(pSMB);
2721 if (rc == -EAGAIN)
2722 goto setAclRetry;
2723 return rc;
2724}
2725
Steve Frenchf654bac2005-04-28 22:41:04 -07002726/* BB fix tabs in this function FIXME BB */
2727int
2728CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2729 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2730{
2731 int rc = 0;
2732 struct smb_t2_qfi_req *pSMB = NULL;
2733 struct smb_t2_qfi_rsp *pSMBr = NULL;
2734 int bytes_returned;
2735 __u16 params, byte_count;
2736
2737 cFYI(1,("In GetExtAttr"));
2738 if(tcon == NULL)
2739 return -ENODEV;
2740
2741GetExtAttrRetry:
2742 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2743 (void **) &pSMBr);
2744 if (rc)
2745 return rc;
2746
Steve Frenchc67593a2005-04-28 22:41:04 -07002747 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002748 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002749 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002750 /* BB find exact max data count below from sess structure BB */
2751 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2752 pSMB->t2.MaxSetupCount = 0;
2753 pSMB->t2.Reserved = 0;
2754 pSMB->t2.Flags = 0;
2755 pSMB->t2.Timeout = 0;
2756 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002757 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2758 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002759 pSMB->t2.DataCount = 0;
2760 pSMB->t2.DataOffset = 0;
2761 pSMB->t2.SetupCount = 1;
2762 pSMB->t2.Reserved3 = 0;
2763 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002764 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002765 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2766 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2767 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002768 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002769 pSMB->Fid = netfid;
2770 pSMB->hdr.smb_buf_length += byte_count;
2771 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2772
2773 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2774 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2775 if (rc) {
2776 cFYI(1, ("error %d in GetExtAttr", rc));
2777 } else {
2778 /* decode response */
2779 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2780 if (rc || (pSMBr->ByteCount < 2))
2781 /* BB also check enough total bytes returned */
2782 /* If rc should we check for EOPNOSUPP and
2783 disable the srvino flag? or in caller? */
2784 rc = -EIO; /* bad smb */
2785 else {
2786 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2787 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2788 struct file_chattr_info * pfinfo;
2789 /* BB Do we need a cast or hash here ? */
2790 if(count != 16) {
2791 cFYI(1, ("Illegal size ret in GetExtAttr"));
2792 rc = -EIO;
2793 goto GetExtAttrOut;
2794 }
2795 pfinfo = (struct file_chattr_info *)
2796 (data_offset + (char *) &pSMBr->hdr.Protocol);
2797 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2798 *pMask = le64_to_cpu(pfinfo->mask);
2799 }
2800 }
2801GetExtAttrOut:
2802 cifs_buf_release(pSMB);
2803 if (rc == -EAGAIN)
2804 goto GetExtAttrRetry;
2805 return rc;
2806}
2807
2808
2809#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810
Steve Frencheeac8042006-01-13 21:34:58 -08002811
2812/* security id for everyone */
Steve French2cd646a2006-09-28 19:43:08 +00002813const static struct cifs_sid sid_everyone =
2814 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002815/* group users */
Steve French2cd646a2006-09-28 19:43:08 +00002816const static struct cifs_sid sid_user =
2817 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002818
Steve French0a4b92c2006-01-12 15:44:21 -08002819/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002820static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002821{
Steve French0a4b92c2006-01-12 15:44:21 -08002822 return 0;
2823}
2824
2825/* Get Security Descriptor (by handle) from remote server for a file or dir */
2826int
2827CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2828 /* BB fix up return info */ char *acl_inf, const int buflen,
2829 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2830{
2831 int rc = 0;
2832 int buf_type = 0;
2833 QUERY_SEC_DESC_REQ * pSMB;
2834 struct kvec iov[1];
2835
2836 cFYI(1, ("GetCifsACL"));
2837
2838 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2839 8 /* parm len */, tcon, (void **) &pSMB);
2840 if (rc)
2841 return rc;
2842
2843 pSMB->MaxParameterCount = cpu_to_le32(4);
2844 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2845 pSMB->MaxSetupCount = 0;
2846 pSMB->Fid = fid; /* file handle always le */
2847 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2848 CIFS_ACL_DACL);
2849 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2850 pSMB->hdr.smb_buf_length += 11;
2851 iov[0].iov_base = (char *)pSMB;
2852 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2853
2854 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2855 cifs_stats_inc(&tcon->num_acl_get);
2856 if (rc) {
2857 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2858 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002859 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002860 __le32 * parm;
2861 int parm_len;
2862 int data_len;
2863 int acl_len;
2864 struct smb_com_ntransact_rsp * pSMBr;
2865
2866/* validate_nttransact */
2867 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2868 (char **)&psec_desc,
2869 &parm_len, &data_len);
2870
2871 if(rc)
2872 goto qsec_out;
2873 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2874
2875 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2876
2877 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2878 rc = -EIO; /* bad smb */
2879 goto qsec_out;
2880 }
2881
2882/* BB check that data area is minimum length and as big as acl_len */
2883
2884 acl_len = le32_to_cpu(*(__le32 *)parm);
2885 /* BB check if(acl_len > bufsize) */
2886
2887 parse_sec_desc(psec_desc, acl_len);
2888 }
2889qsec_out:
2890 if(buf_type == CIFS_SMALL_BUFFER)
2891 cifs_small_buf_release(iov[0].iov_base);
2892 else if(buf_type == CIFS_LARGE_BUFFER)
2893 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002894/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002895 return rc;
2896}
2897
Steve French6b8edfe2005-08-23 20:26:03 -07002898/* Legacy Query Path Information call for lookup to old servers such
2899 as Win9x/WinME */
2900int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2901 const unsigned char *searchName,
2902 FILE_ALL_INFO * pFinfo,
2903 const struct nls_table *nls_codepage, int remap)
2904{
2905 QUERY_INFORMATION_REQ * pSMB;
2906 QUERY_INFORMATION_RSP * pSMBr;
2907 int rc = 0;
2908 int bytes_returned;
2909 int name_len;
2910
2911 cFYI(1, ("In SMBQPath path %s", searchName));
2912QInfRetry:
2913 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2914 (void **) &pSMBr);
2915 if (rc)
2916 return rc;
2917
2918 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2919 name_len =
2920 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2921 PATH_MAX, nls_codepage, remap);
2922 name_len++; /* trailing null */
2923 name_len *= 2;
2924 } else {
2925 name_len = strnlen(searchName, PATH_MAX);
2926 name_len++; /* trailing null */
2927 strncpy(pSMB->FileName, searchName, name_len);
2928 }
2929 pSMB->BufferFormat = 0x04;
2930 name_len++; /* account for buffer type byte */
2931 pSMB->hdr.smb_buf_length += (__u16) name_len;
2932 pSMB->ByteCount = cpu_to_le16(name_len);
2933
2934 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2935 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2936 if (rc) {
2937 cFYI(1, ("Send error in QueryInfo = %d", rc));
2938 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00002939 struct timespec ts;
2940 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2941 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07002942 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00002943 ts.tv_nsec = 0;
2944 ts.tv_sec = time;
2945 /* decode time fields */
2946 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2947 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2948 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07002949 pFinfo->AllocationSize =
2950 cpu_to_le64(le32_to_cpu(pSMBr->size));
2951 pFinfo->EndOfFile = pFinfo->AllocationSize;
2952 pFinfo->Attributes =
2953 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002954 } else
2955 rc = -EIO; /* bad buffer passed in */
2956
2957 cifs_buf_release(pSMB);
2958
2959 if (rc == -EAGAIN)
2960 goto QInfRetry;
2961
2962 return rc;
2963}
2964
2965
2966
2967
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968int
2969CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2970 const unsigned char *searchName,
2971 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00002972 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07002973 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974{
2975/* level 263 SMB_QUERY_FILE_ALL_INFO */
2976 TRANSACTION2_QPI_REQ *pSMB = NULL;
2977 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2978 int rc = 0;
2979 int bytes_returned;
2980 int name_len;
2981 __u16 params, byte_count;
2982
2983/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2984QPathInfoRetry:
2985 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2986 (void **) &pSMBr);
2987 if (rc)
2988 return rc;
2989
2990 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2991 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002992 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002993 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 name_len++; /* trailing null */
2995 name_len *= 2;
2996 } else { /* BB improve the check for buffer overruns BB */
2997 name_len = strnlen(searchName, PATH_MAX);
2998 name_len++; /* trailing null */
2999 strncpy(pSMB->FileName, searchName, name_len);
3000 }
3001
3002 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3003 pSMB->TotalDataCount = 0;
3004 pSMB->MaxParameterCount = cpu_to_le16(2);
3005 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3006 pSMB->MaxSetupCount = 0;
3007 pSMB->Reserved = 0;
3008 pSMB->Flags = 0;
3009 pSMB->Timeout = 0;
3010 pSMB->Reserved2 = 0;
3011 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3012 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3013 pSMB->DataCount = 0;
3014 pSMB->DataOffset = 0;
3015 pSMB->SetupCount = 1;
3016 pSMB->Reserved3 = 0;
3017 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3018 byte_count = params + 1 /* pad */ ;
3019 pSMB->TotalParameterCount = cpu_to_le16(params);
3020 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003021 if(legacy)
3022 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3023 else
3024 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 pSMB->Reserved4 = 0;
3026 pSMB->hdr.smb_buf_length += byte_count;
3027 pSMB->ByteCount = cpu_to_le16(byte_count);
3028
3029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3031 if (rc) {
3032 cFYI(1, ("Send error in QPathInfo = %d", rc));
3033 } else { /* decode response */
3034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3035
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003036 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3037 rc = -EIO;
3038 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 rc = -EIO; /* bad smb */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003040 else if(legacy && (pSMBr->ByteCount < 24))
3041 rc = -EIO; /* 24 or 26 expected but we do not read last field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 else if (pFindData){
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003043 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003045 if(legacy) /* we do not read the last field, EAsize, fortunately
3046 since it varies by subdialect and on Set vs. Get, is
3047 two bytes or 4 bytes depending but we don't care here */
3048 size = sizeof(FILE_INFO_STANDARD);
3049 else
3050 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 memcpy((char *) pFindData,
3052 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003053 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 } else
3055 rc = -ENOMEM;
3056 }
3057 cifs_buf_release(pSMB);
3058 if (rc == -EAGAIN)
3059 goto QPathInfoRetry;
3060
3061 return rc;
3062}
3063
3064int
3065CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3066 const unsigned char *searchName,
3067 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003068 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069{
3070/* SMB_QUERY_FILE_UNIX_BASIC */
3071 TRANSACTION2_QPI_REQ *pSMB = NULL;
3072 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3073 int rc = 0;
3074 int bytes_returned = 0;
3075 int name_len;
3076 __u16 params, byte_count;
3077
3078 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3079UnixQPathInfoRetry:
3080 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3081 (void **) &pSMBr);
3082 if (rc)
3083 return rc;
3084
3085 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3086 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003087 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003088 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 name_len++; /* trailing null */
3090 name_len *= 2;
3091 } else { /* BB improve the check for buffer overruns BB */
3092 name_len = strnlen(searchName, PATH_MAX);
3093 name_len++; /* trailing null */
3094 strncpy(pSMB->FileName, searchName, name_len);
3095 }
3096
3097 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3098 pSMB->TotalDataCount = 0;
3099 pSMB->MaxParameterCount = cpu_to_le16(2);
3100 /* BB find exact max SMB PDU from sess structure BB */
3101 pSMB->MaxDataCount = cpu_to_le16(4000);
3102 pSMB->MaxSetupCount = 0;
3103 pSMB->Reserved = 0;
3104 pSMB->Flags = 0;
3105 pSMB->Timeout = 0;
3106 pSMB->Reserved2 = 0;
3107 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3108 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3109 pSMB->DataCount = 0;
3110 pSMB->DataOffset = 0;
3111 pSMB->SetupCount = 1;
3112 pSMB->Reserved3 = 0;
3113 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3114 byte_count = params + 1 /* pad */ ;
3115 pSMB->TotalParameterCount = cpu_to_le16(params);
3116 pSMB->ParameterCount = pSMB->TotalParameterCount;
3117 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3118 pSMB->Reserved4 = 0;
3119 pSMB->hdr.smb_buf_length += byte_count;
3120 pSMB->ByteCount = cpu_to_le16(byte_count);
3121
3122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3124 if (rc) {
3125 cFYI(1, ("Send error in QPathInfo = %d", rc));
3126 } else { /* decode response */
3127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3128
3129 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3130 rc = -EIO; /* bad smb */
3131 } else {
3132 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3133 memcpy((char *) pFindData,
3134 (char *) &pSMBr->hdr.Protocol +
3135 data_offset,
3136 sizeof (FILE_UNIX_BASIC_INFO));
3137 }
3138 }
3139 cifs_buf_release(pSMB);
3140 if (rc == -EAGAIN)
3141 goto UnixQPathInfoRetry;
3142
3143 return rc;
3144}
3145
3146#if 0 /* function unused at present */
3147int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3148 const char *searchName, FILE_ALL_INFO * findData,
3149 const struct nls_table *nls_codepage)
3150{
3151/* level 257 SMB_ */
3152 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3153 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3154 int rc = 0;
3155 int bytes_returned;
3156 int name_len;
3157 __u16 params, byte_count;
3158
3159 cFYI(1, ("In FindUnique"));
3160findUniqueRetry:
3161 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3162 (void **) &pSMBr);
3163 if (rc)
3164 return rc;
3165
3166 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3167 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003168 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 /* find define for this maxpathcomponent */
3170 , nls_codepage);
3171 name_len++; /* trailing null */
3172 name_len *= 2;
3173 } else { /* BB improve the check for buffer overruns BB */
3174 name_len = strnlen(searchName, PATH_MAX);
3175 name_len++; /* trailing null */
3176 strncpy(pSMB->FileName, searchName, name_len);
3177 }
3178
3179 params = 12 + name_len /* includes null */ ;
3180 pSMB->TotalDataCount = 0; /* no EAs */
3181 pSMB->MaxParameterCount = cpu_to_le16(2);
3182 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3183 pSMB->MaxSetupCount = 0;
3184 pSMB->Reserved = 0;
3185 pSMB->Flags = 0;
3186 pSMB->Timeout = 0;
3187 pSMB->Reserved2 = 0;
3188 pSMB->ParameterOffset = cpu_to_le16(
3189 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3190 pSMB->DataCount = 0;
3191 pSMB->DataOffset = 0;
3192 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3193 pSMB->Reserved3 = 0;
3194 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3195 byte_count = params + 1 /* pad */ ;
3196 pSMB->TotalParameterCount = cpu_to_le16(params);
3197 pSMB->ParameterCount = pSMB->TotalParameterCount;
3198 pSMB->SearchAttributes =
3199 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3200 ATTR_DIRECTORY);
3201 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3202 pSMB->SearchFlags = cpu_to_le16(1);
3203 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3204 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3205 pSMB->hdr.smb_buf_length += byte_count;
3206 pSMB->ByteCount = cpu_to_le16(byte_count);
3207
3208 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3209 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3210
3211 if (rc) {
3212 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3213 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003214 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 /* BB fill in */
3216 }
3217
3218 cifs_buf_release(pSMB);
3219 if (rc == -EAGAIN)
3220 goto findUniqueRetry;
3221
3222 return rc;
3223}
3224#endif /* end unused (temporarily) function */
3225
3226/* xid, tcon, searchName and codepage are input parms, rest are returned */
3227int
3228CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3229 const char *searchName,
3230 const struct nls_table *nls_codepage,
3231 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003232 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
3234/* level 257 SMB_ */
3235 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3236 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3237 T2_FFIRST_RSP_PARMS * parms;
3238 int rc = 0;
3239 int bytes_returned = 0;
3240 int name_len;
3241 __u16 params, byte_count;
3242
Steve French737b7582005-04-28 22:41:06 -07003243 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244
3245findFirstRetry:
3246 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3247 (void **) &pSMBr);
3248 if (rc)
3249 return rc;
3250
3251 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3252 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003253 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003254 PATH_MAX, nls_codepage, remap);
3255 /* We can not add the asterik earlier in case
3256 it got remapped to 0xF03A as if it were part of the
3257 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003259 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003260 pSMB->FileName[name_len+1] = 0;
3261 pSMB->FileName[name_len+2] = '*';
3262 pSMB->FileName[name_len+3] = 0;
3263 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3265 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003266 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 } else { /* BB add check for overrun of SMB buf BB */
3268 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269/* BB fix here and in unicode clause above ie
3270 if(name_len > buffersize-header)
3271 free buffer exit; BB */
3272 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003273 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003274 pSMB->FileName[name_len+1] = '*';
3275 pSMB->FileName[name_len+2] = 0;
3276 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 }
3278
3279 params = 12 + name_len /* includes null */ ;
3280 pSMB->TotalDataCount = 0; /* no EAs */
3281 pSMB->MaxParameterCount = cpu_to_le16(10);
3282 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3283 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3284 pSMB->MaxSetupCount = 0;
3285 pSMB->Reserved = 0;
3286 pSMB->Flags = 0;
3287 pSMB->Timeout = 0;
3288 pSMB->Reserved2 = 0;
3289 byte_count = params + 1 /* pad */ ;
3290 pSMB->TotalParameterCount = cpu_to_le16(params);
3291 pSMB->ParameterCount = pSMB->TotalParameterCount;
3292 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003293 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3294 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 pSMB->DataCount = 0;
3296 pSMB->DataOffset = 0;
3297 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3298 pSMB->Reserved3 = 0;
3299 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3300 pSMB->SearchAttributes =
3301 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3302 ATTR_DIRECTORY);
3303 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3304 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3305 CIFS_SEARCH_RETURN_RESUME);
3306 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3307
3308 /* BB what should we set StorageType to? Does it matter? BB */
3309 pSMB->SearchStorageType = 0;
3310 pSMB->hdr.smb_buf_length += byte_count;
3311 pSMB->ByteCount = cpu_to_le16(byte_count);
3312
3313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3314 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003315 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
Steve French88274812006-03-09 22:21:45 +00003317 if (rc) {/* BB add logic to retry regular search if Unix search
3318 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 /* BB Add code to handle unsupported level rc */
3320 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003321
Steve French88274812006-03-09 22:21:45 +00003322 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323
3324 /* BB eventually could optimize out free and realloc of buf */
3325 /* for this case */
3326 if (rc == -EAGAIN)
3327 goto findFirstRetry;
3328 } else { /* decode response */
3329 /* BB remember to free buffer if error BB */
3330 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3331 if(rc == 0) {
3332 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3333 psrch_inf->unicode = TRUE;
3334 else
3335 psrch_inf->unicode = FALSE;
3336
3337 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003338 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 psrch_inf->srch_entries_start =
3340 (char *) &pSMBr->hdr.Protocol +
3341 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3343 le16_to_cpu(pSMBr->t2.ParameterOffset));
3344
3345 if(parms->EndofSearch)
3346 psrch_inf->endOfSearch = TRUE;
3347 else
3348 psrch_inf->endOfSearch = FALSE;
3349
3350 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003351 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 *pnetfid = parms->SearchHandle;
3354 } else {
3355 cifs_buf_release(pSMB);
3356 }
3357 }
3358
3359 return rc;
3360}
3361
3362int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3363 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3364{
3365 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3366 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3367 T2_FNEXT_RSP_PARMS * parms;
3368 char *response_data;
3369 int rc = 0;
3370 int bytes_returned, name_len;
3371 __u16 params, byte_count;
3372
3373 cFYI(1, ("In FindNext"));
3374
3375 if(psrch_inf->endOfSearch == TRUE)
3376 return -ENOENT;
3377
3378 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3379 (void **) &pSMBr);
3380 if (rc)
3381 return rc;
3382
3383 params = 14; /* includes 2 bytes of null string, converted to LE below */
3384 byte_count = 0;
3385 pSMB->TotalDataCount = 0; /* no EAs */
3386 pSMB->MaxParameterCount = cpu_to_le16(8);
3387 pSMB->MaxDataCount =
3388 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3389 pSMB->MaxSetupCount = 0;
3390 pSMB->Reserved = 0;
3391 pSMB->Flags = 0;
3392 pSMB->Timeout = 0;
3393 pSMB->Reserved2 = 0;
3394 pSMB->ParameterOffset = cpu_to_le16(
3395 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3396 pSMB->DataCount = 0;
3397 pSMB->DataOffset = 0;
3398 pSMB->SetupCount = 1;
3399 pSMB->Reserved3 = 0;
3400 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3401 pSMB->SearchHandle = searchHandle; /* always kept as le */
3402 pSMB->SearchCount =
3403 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3404 /* test for Unix extensions */
3405/* if (tcon->ses->capabilities & CAP_UNIX) {
3406 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3407 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3408 } else {
3409 pSMB->InformationLevel =
3410 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3411 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3412 } */
3413 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3414 pSMB->ResumeKey = psrch_inf->resume_key;
3415 pSMB->SearchFlags =
3416 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3417
3418 name_len = psrch_inf->resume_name_len;
3419 params += name_len;
3420 if(name_len < PATH_MAX) {
3421 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3422 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003423 /* 14 byte parm len above enough for 2 byte null terminator */
3424 pSMB->ResumeFileName[name_len] = 0;
3425 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 } else {
3427 rc = -EINVAL;
3428 goto FNext2_err_exit;
3429 }
3430 byte_count = params + 1 /* pad */ ;
3431 pSMB->TotalParameterCount = cpu_to_le16(params);
3432 pSMB->ParameterCount = pSMB->TotalParameterCount;
3433 pSMB->hdr.smb_buf_length += byte_count;
3434 pSMB->ByteCount = cpu_to_le16(byte_count);
3435
3436 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3437 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003438 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 if (rc) {
3440 if (rc == -EBADF) {
3441 psrch_inf->endOfSearch = TRUE;
3442 rc = 0; /* search probably was closed at end of search above */
3443 } else
3444 cFYI(1, ("FindNext returned = %d", rc));
3445 } else { /* decode response */
3446 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3447
3448 if(rc == 0) {
3449 /* BB fixme add lock for file (srch_info) struct here */
3450 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3451 psrch_inf->unicode = TRUE;
3452 else
3453 psrch_inf->unicode = FALSE;
3454 response_data = (char *) &pSMBr->hdr.Protocol +
3455 le16_to_cpu(pSMBr->t2.ParameterOffset);
3456 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3457 response_data = (char *)&pSMBr->hdr.Protocol +
3458 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003459 if(psrch_inf->smallBuf)
3460 cifs_small_buf_release(
3461 psrch_inf->ntwrk_buf_start);
3462 else
3463 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 psrch_inf->srch_entries_start = response_data;
3465 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003466 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 if(parms->EndofSearch)
3468 psrch_inf->endOfSearch = TRUE;
3469 else
3470 psrch_inf->endOfSearch = FALSE;
3471
3472 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3473 psrch_inf->index_of_last_entry +=
3474 psrch_inf->entries_in_buffer;
3475/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3476
3477 /* BB fixme add unlock here */
3478 }
3479
3480 }
3481
3482 /* BB On error, should we leave previous search buf (and count and
3483 last entry fields) intact or free the previous one? */
3484
3485 /* Note: On -EAGAIN error only caller can retry on handle based calls
3486 since file handle passed in no longer valid */
3487FNext2_err_exit:
3488 if (rc != 0)
3489 cifs_buf_release(pSMB);
3490
3491 return rc;
3492}
3493
3494int
3495CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3496{
3497 int rc = 0;
3498 FINDCLOSE_REQ *pSMB = NULL;
3499 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3500 int bytes_returned;
3501
3502 cFYI(1, ("In CIFSSMBFindClose"));
3503 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3504
3505 /* no sense returning error if session restarted
3506 as file handle has been closed */
3507 if(rc == -EAGAIN)
3508 return 0;
3509 if (rc)
3510 return rc;
3511
3512 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3513 pSMB->FileID = searchHandle;
3514 pSMB->ByteCount = 0;
3515 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3516 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3517 if (rc) {
3518 cERROR(1, ("Send error in FindClose = %d", rc));
3519 }
Steve Frencha4544342005-08-24 13:59:35 -07003520 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 cifs_small_buf_release(pSMB);
3522
3523 /* Since session is dead, search handle closed on server already */
3524 if (rc == -EAGAIN)
3525 rc = 0;
3526
3527 return rc;
3528}
3529
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530int
3531CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3532 const unsigned char *searchName,
3533 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003534 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535{
3536 int rc = 0;
3537 TRANSACTION2_QPI_REQ *pSMB = NULL;
3538 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3539 int name_len, bytes_returned;
3540 __u16 params, byte_count;
3541
3542 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3543 if(tcon == NULL)
3544 return -ENODEV;
3545
3546GetInodeNumberRetry:
3547 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3548 (void **) &pSMBr);
3549 if (rc)
3550 return rc;
3551
3552
3553 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3554 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003555 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003556 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 name_len++; /* trailing null */
3558 name_len *= 2;
3559 } else { /* BB improve the check for buffer overruns BB */
3560 name_len = strnlen(searchName, PATH_MAX);
3561 name_len++; /* trailing null */
3562 strncpy(pSMB->FileName, searchName, name_len);
3563 }
3564
3565 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3566 pSMB->TotalDataCount = 0;
3567 pSMB->MaxParameterCount = cpu_to_le16(2);
3568 /* BB find exact max data count below from sess structure BB */
3569 pSMB->MaxDataCount = cpu_to_le16(4000);
3570 pSMB->MaxSetupCount = 0;
3571 pSMB->Reserved = 0;
3572 pSMB->Flags = 0;
3573 pSMB->Timeout = 0;
3574 pSMB->Reserved2 = 0;
3575 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3576 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3577 pSMB->DataCount = 0;
3578 pSMB->DataOffset = 0;
3579 pSMB->SetupCount = 1;
3580 pSMB->Reserved3 = 0;
3581 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3582 byte_count = params + 1 /* pad */ ;
3583 pSMB->TotalParameterCount = cpu_to_le16(params);
3584 pSMB->ParameterCount = pSMB->TotalParameterCount;
3585 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3586 pSMB->Reserved4 = 0;
3587 pSMB->hdr.smb_buf_length += byte_count;
3588 pSMB->ByteCount = cpu_to_le16(byte_count);
3589
3590 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3591 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3592 if (rc) {
3593 cFYI(1, ("error %d in QueryInternalInfo", rc));
3594 } else {
3595 /* decode response */
3596 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3597 if (rc || (pSMBr->ByteCount < 2))
3598 /* BB also check enough total bytes returned */
3599 /* If rc should we check for EOPNOSUPP and
3600 disable the srvino flag? or in caller? */
3601 rc = -EIO; /* bad smb */
3602 else {
3603 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3604 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3605 struct file_internal_info * pfinfo;
3606 /* BB Do we need a cast or hash here ? */
3607 if(count < 8) {
3608 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3609 rc = -EIO;
3610 goto GetInodeNumOut;
3611 }
3612 pfinfo = (struct file_internal_info *)
3613 (data_offset + (char *) &pSMBr->hdr.Protocol);
3614 *inode_number = pfinfo->UniqueId;
3615 }
3616 }
3617GetInodeNumOut:
3618 cifs_buf_release(pSMB);
3619 if (rc == -EAGAIN)
3620 goto GetInodeNumberRetry;
3621 return rc;
3622}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623
3624int
3625CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3626 const unsigned char *searchName,
3627 unsigned char **targetUNCs,
3628 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003629 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630{
3631/* TRANS2_GET_DFS_REFERRAL */
3632 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3633 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3634 struct dfs_referral_level_3 * referrals = NULL;
3635 int rc = 0;
3636 int bytes_returned;
3637 int name_len;
3638 unsigned int i;
3639 char * temp;
3640 __u16 params, byte_count;
3641 *number_of_UNC_in_array = 0;
3642 *targetUNCs = NULL;
3643
3644 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3645 if (ses == NULL)
3646 return -ENODEV;
3647getDFSRetry:
3648 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3649 (void **) &pSMBr);
3650 if (rc)
3651 return rc;
Steve French1982c342005-08-17 12:38:22 -07003652
3653 /* server pointer checked in called function,
3654 but should never be null here anyway */
3655 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 pSMB->hdr.Tid = ses->ipc_tid;
3657 pSMB->hdr.Uid = ses->Suid;
3658 if (ses->capabilities & CAP_STATUS32) {
3659 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3660 }
3661 if (ses->capabilities & CAP_DFS) {
3662 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3663 }
3664
3665 if (ses->capabilities & CAP_UNICODE) {
3666 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3667 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003668 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003669 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 name_len++; /* trailing null */
3671 name_len *= 2;
3672 } else { /* BB improve the check for buffer overruns BB */
3673 name_len = strnlen(searchName, PATH_MAX);
3674 name_len++; /* trailing null */
3675 strncpy(pSMB->RequestFileName, searchName, name_len);
3676 }
3677
3678 params = 2 /* level */ + name_len /*includes null */ ;
3679 pSMB->TotalDataCount = 0;
3680 pSMB->DataCount = 0;
3681 pSMB->DataOffset = 0;
3682 pSMB->MaxParameterCount = 0;
3683 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3684 pSMB->MaxSetupCount = 0;
3685 pSMB->Reserved = 0;
3686 pSMB->Flags = 0;
3687 pSMB->Timeout = 0;
3688 pSMB->Reserved2 = 0;
3689 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3690 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3691 pSMB->SetupCount = 1;
3692 pSMB->Reserved3 = 0;
3693 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3694 byte_count = params + 3 /* pad */ ;
3695 pSMB->ParameterCount = cpu_to_le16(params);
3696 pSMB->TotalParameterCount = pSMB->ParameterCount;
3697 pSMB->MaxReferralLevel = cpu_to_le16(3);
3698 pSMB->hdr.smb_buf_length += byte_count;
3699 pSMB->ByteCount = cpu_to_le16(byte_count);
3700
3701 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3703 if (rc) {
3704 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3705 } else { /* decode response */
3706/* BB Add logic to parse referrals here */
3707 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3708
3709 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3710 rc = -EIO; /* bad smb */
3711 else {
3712 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3713 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3714
3715 cFYI(1,
3716 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3717 pSMBr->ByteCount, data_offset));
3718 referrals =
3719 (struct dfs_referral_level_3 *)
3720 (8 /* sizeof start of data block */ +
3721 data_offset +
3722 (char *) &pSMBr->hdr.Protocol);
3723 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",
3724 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)));
3725 /* BB This field is actually two bytes in from start of
3726 data block so we could do safety check that DataBlock
3727 begins at address of pSMBr->NumberOfReferrals */
3728 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3729
3730 /* BB Fix below so can return more than one referral */
3731 if(*number_of_UNC_in_array > 1)
3732 *number_of_UNC_in_array = 1;
3733
3734 /* get the length of the strings describing refs */
3735 name_len = 0;
3736 for(i=0;i<*number_of_UNC_in_array;i++) {
3737 /* make sure that DfsPathOffset not past end */
3738 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3739 if (offset > data_count) {
3740 /* if invalid referral, stop here and do
3741 not try to copy any more */
3742 *number_of_UNC_in_array = i;
3743 break;
3744 }
3745 temp = ((char *)referrals) + offset;
3746
3747 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3748 name_len += UniStrnlen((wchar_t *)temp,data_count);
3749 } else {
3750 name_len += strnlen(temp,data_count);
3751 }
3752 referrals++;
3753 /* BB add check that referral pointer does not fall off end PDU */
3754
3755 }
3756 /* BB add check for name_len bigger than bcc */
3757 *targetUNCs =
3758 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3759 if(*targetUNCs == NULL) {
3760 rc = -ENOMEM;
3761 goto GetDFSRefExit;
3762 }
3763 /* copy the ref strings */
3764 referrals =
3765 (struct dfs_referral_level_3 *)
3766 (8 /* sizeof data hdr */ +
3767 data_offset +
3768 (char *) &pSMBr->hdr.Protocol);
3769
3770 for(i=0;i<*number_of_UNC_in_array;i++) {
3771 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3772 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3773 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003774 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 } else {
3776 strncpy(*targetUNCs,temp,name_len);
3777 }
3778 /* BB update target_uncs pointers */
3779 referrals++;
3780 }
3781 temp = *targetUNCs;
3782 temp[name_len] = 0;
3783 }
3784
3785 }
3786GetDFSRefExit:
3787 if (pSMB)
3788 cifs_buf_release(pSMB);
3789
3790 if (rc == -EAGAIN)
3791 goto getDFSRetry;
3792
3793 return rc;
3794}
3795
Steve French20962432005-09-21 22:05:57 -07003796/* Query File System Info such as free space to old servers such as Win 9x */
3797int
3798SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3799{
3800/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3801 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3802 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3803 FILE_SYSTEM_ALLOC_INFO *response_data;
3804 int rc = 0;
3805 int bytes_returned = 0;
3806 __u16 params, byte_count;
3807
3808 cFYI(1, ("OldQFSInfo"));
3809oldQFSInfoRetry:
3810 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3811 (void **) &pSMBr);
3812 if (rc)
3813 return rc;
3814 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3815 (void **) &pSMBr);
3816 if (rc)
3817 return rc;
3818
3819 params = 2; /* level */
3820 pSMB->TotalDataCount = 0;
3821 pSMB->MaxParameterCount = cpu_to_le16(2);
3822 pSMB->MaxDataCount = cpu_to_le16(1000);
3823 pSMB->MaxSetupCount = 0;
3824 pSMB->Reserved = 0;
3825 pSMB->Flags = 0;
3826 pSMB->Timeout = 0;
3827 pSMB->Reserved2 = 0;
3828 byte_count = params + 1 /* pad */ ;
3829 pSMB->TotalParameterCount = cpu_to_le16(params);
3830 pSMB->ParameterCount = pSMB->TotalParameterCount;
3831 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3832 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3833 pSMB->DataCount = 0;
3834 pSMB->DataOffset = 0;
3835 pSMB->SetupCount = 1;
3836 pSMB->Reserved3 = 0;
3837 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3838 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3839 pSMB->hdr.smb_buf_length += byte_count;
3840 pSMB->ByteCount = cpu_to_le16(byte_count);
3841
3842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3844 if (rc) {
3845 cFYI(1, ("Send error in QFSInfo = %d", rc));
3846 } else { /* decode response */
3847 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3848
3849 if (rc || (pSMBr->ByteCount < 18))
3850 rc = -EIO; /* bad smb */
3851 else {
3852 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3853 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3854 pSMBr->ByteCount, data_offset));
3855
3856 response_data =
3857 (FILE_SYSTEM_ALLOC_INFO *)
3858 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3859 FSData->f_bsize =
3860 le16_to_cpu(response_data->BytesPerSector) *
3861 le32_to_cpu(response_data->
3862 SectorsPerAllocationUnit);
3863 FSData->f_blocks =
3864 le32_to_cpu(response_data->TotalAllocationUnits);
3865 FSData->f_bfree = FSData->f_bavail =
3866 le32_to_cpu(response_data->FreeAllocationUnits);
3867 cFYI(1,
3868 ("Blocks: %lld Free: %lld Block size %ld",
3869 (unsigned long long)FSData->f_blocks,
3870 (unsigned long long)FSData->f_bfree,
3871 FSData->f_bsize));
3872 }
3873 }
3874 cifs_buf_release(pSMB);
3875
3876 if (rc == -EAGAIN)
3877 goto oldQFSInfoRetry;
3878
3879 return rc;
3880}
3881
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882int
Steve French737b7582005-04-28 22:41:06 -07003883CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884{
3885/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3886 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3887 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3888 FILE_SYSTEM_INFO *response_data;
3889 int rc = 0;
3890 int bytes_returned = 0;
3891 __u16 params, byte_count;
3892
3893 cFYI(1, ("In QFSInfo"));
3894QFSInfoRetry:
3895 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3896 (void **) &pSMBr);
3897 if (rc)
3898 return rc;
3899
3900 params = 2; /* level */
3901 pSMB->TotalDataCount = 0;
3902 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003903 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 pSMB->MaxSetupCount = 0;
3905 pSMB->Reserved = 0;
3906 pSMB->Flags = 0;
3907 pSMB->Timeout = 0;
3908 pSMB->Reserved2 = 0;
3909 byte_count = params + 1 /* pad */ ;
3910 pSMB->TotalParameterCount = cpu_to_le16(params);
3911 pSMB->ParameterCount = pSMB->TotalParameterCount;
3912 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3913 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3914 pSMB->DataCount = 0;
3915 pSMB->DataOffset = 0;
3916 pSMB->SetupCount = 1;
3917 pSMB->Reserved3 = 0;
3918 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3919 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3920 pSMB->hdr.smb_buf_length += byte_count;
3921 pSMB->ByteCount = cpu_to_le16(byte_count);
3922
3923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3925 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003926 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 } else { /* decode response */
3928 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3929
Steve French20962432005-09-21 22:05:57 -07003930 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 rc = -EIO; /* bad smb */
3932 else {
3933 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
3935 response_data =
3936 (FILE_SYSTEM_INFO
3937 *) (((char *) &pSMBr->hdr.Protocol) +
3938 data_offset);
3939 FSData->f_bsize =
3940 le32_to_cpu(response_data->BytesPerSector) *
3941 le32_to_cpu(response_data->
3942 SectorsPerAllocationUnit);
3943 FSData->f_blocks =
3944 le64_to_cpu(response_data->TotalAllocationUnits);
3945 FSData->f_bfree = FSData->f_bavail =
3946 le64_to_cpu(response_data->FreeAllocationUnits);
3947 cFYI(1,
3948 ("Blocks: %lld Free: %lld Block size %ld",
3949 (unsigned long long)FSData->f_blocks,
3950 (unsigned long long)FSData->f_bfree,
3951 FSData->f_bsize));
3952 }
3953 }
3954 cifs_buf_release(pSMB);
3955
3956 if (rc == -EAGAIN)
3957 goto QFSInfoRetry;
3958
3959 return rc;
3960}
3961
3962int
Steve French737b7582005-04-28 22:41:06 -07003963CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964{
3965/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3966 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3967 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3968 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3969 int rc = 0;
3970 int bytes_returned = 0;
3971 __u16 params, byte_count;
3972
3973 cFYI(1, ("In QFSAttributeInfo"));
3974QFSAttributeRetry:
3975 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3976 (void **) &pSMBr);
3977 if (rc)
3978 return rc;
3979
3980 params = 2; /* level */
3981 pSMB->TotalDataCount = 0;
3982 pSMB->MaxParameterCount = cpu_to_le16(2);
3983 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3984 pSMB->MaxSetupCount = 0;
3985 pSMB->Reserved = 0;
3986 pSMB->Flags = 0;
3987 pSMB->Timeout = 0;
3988 pSMB->Reserved2 = 0;
3989 byte_count = params + 1 /* pad */ ;
3990 pSMB->TotalParameterCount = cpu_to_le16(params);
3991 pSMB->ParameterCount = pSMB->TotalParameterCount;
3992 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3993 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3994 pSMB->DataCount = 0;
3995 pSMB->DataOffset = 0;
3996 pSMB->SetupCount = 1;
3997 pSMB->Reserved3 = 0;
3998 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3999 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4000 pSMB->hdr.smb_buf_length += byte_count;
4001 pSMB->ByteCount = cpu_to_le16(byte_count);
4002
4003 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4005 if (rc) {
4006 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4007 } else { /* decode response */
4008 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4009
4010 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4011 rc = -EIO; /* bad smb */
4012 } else {
4013 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4014 response_data =
4015 (FILE_SYSTEM_ATTRIBUTE_INFO
4016 *) (((char *) &pSMBr->hdr.Protocol) +
4017 data_offset);
4018 memcpy(&tcon->fsAttrInfo, response_data,
4019 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4020 }
4021 }
4022 cifs_buf_release(pSMB);
4023
4024 if (rc == -EAGAIN)
4025 goto QFSAttributeRetry;
4026
4027 return rc;
4028}
4029
4030int
Steve French737b7582005-04-28 22:41:06 -07004031CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032{
4033/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4034 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4035 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4036 FILE_SYSTEM_DEVICE_INFO *response_data;
4037 int rc = 0;
4038 int bytes_returned = 0;
4039 __u16 params, byte_count;
4040
4041 cFYI(1, ("In QFSDeviceInfo"));
4042QFSDeviceRetry:
4043 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4044 (void **) &pSMBr);
4045 if (rc)
4046 return rc;
4047
4048 params = 2; /* level */
4049 pSMB->TotalDataCount = 0;
4050 pSMB->MaxParameterCount = cpu_to_le16(2);
4051 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4052 pSMB->MaxSetupCount = 0;
4053 pSMB->Reserved = 0;
4054 pSMB->Flags = 0;
4055 pSMB->Timeout = 0;
4056 pSMB->Reserved2 = 0;
4057 byte_count = params + 1 /* pad */ ;
4058 pSMB->TotalParameterCount = cpu_to_le16(params);
4059 pSMB->ParameterCount = pSMB->TotalParameterCount;
4060 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4061 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4062
4063 pSMB->DataCount = 0;
4064 pSMB->DataOffset = 0;
4065 pSMB->SetupCount = 1;
4066 pSMB->Reserved3 = 0;
4067 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4068 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4069 pSMB->hdr.smb_buf_length += byte_count;
4070 pSMB->ByteCount = cpu_to_le16(byte_count);
4071
4072 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4074 if (rc) {
4075 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4076 } else { /* decode response */
4077 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4078
4079 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4080 rc = -EIO; /* bad smb */
4081 else {
4082 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4083 response_data =
Steve French737b7582005-04-28 22:41:06 -07004084 (FILE_SYSTEM_DEVICE_INFO *)
4085 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 data_offset);
4087 memcpy(&tcon->fsDevInfo, response_data,
4088 sizeof (FILE_SYSTEM_DEVICE_INFO));
4089 }
4090 }
4091 cifs_buf_release(pSMB);
4092
4093 if (rc == -EAGAIN)
4094 goto QFSDeviceRetry;
4095
4096 return rc;
4097}
4098
4099int
Steve French737b7582005-04-28 22:41:06 -07004100CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101{
4102/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4103 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4104 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4105 FILE_SYSTEM_UNIX_INFO *response_data;
4106 int rc = 0;
4107 int bytes_returned = 0;
4108 __u16 params, byte_count;
4109
4110 cFYI(1, ("In QFSUnixInfo"));
4111QFSUnixRetry:
4112 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4113 (void **) &pSMBr);
4114 if (rc)
4115 return rc;
4116
4117 params = 2; /* level */
4118 pSMB->TotalDataCount = 0;
4119 pSMB->DataCount = 0;
4120 pSMB->DataOffset = 0;
4121 pSMB->MaxParameterCount = cpu_to_le16(2);
4122 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4123 pSMB->MaxSetupCount = 0;
4124 pSMB->Reserved = 0;
4125 pSMB->Flags = 0;
4126 pSMB->Timeout = 0;
4127 pSMB->Reserved2 = 0;
4128 byte_count = params + 1 /* pad */ ;
4129 pSMB->ParameterCount = cpu_to_le16(params);
4130 pSMB->TotalParameterCount = pSMB->ParameterCount;
4131 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4132 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4133 pSMB->SetupCount = 1;
4134 pSMB->Reserved3 = 0;
4135 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4136 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4137 pSMB->hdr.smb_buf_length += byte_count;
4138 pSMB->ByteCount = cpu_to_le16(byte_count);
4139
4140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4141 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4142 if (rc) {
4143 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4144 } else { /* decode response */
4145 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4146
4147 if (rc || (pSMBr->ByteCount < 13)) {
4148 rc = -EIO; /* bad smb */
4149 } else {
4150 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4151 response_data =
4152 (FILE_SYSTEM_UNIX_INFO
4153 *) (((char *) &pSMBr->hdr.Protocol) +
4154 data_offset);
4155 memcpy(&tcon->fsUnixInfo, response_data,
4156 sizeof (FILE_SYSTEM_UNIX_INFO));
4157 }
4158 }
4159 cifs_buf_release(pSMB);
4160
4161 if (rc == -EAGAIN)
4162 goto QFSUnixRetry;
4163
4164
4165 return rc;
4166}
4167
Jeremy Allisonac670552005-06-22 17:26:35 -07004168int
Steve French45abc6e2005-06-23 13:42:03 -05004169CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004170{
4171/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4172 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4173 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4174 int rc = 0;
4175 int bytes_returned = 0;
4176 __u16 params, param_offset, offset, byte_count;
4177
4178 cFYI(1, ("In SETFSUnixInfo"));
4179SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004180 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004181 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4182 (void **) &pSMBr);
4183 if (rc)
4184 return rc;
4185
4186 params = 4; /* 2 bytes zero followed by info level. */
4187 pSMB->MaxSetupCount = 0;
4188 pSMB->Reserved = 0;
4189 pSMB->Flags = 0;
4190 pSMB->Timeout = 0;
4191 pSMB->Reserved2 = 0;
4192 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4193 offset = param_offset + params;
4194
4195 pSMB->MaxParameterCount = cpu_to_le16(4);
4196 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4197 pSMB->SetupCount = 1;
4198 pSMB->Reserved3 = 0;
4199 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4200 byte_count = 1 /* pad */ + params + 12;
4201
4202 pSMB->DataCount = cpu_to_le16(12);
4203 pSMB->ParameterCount = cpu_to_le16(params);
4204 pSMB->TotalDataCount = pSMB->DataCount;
4205 pSMB->TotalParameterCount = pSMB->ParameterCount;
4206 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4207 pSMB->DataOffset = cpu_to_le16(offset);
4208
4209 /* Params. */
4210 pSMB->FileNum = 0;
4211 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4212
4213 /* Data. */
4214 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4215 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4216 pSMB->ClientUnixCap = cpu_to_le64(cap);
4217
4218 pSMB->hdr.smb_buf_length += byte_count;
4219 pSMB->ByteCount = cpu_to_le16(byte_count);
4220
4221 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4222 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4223 if (rc) {
4224 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4225 } else { /* decode response */
4226 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4227 if (rc) {
4228 rc = -EIO; /* bad smb */
4229 }
4230 }
4231 cifs_buf_release(pSMB);
4232
4233 if (rc == -EAGAIN)
4234 goto SETFSUnixRetry;
4235
4236 return rc;
4237}
4238
4239
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
4241int
4242CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004243 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244{
4245/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4246 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4247 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4248 FILE_SYSTEM_POSIX_INFO *response_data;
4249 int rc = 0;
4250 int bytes_returned = 0;
4251 __u16 params, byte_count;
4252
4253 cFYI(1, ("In QFSPosixInfo"));
4254QFSPosixRetry:
4255 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4256 (void **) &pSMBr);
4257 if (rc)
4258 return rc;
4259
4260 params = 2; /* level */
4261 pSMB->TotalDataCount = 0;
4262 pSMB->DataCount = 0;
4263 pSMB->DataOffset = 0;
4264 pSMB->MaxParameterCount = cpu_to_le16(2);
4265 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4266 pSMB->MaxSetupCount = 0;
4267 pSMB->Reserved = 0;
4268 pSMB->Flags = 0;
4269 pSMB->Timeout = 0;
4270 pSMB->Reserved2 = 0;
4271 byte_count = params + 1 /* pad */ ;
4272 pSMB->ParameterCount = cpu_to_le16(params);
4273 pSMB->TotalParameterCount = pSMB->ParameterCount;
4274 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4275 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4276 pSMB->SetupCount = 1;
4277 pSMB->Reserved3 = 0;
4278 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4279 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4280 pSMB->hdr.smb_buf_length += byte_count;
4281 pSMB->ByteCount = cpu_to_le16(byte_count);
4282
4283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4284 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4285 if (rc) {
4286 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4287 } else { /* decode response */
4288 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4289
4290 if (rc || (pSMBr->ByteCount < 13)) {
4291 rc = -EIO; /* bad smb */
4292 } else {
4293 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4294 response_data =
4295 (FILE_SYSTEM_POSIX_INFO
4296 *) (((char *) &pSMBr->hdr.Protocol) +
4297 data_offset);
4298 FSData->f_bsize =
4299 le32_to_cpu(response_data->BlockSize);
4300 FSData->f_blocks =
4301 le64_to_cpu(response_data->TotalBlocks);
4302 FSData->f_bfree =
4303 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004304 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 FSData->f_bavail = FSData->f_bfree;
4306 } else {
4307 FSData->f_bavail =
4308 le64_to_cpu(response_data->UserBlocksAvail);
4309 }
Steve French70ca7342005-09-22 16:32:06 -07004310 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 FSData->f_files =
4312 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004313 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 FSData->f_ffree =
4315 le64_to_cpu(response_data->FreeFileNodes);
4316 }
4317 }
4318 cifs_buf_release(pSMB);
4319
4320 if (rc == -EAGAIN)
4321 goto QFSPosixRetry;
4322
4323 return rc;
4324}
4325
4326
4327/* We can not use write of zero bytes trick to
4328 set file size due to need for large file support. Also note that
4329 this SetPathInfo is preferred to SetFileInfo based method in next
4330 routine which is only needed to work around a sharing violation bug
4331 in Samba which this routine can run into */
4332
4333int
4334CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004335 __u64 size, int SetAllocation,
4336 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337{
4338 struct smb_com_transaction2_spi_req *pSMB = NULL;
4339 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4340 struct file_end_of_file_info *parm_data;
4341 int name_len;
4342 int rc = 0;
4343 int bytes_returned = 0;
4344 __u16 params, byte_count, data_count, param_offset, offset;
4345
4346 cFYI(1, ("In SetEOF"));
4347SetEOFRetry:
4348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4349 (void **) &pSMBr);
4350 if (rc)
4351 return rc;
4352
4353 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4354 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004355 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004356 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 name_len++; /* trailing null */
4358 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004359 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 name_len = strnlen(fileName, PATH_MAX);
4361 name_len++; /* trailing null */
4362 strncpy(pSMB->FileName, fileName, name_len);
4363 }
4364 params = 6 + name_len;
4365 data_count = sizeof (struct file_end_of_file_info);
4366 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004367 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 pSMB->MaxSetupCount = 0;
4369 pSMB->Reserved = 0;
4370 pSMB->Flags = 0;
4371 pSMB->Timeout = 0;
4372 pSMB->Reserved2 = 0;
4373 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4374 InformationLevel) - 4;
4375 offset = param_offset + params;
4376 if(SetAllocation) {
4377 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4378 pSMB->InformationLevel =
4379 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4380 else
4381 pSMB->InformationLevel =
4382 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4383 } else /* Set File Size */ {
4384 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4385 pSMB->InformationLevel =
4386 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4387 else
4388 pSMB->InformationLevel =
4389 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4390 }
4391
4392 parm_data =
4393 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4394 offset);
4395 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4396 pSMB->DataOffset = cpu_to_le16(offset);
4397 pSMB->SetupCount = 1;
4398 pSMB->Reserved3 = 0;
4399 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4400 byte_count = 3 /* pad */ + params + data_count;
4401 pSMB->DataCount = cpu_to_le16(data_count);
4402 pSMB->TotalDataCount = pSMB->DataCount;
4403 pSMB->ParameterCount = cpu_to_le16(params);
4404 pSMB->TotalParameterCount = pSMB->ParameterCount;
4405 pSMB->Reserved4 = 0;
4406 pSMB->hdr.smb_buf_length += byte_count;
4407 parm_data->FileSize = cpu_to_le64(size);
4408 pSMB->ByteCount = cpu_to_le16(byte_count);
4409 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4410 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4411 if (rc) {
4412 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4413 }
4414
4415 cifs_buf_release(pSMB);
4416
4417 if (rc == -EAGAIN)
4418 goto SetEOFRetry;
4419
4420 return rc;
4421}
4422
4423int
4424CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4425 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4426{
4427 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4428 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4429 char *data_offset;
4430 struct file_end_of_file_info *parm_data;
4431 int rc = 0;
4432 int bytes_returned = 0;
4433 __u16 params, param_offset, offset, byte_count, count;
4434
4435 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4436 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004437 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4438
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 if (rc)
4440 return rc;
4441
Steve Frenchcd634992005-04-28 22:41:10 -07004442 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4443
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4445 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4446
4447 params = 6;
4448 pSMB->MaxSetupCount = 0;
4449 pSMB->Reserved = 0;
4450 pSMB->Flags = 0;
4451 pSMB->Timeout = 0;
4452 pSMB->Reserved2 = 0;
4453 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4454 offset = param_offset + params;
4455
4456 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4457
4458 count = sizeof(struct file_end_of_file_info);
4459 pSMB->MaxParameterCount = cpu_to_le16(2);
4460 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4461 pSMB->SetupCount = 1;
4462 pSMB->Reserved3 = 0;
4463 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4464 byte_count = 3 /* pad */ + params + count;
4465 pSMB->DataCount = cpu_to_le16(count);
4466 pSMB->ParameterCount = cpu_to_le16(params);
4467 pSMB->TotalDataCount = pSMB->DataCount;
4468 pSMB->TotalParameterCount = pSMB->ParameterCount;
4469 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4470 parm_data =
4471 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4472 offset);
4473 pSMB->DataOffset = cpu_to_le16(offset);
4474 parm_data->FileSize = cpu_to_le64(size);
4475 pSMB->Fid = fid;
4476 if(SetAllocation) {
4477 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4478 pSMB->InformationLevel =
4479 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4480 else
4481 pSMB->InformationLevel =
4482 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4483 } else /* Set File Size */ {
4484 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4485 pSMB->InformationLevel =
4486 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4487 else
4488 pSMB->InformationLevel =
4489 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4490 }
4491 pSMB->Reserved4 = 0;
4492 pSMB->hdr.smb_buf_length += byte_count;
4493 pSMB->ByteCount = cpu_to_le16(byte_count);
4494 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4495 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4496 if (rc) {
4497 cFYI(1,
4498 ("Send error in SetFileInfo (SetFileSize) = %d",
4499 rc));
4500 }
4501
4502 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004503 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504
4505 /* Note: On -EAGAIN error only caller can retry on handle based calls
4506 since file handle passed in no longer valid */
4507
4508 return rc;
4509}
4510
4511/* Some legacy servers such as NT4 require that the file times be set on
4512 an open handle, rather than by pathname - this is awkward due to
4513 potential access conflicts on the open, but it is unavoidable for these
4514 old servers since the only other choice is to go from 100 nanosecond DCE
4515 time and resort to the original setpathinfo level which takes the ancient
4516 DOS time format with 2 second granularity */
4517int
4518CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4519 __u16 fid)
4520{
4521 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4522 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4523 char *data_offset;
4524 int rc = 0;
4525 int bytes_returned = 0;
4526 __u16 params, param_offset, offset, byte_count, count;
4527
4528 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004529 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4530
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 if (rc)
4532 return rc;
4533
Steve Frenchcd634992005-04-28 22:41:10 -07004534 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4535
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 /* At this point there is no need to override the current pid
4537 with the pid of the opener, but that could change if we someday
4538 use an existing handle (rather than opening one on the fly) */
4539 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4540 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4541
4542 params = 6;
4543 pSMB->MaxSetupCount = 0;
4544 pSMB->Reserved = 0;
4545 pSMB->Flags = 0;
4546 pSMB->Timeout = 0;
4547 pSMB->Reserved2 = 0;
4548 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4549 offset = param_offset + params;
4550
4551 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4552
4553 count = sizeof (FILE_BASIC_INFO);
4554 pSMB->MaxParameterCount = cpu_to_le16(2);
4555 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4556 pSMB->SetupCount = 1;
4557 pSMB->Reserved3 = 0;
4558 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4559 byte_count = 3 /* pad */ + params + count;
4560 pSMB->DataCount = cpu_to_le16(count);
4561 pSMB->ParameterCount = cpu_to_le16(params);
4562 pSMB->TotalDataCount = pSMB->DataCount;
4563 pSMB->TotalParameterCount = pSMB->ParameterCount;
4564 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4565 pSMB->DataOffset = cpu_to_le16(offset);
4566 pSMB->Fid = fid;
4567 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4568 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4569 else
4570 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4571 pSMB->Reserved4 = 0;
4572 pSMB->hdr.smb_buf_length += byte_count;
4573 pSMB->ByteCount = cpu_to_le16(byte_count);
4574 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4576 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4577 if (rc) {
4578 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4579 }
4580
Steve Frenchcd634992005-04-28 22:41:10 -07004581 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582
4583 /* Note: On -EAGAIN error only caller can retry on handle based calls
4584 since file handle passed in no longer valid */
4585
4586 return rc;
4587}
4588
4589
4590int
4591CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4592 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004593 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594{
4595 TRANSACTION2_SPI_REQ *pSMB = NULL;
4596 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4597 int name_len;
4598 int rc = 0;
4599 int bytes_returned = 0;
4600 char *data_offset;
4601 __u16 params, param_offset, offset, byte_count, count;
4602
4603 cFYI(1, ("In SetTimes"));
4604
4605SetTimesRetry:
4606 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4607 (void **) &pSMBr);
4608 if (rc)
4609 return rc;
4610
4611 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4612 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004613 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004614 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 name_len++; /* trailing null */
4616 name_len *= 2;
4617 } else { /* BB improve the check for buffer overruns BB */
4618 name_len = strnlen(fileName, PATH_MAX);
4619 name_len++; /* trailing null */
4620 strncpy(pSMB->FileName, fileName, name_len);
4621 }
4622
4623 params = 6 + name_len;
4624 count = sizeof (FILE_BASIC_INFO);
4625 pSMB->MaxParameterCount = cpu_to_le16(2);
4626 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4627 pSMB->MaxSetupCount = 0;
4628 pSMB->Reserved = 0;
4629 pSMB->Flags = 0;
4630 pSMB->Timeout = 0;
4631 pSMB->Reserved2 = 0;
4632 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4633 InformationLevel) - 4;
4634 offset = param_offset + params;
4635 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4636 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4637 pSMB->DataOffset = cpu_to_le16(offset);
4638 pSMB->SetupCount = 1;
4639 pSMB->Reserved3 = 0;
4640 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4641 byte_count = 3 /* pad */ + params + count;
4642
4643 pSMB->DataCount = cpu_to_le16(count);
4644 pSMB->ParameterCount = cpu_to_le16(params);
4645 pSMB->TotalDataCount = pSMB->DataCount;
4646 pSMB->TotalParameterCount = pSMB->ParameterCount;
4647 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4648 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4649 else
4650 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4651 pSMB->Reserved4 = 0;
4652 pSMB->hdr.smb_buf_length += byte_count;
4653 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4654 pSMB->ByteCount = cpu_to_le16(byte_count);
4655 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4656 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4657 if (rc) {
4658 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4659 }
4660
4661 cifs_buf_release(pSMB);
4662
4663 if (rc == -EAGAIN)
4664 goto SetTimesRetry;
4665
4666 return rc;
4667}
4668
4669/* Can not be used to set time stamps yet (due to old DOS time format) */
4670/* Can be used to set attributes */
4671#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4672 handling it anyway and NT4 was what we thought it would be needed for
4673 Do not delete it until we prove whether needed for Win9x though */
4674int
4675CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4676 __u16 dos_attrs, const struct nls_table *nls_codepage)
4677{
4678 SETATTR_REQ *pSMB = NULL;
4679 SETATTR_RSP *pSMBr = NULL;
4680 int rc = 0;
4681 int bytes_returned;
4682 int name_len;
4683
4684 cFYI(1, ("In SetAttrLegacy"));
4685
4686SetAttrLgcyRetry:
4687 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4688 (void **) &pSMBr);
4689 if (rc)
4690 return rc;
4691
4692 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4693 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004694 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 PATH_MAX, nls_codepage);
4696 name_len++; /* trailing null */
4697 name_len *= 2;
4698 } else { /* BB improve the check for buffer overruns BB */
4699 name_len = strnlen(fileName, PATH_MAX);
4700 name_len++; /* trailing null */
4701 strncpy(pSMB->fileName, fileName, name_len);
4702 }
4703 pSMB->attr = cpu_to_le16(dos_attrs);
4704 pSMB->BufferFormat = 0x04;
4705 pSMB->hdr.smb_buf_length += name_len + 1;
4706 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4707 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4708 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4709 if (rc) {
4710 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4711 }
4712
4713 cifs_buf_release(pSMB);
4714
4715 if (rc == -EAGAIN)
4716 goto SetAttrLgcyRetry;
4717
4718 return rc;
4719}
4720#endif /* temporarily unneeded SetAttr legacy function */
4721
4722int
4723CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004724 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4725 dev_t device, const struct nls_table *nls_codepage,
4726 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727{
4728 TRANSACTION2_SPI_REQ *pSMB = NULL;
4729 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4730 int name_len;
4731 int rc = 0;
4732 int bytes_returned = 0;
4733 FILE_UNIX_BASIC_INFO *data_offset;
4734 __u16 params, param_offset, offset, count, byte_count;
4735
4736 cFYI(1, ("In SetUID/GID/Mode"));
4737setPermsRetry:
4738 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4739 (void **) &pSMBr);
4740 if (rc)
4741 return rc;
4742
4743 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4744 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004745 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004746 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 name_len++; /* trailing null */
4748 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004749 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 name_len = strnlen(fileName, PATH_MAX);
4751 name_len++; /* trailing null */
4752 strncpy(pSMB->FileName, fileName, name_len);
4753 }
4754
4755 params = 6 + name_len;
4756 count = sizeof (FILE_UNIX_BASIC_INFO);
4757 pSMB->MaxParameterCount = cpu_to_le16(2);
4758 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4759 pSMB->MaxSetupCount = 0;
4760 pSMB->Reserved = 0;
4761 pSMB->Flags = 0;
4762 pSMB->Timeout = 0;
4763 pSMB->Reserved2 = 0;
4764 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4765 InformationLevel) - 4;
4766 offset = param_offset + params;
4767 data_offset =
4768 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4769 offset);
4770 memset(data_offset, 0, count);
4771 pSMB->DataOffset = cpu_to_le16(offset);
4772 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4773 pSMB->SetupCount = 1;
4774 pSMB->Reserved3 = 0;
4775 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4776 byte_count = 3 /* pad */ + params + count;
4777 pSMB->ParameterCount = cpu_to_le16(params);
4778 pSMB->DataCount = cpu_to_le16(count);
4779 pSMB->TotalParameterCount = pSMB->ParameterCount;
4780 pSMB->TotalDataCount = pSMB->DataCount;
4781 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4782 pSMB->Reserved4 = 0;
4783 pSMB->hdr.smb_buf_length += byte_count;
4784 data_offset->Uid = cpu_to_le64(uid);
4785 data_offset->Gid = cpu_to_le64(gid);
4786 /* better to leave device as zero when it is */
4787 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4788 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4789 data_offset->Permissions = cpu_to_le64(mode);
4790
4791 if(S_ISREG(mode))
4792 data_offset->Type = cpu_to_le32(UNIX_FILE);
4793 else if(S_ISDIR(mode))
4794 data_offset->Type = cpu_to_le32(UNIX_DIR);
4795 else if(S_ISLNK(mode))
4796 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4797 else if(S_ISCHR(mode))
4798 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4799 else if(S_ISBLK(mode))
4800 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4801 else if(S_ISFIFO(mode))
4802 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4803 else if(S_ISSOCK(mode))
4804 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4805
4806
4807 pSMB->ByteCount = cpu_to_le16(byte_count);
4808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4810 if (rc) {
4811 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4812 }
4813
4814 if (pSMB)
4815 cifs_buf_release(pSMB);
4816 if (rc == -EAGAIN)
4817 goto setPermsRetry;
4818 return rc;
4819}
4820
4821int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004822 const int notify_subdirs, const __u16 netfid,
4823 __u32 filter, struct file * pfile, int multishot,
4824 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825{
4826 int rc = 0;
4827 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004828 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004829 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 int bytes_returned;
4831
4832 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4833 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4834 (void **) &pSMBr);
4835 if (rc)
4836 return rc;
4837
4838 pSMB->TotalParameterCount = 0 ;
4839 pSMB->TotalDataCount = 0;
4840 pSMB->MaxParameterCount = cpu_to_le32(2);
4841 /* BB find exact data count max from sess structure BB */
4842 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004843/* BB VERIFY verify which is correct for above BB */
4844 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4845 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4846
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 pSMB->MaxSetupCount = 4;
4848 pSMB->Reserved = 0;
4849 pSMB->ParameterOffset = 0;
4850 pSMB->DataCount = 0;
4851 pSMB->DataOffset = 0;
4852 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4853 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4854 pSMB->ParameterCount = pSMB->TotalParameterCount;
4855 if(notify_subdirs)
4856 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4857 pSMB->Reserved2 = 0;
4858 pSMB->CompletionFilter = cpu_to_le32(filter);
4859 pSMB->Fid = netfid; /* file handle always le */
4860 pSMB->ByteCount = 0;
4861
4862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4863 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4864 if (rc) {
4865 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004866 } else {
4867 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004868 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004869 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004870 sizeof(struct dir_notify_req),
4871 GFP_KERNEL);
4872 if(dnotify_req) {
4873 dnotify_req->Pid = pSMB->hdr.Pid;
4874 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4875 dnotify_req->Mid = pSMB->hdr.Mid;
4876 dnotify_req->Tid = pSMB->hdr.Tid;
4877 dnotify_req->Uid = pSMB->hdr.Uid;
4878 dnotify_req->netfid = netfid;
4879 dnotify_req->pfile = pfile;
4880 dnotify_req->filter = filter;
4881 dnotify_req->multishot = multishot;
4882 spin_lock(&GlobalMid_Lock);
4883 list_add_tail(&dnotify_req->lhead,
4884 &GlobalDnotifyReqList);
4885 spin_unlock(&GlobalMid_Lock);
4886 } else
4887 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 }
4889 cifs_buf_release(pSMB);
4890 return rc;
4891}
4892#ifdef CONFIG_CIFS_XATTR
4893ssize_t
4894CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4895 const unsigned char *searchName,
4896 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004897 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898{
4899 /* BB assumes one setup word */
4900 TRANSACTION2_QPI_REQ *pSMB = NULL;
4901 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4902 int rc = 0;
4903 int bytes_returned;
4904 int name_len;
4905 struct fea * temp_fea;
4906 char * temp_ptr;
4907 __u16 params, byte_count;
4908
4909 cFYI(1, ("In Query All EAs path %s", searchName));
4910QAllEAsRetry:
4911 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4912 (void **) &pSMBr);
4913 if (rc)
4914 return rc;
4915
4916 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4917 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004918 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004919 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 name_len++; /* trailing null */
4921 name_len *= 2;
4922 } else { /* BB improve the check for buffer overruns BB */
4923 name_len = strnlen(searchName, PATH_MAX);
4924 name_len++; /* trailing null */
4925 strncpy(pSMB->FileName, searchName, name_len);
4926 }
4927
4928 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4929 pSMB->TotalDataCount = 0;
4930 pSMB->MaxParameterCount = cpu_to_le16(2);
4931 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4932 pSMB->MaxSetupCount = 0;
4933 pSMB->Reserved = 0;
4934 pSMB->Flags = 0;
4935 pSMB->Timeout = 0;
4936 pSMB->Reserved2 = 0;
4937 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4938 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4939 pSMB->DataCount = 0;
4940 pSMB->DataOffset = 0;
4941 pSMB->SetupCount = 1;
4942 pSMB->Reserved3 = 0;
4943 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4944 byte_count = params + 1 /* pad */ ;
4945 pSMB->TotalParameterCount = cpu_to_le16(params);
4946 pSMB->ParameterCount = pSMB->TotalParameterCount;
4947 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4948 pSMB->Reserved4 = 0;
4949 pSMB->hdr.smb_buf_length += byte_count;
4950 pSMB->ByteCount = cpu_to_le16(byte_count);
4951
4952 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4953 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4954 if (rc) {
4955 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4956 } else { /* decode response */
4957 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4958
4959 /* BB also check enough total bytes returned */
4960 /* BB we need to improve the validity checking
4961 of these trans2 responses */
4962 if (rc || (pSMBr->ByteCount < 4))
4963 rc = -EIO; /* bad smb */
4964 /* else if (pFindData){
4965 memcpy((char *) pFindData,
4966 (char *) &pSMBr->hdr.Protocol +
4967 data_offset, kl);
4968 }*/ else {
4969 /* check that length of list is not more than bcc */
4970 /* check that each entry does not go beyond length
4971 of list */
4972 /* check that each element of each entry does not
4973 go beyond end of list */
4974 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4975 struct fealist * ea_response_data;
4976 rc = 0;
4977 /* validate_trans2_offsets() */
4978 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4979 ea_response_data = (struct fealist *)
4980 (((char *) &pSMBr->hdr.Protocol) +
4981 data_offset);
4982 name_len = le32_to_cpu(ea_response_data->list_len);
4983 cFYI(1,("ea length %d", name_len));
4984 if(name_len <= 8) {
4985 /* returned EA size zeroed at top of function */
4986 cFYI(1,("empty EA list returned from server"));
4987 } else {
4988 /* account for ea list len */
4989 name_len -= 4;
4990 temp_fea = ea_response_data->list;
4991 temp_ptr = (char *)temp_fea;
4992 while(name_len > 0) {
4993 __u16 value_len;
4994 name_len -= 4;
4995 temp_ptr += 4;
4996 rc += temp_fea->name_len;
4997 /* account for prefix user. and trailing null */
4998 rc = rc + 5 + 1;
4999 if(rc<(int)buf_size) {
5000 memcpy(EAData,"user.",5);
5001 EAData+=5;
5002 memcpy(EAData,temp_ptr,temp_fea->name_len);
5003 EAData+=temp_fea->name_len;
5004 /* null terminate name */
5005 *EAData = 0;
5006 EAData = EAData + 1;
5007 } else if(buf_size == 0) {
5008 /* skip copy - calc size only */
5009 } else {
5010 /* stop before overrun buffer */
5011 rc = -ERANGE;
5012 break;
5013 }
5014 name_len -= temp_fea->name_len;
5015 temp_ptr += temp_fea->name_len;
5016 /* account for trailing null */
5017 name_len--;
5018 temp_ptr++;
5019 value_len = le16_to_cpu(temp_fea->value_len);
5020 name_len -= value_len;
5021 temp_ptr += value_len;
5022 /* BB check that temp_ptr is still within smb BB*/
5023 /* no trailing null to account for in value len */
5024 /* go on to next EA */
5025 temp_fea = (struct fea *)temp_ptr;
5026 }
5027 }
5028 }
5029 }
5030 if (pSMB)
5031 cifs_buf_release(pSMB);
5032 if (rc == -EAGAIN)
5033 goto QAllEAsRetry;
5034
5035 return (ssize_t)rc;
5036}
5037
5038ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5039 const unsigned char * searchName,const unsigned char * ea_name,
5040 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005041 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042{
5043 TRANSACTION2_QPI_REQ *pSMB = NULL;
5044 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5045 int rc = 0;
5046 int bytes_returned;
5047 int name_len;
5048 struct fea * temp_fea;
5049 char * temp_ptr;
5050 __u16 params, byte_count;
5051
5052 cFYI(1, ("In Query EA path %s", searchName));
5053QEARetry:
5054 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5055 (void **) &pSMBr);
5056 if (rc)
5057 return rc;
5058
5059 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5060 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005061 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005062 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 name_len++; /* trailing null */
5064 name_len *= 2;
5065 } else { /* BB improve the check for buffer overruns BB */
5066 name_len = strnlen(searchName, PATH_MAX);
5067 name_len++; /* trailing null */
5068 strncpy(pSMB->FileName, searchName, name_len);
5069 }
5070
5071 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5072 pSMB->TotalDataCount = 0;
5073 pSMB->MaxParameterCount = cpu_to_le16(2);
5074 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5075 pSMB->MaxSetupCount = 0;
5076 pSMB->Reserved = 0;
5077 pSMB->Flags = 0;
5078 pSMB->Timeout = 0;
5079 pSMB->Reserved2 = 0;
5080 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5081 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5082 pSMB->DataCount = 0;
5083 pSMB->DataOffset = 0;
5084 pSMB->SetupCount = 1;
5085 pSMB->Reserved3 = 0;
5086 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5087 byte_count = params + 1 /* pad */ ;
5088 pSMB->TotalParameterCount = cpu_to_le16(params);
5089 pSMB->ParameterCount = pSMB->TotalParameterCount;
5090 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5091 pSMB->Reserved4 = 0;
5092 pSMB->hdr.smb_buf_length += byte_count;
5093 pSMB->ByteCount = cpu_to_le16(byte_count);
5094
5095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5097 if (rc) {
5098 cFYI(1, ("Send error in Query EA = %d", rc));
5099 } else { /* decode response */
5100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5101
5102 /* BB also check enough total bytes returned */
5103 /* BB we need to improve the validity checking
5104 of these trans2 responses */
5105 if (rc || (pSMBr->ByteCount < 4))
5106 rc = -EIO; /* bad smb */
5107 /* else if (pFindData){
5108 memcpy((char *) pFindData,
5109 (char *) &pSMBr->hdr.Protocol +
5110 data_offset, kl);
5111 }*/ else {
5112 /* check that length of list is not more than bcc */
5113 /* check that each entry does not go beyond length
5114 of list */
5115 /* check that each element of each entry does not
5116 go beyond end of list */
5117 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5118 struct fealist * ea_response_data;
5119 rc = -ENODATA;
5120 /* validate_trans2_offsets() */
5121 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5122 ea_response_data = (struct fealist *)
5123 (((char *) &pSMBr->hdr.Protocol) +
5124 data_offset);
5125 name_len = le32_to_cpu(ea_response_data->list_len);
5126 cFYI(1,("ea length %d", name_len));
5127 if(name_len <= 8) {
5128 /* returned EA size zeroed at top of function */
5129 cFYI(1,("empty EA list returned from server"));
5130 } else {
5131 /* account for ea list len */
5132 name_len -= 4;
5133 temp_fea = ea_response_data->list;
5134 temp_ptr = (char *)temp_fea;
5135 /* loop through checking if we have a matching
5136 name and then return the associated value */
5137 while(name_len > 0) {
5138 __u16 value_len;
5139 name_len -= 4;
5140 temp_ptr += 4;
5141 value_len = le16_to_cpu(temp_fea->value_len);
5142 /* BB validate that value_len falls within SMB,
5143 even though maximum for name_len is 255 */
5144 if(memcmp(temp_fea->name,ea_name,
5145 temp_fea->name_len) == 0) {
5146 /* found a match */
5147 rc = value_len;
5148 /* account for prefix user. and trailing null */
5149 if(rc<=(int)buf_size) {
5150 memcpy(ea_value,
5151 temp_fea->name+temp_fea->name_len+1,
5152 rc);
5153 /* ea values, unlike ea names,
5154 are not null terminated */
5155 } else if(buf_size == 0) {
5156 /* skip copy - calc size only */
5157 } else {
5158 /* stop before overrun buffer */
5159 rc = -ERANGE;
5160 }
5161 break;
5162 }
5163 name_len -= temp_fea->name_len;
5164 temp_ptr += temp_fea->name_len;
5165 /* account for trailing null */
5166 name_len--;
5167 temp_ptr++;
5168 name_len -= value_len;
5169 temp_ptr += value_len;
5170 /* no trailing null to account for in value len */
5171 /* go on to next EA */
5172 temp_fea = (struct fea *)temp_ptr;
5173 }
5174 }
5175 }
5176 }
5177 if (pSMB)
5178 cifs_buf_release(pSMB);
5179 if (rc == -EAGAIN)
5180 goto QEARetry;
5181
5182 return (ssize_t)rc;
5183}
5184
5185int
5186CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5187 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005188 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5189 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190{
5191 struct smb_com_transaction2_spi_req *pSMB = NULL;
5192 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5193 struct fealist *parm_data;
5194 int name_len;
5195 int rc = 0;
5196 int bytes_returned = 0;
5197 __u16 params, param_offset, byte_count, offset, count;
5198
5199 cFYI(1, ("In SetEA"));
5200SetEARetry:
5201 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5202 (void **) &pSMBr);
5203 if (rc)
5204 return rc;
5205
5206 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5207 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005208 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005209 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 name_len++; /* trailing null */
5211 name_len *= 2;
5212 } else { /* BB improve the check for buffer overruns BB */
5213 name_len = strnlen(fileName, PATH_MAX);
5214 name_len++; /* trailing null */
5215 strncpy(pSMB->FileName, fileName, name_len);
5216 }
5217
5218 params = 6 + name_len;
5219
5220 /* done calculating parms using name_len of file name,
5221 now use name_len to calculate length of ea name
5222 we are going to create in the inode xattrs */
5223 if(ea_name == NULL)
5224 name_len = 0;
5225 else
5226 name_len = strnlen(ea_name,255);
5227
5228 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5229 pSMB->MaxParameterCount = cpu_to_le16(2);
5230 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5231 pSMB->MaxSetupCount = 0;
5232 pSMB->Reserved = 0;
5233 pSMB->Flags = 0;
5234 pSMB->Timeout = 0;
5235 pSMB->Reserved2 = 0;
5236 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5237 InformationLevel) - 4;
5238 offset = param_offset + params;
5239 pSMB->InformationLevel =
5240 cpu_to_le16(SMB_SET_FILE_EA);
5241
5242 parm_data =
5243 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5244 offset);
5245 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5246 pSMB->DataOffset = cpu_to_le16(offset);
5247 pSMB->SetupCount = 1;
5248 pSMB->Reserved3 = 0;
5249 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5250 byte_count = 3 /* pad */ + params + count;
5251 pSMB->DataCount = cpu_to_le16(count);
5252 parm_data->list_len = cpu_to_le32(count);
5253 parm_data->list[0].EA_flags = 0;
5254 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005255 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 /* EA names are always ASCII */
5257 if(ea_name)
5258 strncpy(parm_data->list[0].name,ea_name,name_len);
5259 parm_data->list[0].name[name_len] = 0;
5260 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5261 /* caller ensures that ea_value_len is less than 64K but
5262 we need to ensure that it fits within the smb */
5263
5264 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5265 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5266 if(ea_value_len)
5267 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5268
5269 pSMB->TotalDataCount = pSMB->DataCount;
5270 pSMB->ParameterCount = cpu_to_le16(params);
5271 pSMB->TotalParameterCount = pSMB->ParameterCount;
5272 pSMB->Reserved4 = 0;
5273 pSMB->hdr.smb_buf_length += byte_count;
5274 pSMB->ByteCount = cpu_to_le16(byte_count);
5275 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5276 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5277 if (rc) {
5278 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5279 }
5280
5281 cifs_buf_release(pSMB);
5282
5283 if (rc == -EAGAIN)
5284 goto SetEARetry;
5285
5286 return rc;
5287}
5288
5289#endif