blob: 75f060328e291a4d7d54f64dd9ea80c03dd01308 [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 French25ee4a92006-09-30 00:54:23 +0000453 int tmp, adjust;
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 French25ee4a92006-09-30 00:54:23 +0000479 tmp = le16_to_cpu(rsp->ServerTimeZone);
480 if (tmp == (int)0xffff) {
481 /* OS/2 often does not set timezone therefore
482 * we must use server time to calc time zone.
483 * Could deviate slightly from the right zone. Not easy
484 * to adjust, since timezones are not always a multiple
485 * of 60 (sometimes 30 minutes - are there smaller?)
486 */
487 struct timespec ts, utc;
488 utc = CURRENT_TIME;
489 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
490 le16_to_cpu(rsp->SrvTime.Time));
491 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
492 (int)ts.tv_sec, (int)utc.tv_sec,
493 (int)(utc.tv_sec - ts.tv_sec)));
494 tmp = (int)(utc.tv_sec - ts.tv_sec);
495 adjust = tmp < 0 ? -29 : 29;
496 tmp = ((tmp + adjust) / 60) * 60;
Steve French175ec9e2006-09-30 01:07:38 +0000497 server->timeAdj = tmp;
Steve French25ee4a92006-09-30 00:54:23 +0000498 } else {
Steve French175ec9e2006-09-30 01:07:38 +0000499 server->timeAdj = tmp * 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000500 }
Steve French175ec9e2006-09-30 01:07:38 +0000501 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000502
Steve French39798772006-05-31 22:40:51 +0000503
Steve French254e55e2006-06-04 05:53:15 +0000504 /* BB get server time for time conversions and add
505 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000506
Steve French25ee4a92006-09-30 00:54:23 +0000507 if (rsp->EncryptionKeyLength ==
508 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000509 memcpy(server->cryptKey, rsp->EncryptionKey,
510 CIFS_CRYPTO_KEY_SIZE);
511 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
512 rc = -EIO; /* need cryptkey unless plain text */
513 goto neg_err_exit;
514 }
Steve French39798772006-05-31 22:40:51 +0000515
Steve French254e55e2006-06-04 05:53:15 +0000516 cFYI(1,("LANMAN negotiated"));
517 /* we will not end up setting signing flags - as no signing
518 was in LANMAN and server did not return the flags on */
519 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000520#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000521 } else if(pSMBr->hdr.WordCount == 13) {
522 cERROR(1,("mount failed, cifs module not built "
523 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000524 rc = -EOPNOTSUPP;
525#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000526 goto neg_err_exit;
527 } else if(pSMBr->hdr.WordCount != 17) {
528 /* unknown wct */
529 rc = -EOPNOTSUPP;
530 goto neg_err_exit;
531 }
532 /* else wct == 17 NTLM */
533 server->secMode = pSMBr->SecurityMode;
534 if((server->secMode & SECMODE_USER) == 0)
535 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000536
Steve French254e55e2006-06-04 05:53:15 +0000537 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000538#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000539 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000540#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000541 cERROR(1,("Server requests plain text password"
542 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000543
Steve Frenchf40c5622006-06-28 00:13:38 +0000544 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000545 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000546 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000547 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000548 else if(secFlags & CIFSSEC_MAY_NTLMV2)
549 server->secType = NTLMv2;
550 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000551
Steve French254e55e2006-06-04 05:53:15 +0000552 /* one byte, so no need to convert this or EncryptionKeyLen from
553 little endian */
554 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
555 /* probably no need to store and check maxvcs */
556 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000558 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
559 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
560 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
561 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve French175ec9e2006-09-30 01:07:38 +0000562 server->timeAdj = le16_to_cpu(pSMBr->ServerTimeZone) * 60;
Steve French254e55e2006-06-04 05:53:15 +0000563 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
564 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
565 CIFS_CRYPTO_KEY_SIZE);
566 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
567 && (pSMBr->EncryptionKeyLength == 0)) {
568 /* decode security blob */
569 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
570 rc = -EIO; /* no crypt key only if plain text pwd */
571 goto neg_err_exit;
572 }
573
574 /* BB might be helpful to save off the domain of server here */
575
576 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
577 (server->capabilities & CAP_EXTENDED_SECURITY)) {
578 count = pSMBr->ByteCount;
579 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000581 else if (count == 16) {
582 server->secType = RawNTLMSSP;
583 if (server->socketUseCount.counter > 1) {
584 if (memcmp(server->server_GUID,
585 pSMBr->u.extended_response.
586 GUID, 16) != 0) {
587 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000589 pSMBr->u.extended_response.GUID,
590 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
Steve French254e55e2006-06-04 05:53:15 +0000592 } else
593 memcpy(server->server_GUID,
594 pSMBr->u.extended_response.GUID, 16);
595 } else {
596 rc = decode_negTokenInit(pSMBr->u.extended_response.
597 SecurityBlob,
598 count - 16,
599 &server->secType);
600 if(rc == 1) {
601 /* BB Need to fill struct for sessetup here */
602 rc = -EOPNOTSUPP;
603 } else {
604 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 }
Steve French254e55e2006-06-04 05:53:15 +0000607 } else
608 server->capabilities &= ~CAP_EXTENDED_SECURITY;
609
Steve French6344a422006-06-12 04:18:35 +0000610#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000611signing_check:
Steve French6344a422006-06-12 04:18:35 +0000612#endif
Steve French254e55e2006-06-04 05:53:15 +0000613 if(sign_CIFS_PDUs == FALSE) {
614 if(server->secMode & SECMODE_SIGN_REQUIRED)
615 cERROR(1,("Server requires "
616 "/proc/fs/cifs/PacketSigningEnabled to be on"));
617 server->secMode &=
618 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
619 } else if(sign_CIFS_PDUs == 1) {
620 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
621 server->secMode &=
622 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
623 } else if(sign_CIFS_PDUs == 2) {
624 if((server->secMode &
625 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
626 cERROR(1,("signing required but server lacks support"));
627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
Steve French39798772006-05-31 22:40:51 +0000629neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700630 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000631
632 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 return rc;
634}
635
636int
637CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
638{
639 struct smb_hdr *smb_buffer;
640 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
641 int rc = 0;
642 int length;
643
644 cFYI(1, ("In tree disconnect"));
645 /*
646 * If last user of the connection and
647 * connection alive - disconnect it
648 * If this is the last connection on the server session disconnect it
649 * (and inside session disconnect we should check if tcp socket needs
650 * to be freed and kernel thread woken up).
651 */
652 if (tcon)
653 down(&tcon->tconSem);
654 else
655 return -EIO;
656
657 atomic_dec(&tcon->useCount);
658 if (atomic_read(&tcon->useCount) > 0) {
659 up(&tcon->tconSem);
660 return -EBUSY;
661 }
662
663 /* No need to return error on this operation if tid invalidated and
664 closed on server already e.g. due to tcp session crashing */
665 if(tcon->tidStatus == CifsNeedReconnect) {
666 up(&tcon->tconSem);
667 return 0;
668 }
669
670 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
671 up(&tcon->tconSem);
672 return -EIO;
673 }
Steve French09d1db52005-04-28 22:41:08 -0700674 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
675 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (rc) {
677 up(&tcon->tconSem);
678 return rc;
679 } else {
680 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
683 &length, 0);
684 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700685 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 if (smb_buffer)
688 cifs_small_buf_release(smb_buffer);
689 up(&tcon->tconSem);
690
691 /* No need to return error on this operation if tid invalidated and
692 closed on server already e.g. due to tcp session crashing */
693 if (rc == -EAGAIN)
694 rc = 0;
695
696 return rc;
697}
698
699int
700CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
701{
702 struct smb_hdr *smb_buffer_response;
703 LOGOFF_ANDX_REQ *pSMB;
704 int rc = 0;
705 int length;
706
707 cFYI(1, ("In SMBLogoff for session disconnect"));
708 if (ses)
709 down(&ses->sesSem);
710 else
711 return -EIO;
712
713 atomic_dec(&ses->inUse);
714 if (atomic_read(&ses->inUse) > 0) {
715 up(&ses->sesSem);
716 return -EBUSY;
717 }
718 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
719 if (rc) {
720 up(&ses->sesSem);
721 return rc;
722 }
723
724 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
725
726 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700727 pSMB->hdr.Mid = GetNextMid(ses->server);
728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 if(ses->server->secMode &
730 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
731 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
732 }
733
734 pSMB->hdr.Uid = ses->Suid;
735
736 pSMB->AndXCommand = 0xFF;
737 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
738 smb_buffer_response, &length, 0);
739 if (ses->server) {
740 atomic_dec(&ses->server->socketUseCount);
741 if (atomic_read(&ses->server->socketUseCount) == 0) {
742 spin_lock(&GlobalMid_Lock);
743 ses->server->tcpStatus = CifsExiting;
744 spin_unlock(&GlobalMid_Lock);
745 rc = -ESHUTDOWN;
746 }
747 }
Steve Frencha59c6582005-08-17 12:12:19 -0700748 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700749 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751 /* if session dead then we do not need to do ulogoff,
752 since server closed smb session, no sense reporting
753 error */
754 if (rc == -EAGAIN)
755 rc = 0;
756 return rc;
757}
758
759int
Steve French737b7582005-04-28 22:41:06 -0700760CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
761 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 DELETE_FILE_REQ *pSMB = NULL;
764 DELETE_FILE_RSP *pSMBr = NULL;
765 int rc = 0;
766 int bytes_returned;
767 int name_len;
768
769DelFileRetry:
770 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
771 (void **) &pSMBr);
772 if (rc)
773 return rc;
774
775 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
776 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500777 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700778 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 name_len++; /* trailing null */
780 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700781 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 name_len = strnlen(fileName, PATH_MAX);
783 name_len++; /* trailing null */
784 strncpy(pSMB->fileName, fileName, name_len);
785 }
786 pSMB->SearchAttributes =
787 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
788 pSMB->BufferFormat = 0x04;
789 pSMB->hdr.smb_buf_length += name_len + 1;
790 pSMB->ByteCount = cpu_to_le16(name_len + 1);
791 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
792 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700793 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 if (rc) {
795 cFYI(1, ("Error in RMFile = %d", rc));
796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 cifs_buf_release(pSMB);
799 if (rc == -EAGAIN)
800 goto DelFileRetry;
801
802 return rc;
803}
804
805int
Steve French737b7582005-04-28 22:41:06 -0700806CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
807 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
809 DELETE_DIRECTORY_REQ *pSMB = NULL;
810 DELETE_DIRECTORY_RSP *pSMBr = NULL;
811 int rc = 0;
812 int bytes_returned;
813 int name_len;
814
815 cFYI(1, ("In CIFSSMBRmDir"));
816RmDirRetry:
817 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
818 (void **) &pSMBr);
819 if (rc)
820 return rc;
821
822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700823 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
824 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 name_len++; /* trailing null */
826 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700827 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 name_len = strnlen(dirName, PATH_MAX);
829 name_len++; /* trailing null */
830 strncpy(pSMB->DirName, dirName, name_len);
831 }
832
833 pSMB->BufferFormat = 0x04;
834 pSMB->hdr.smb_buf_length += name_len + 1;
835 pSMB->ByteCount = cpu_to_le16(name_len + 1);
836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
837 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700838 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (rc) {
840 cFYI(1, ("Error in RMDir = %d", rc));
841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 cifs_buf_release(pSMB);
844 if (rc == -EAGAIN)
845 goto RmDirRetry;
846 return rc;
847}
848
849int
850CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700851 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852{
853 int rc = 0;
854 CREATE_DIRECTORY_REQ *pSMB = NULL;
855 CREATE_DIRECTORY_RSP *pSMBr = NULL;
856 int bytes_returned;
857 int name_len;
858
859 cFYI(1, ("In CIFSSMBMkDir"));
860MkDirRetry:
861 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
862 (void **) &pSMBr);
863 if (rc)
864 return rc;
865
866 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500867 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700868 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 name_len++; /* trailing null */
870 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700871 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 name_len = strnlen(name, PATH_MAX);
873 name_len++; /* trailing null */
874 strncpy(pSMB->DirName, name, name_len);
875 }
876
877 pSMB->BufferFormat = 0x04;
878 pSMB->hdr.smb_buf_length += name_len + 1;
879 pSMB->ByteCount = cpu_to_le16(name_len + 1);
880 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
881 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700882 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (rc) {
884 cFYI(1, ("Error in Mkdir = %d", rc));
885 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 cifs_buf_release(pSMB);
888 if (rc == -EAGAIN)
889 goto MkDirRetry;
890 return rc;
891}
892
Steve Frencha9d02ad2005-08-24 23:06:05 -0700893static __u16 convert_disposition(int disposition)
894{
895 __u16 ofun = 0;
896
897 switch (disposition) {
898 case FILE_SUPERSEDE:
899 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
900 break;
901 case FILE_OPEN:
902 ofun = SMBOPEN_OAPPEND;
903 break;
904 case FILE_CREATE:
905 ofun = SMBOPEN_OCREATE;
906 break;
907 case FILE_OPEN_IF:
908 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
909 break;
910 case FILE_OVERWRITE:
911 ofun = SMBOPEN_OTRUNC;
912 break;
913 case FILE_OVERWRITE_IF:
914 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
915 break;
916 default:
917 cFYI(1,("unknown disposition %d",disposition));
918 ofun = SMBOPEN_OAPPEND; /* regular open */
919 }
920 return ofun;
921}
922
923int
924SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
925 const char *fileName, const int openDisposition,
926 const int access_flags, const int create_options, __u16 * netfid,
927 int *pOplock, FILE_ALL_INFO * pfile_info,
928 const struct nls_table *nls_codepage, int remap)
929{
930 int rc = -EACCES;
931 OPENX_REQ *pSMB = NULL;
932 OPENX_RSP *pSMBr = NULL;
933 int bytes_returned;
934 int name_len;
935 __u16 count;
936
937OldOpenRetry:
938 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
939 (void **) &pSMBr);
940 if (rc)
941 return rc;
942
943 pSMB->AndXCommand = 0xFF; /* none */
944
945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
946 count = 1; /* account for one byte pad to word boundary */
947 name_len =
948 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
949 fileName, PATH_MAX, nls_codepage, remap);
950 name_len++; /* trailing null */
951 name_len *= 2;
952 } else { /* BB improve check for buffer overruns BB */
953 count = 0; /* no pad */
954 name_len = strnlen(fileName, PATH_MAX);
955 name_len++; /* trailing null */
956 strncpy(pSMB->fileName, fileName, name_len);
957 }
958 if (*pOplock & REQ_OPLOCK)
959 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
960 else if (*pOplock & REQ_BATCHOPLOCK) {
961 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
962 }
963 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
964 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
965 /* 0 = read
966 1 = write
967 2 = rw
968 3 = execute
969 */
970 pSMB->Mode = cpu_to_le16(2);
971 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
972 /* set file as system file if special file such
973 as fifo and server expecting SFU style and
974 no Unix extensions */
975
976 if(create_options & CREATE_OPTION_SPECIAL)
977 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
978 else
Steve French3e87d802005-09-18 20:49:21 -0700979 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700980
981 /* if ((omode & S_IWUGO) == 0)
982 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
983 /* Above line causes problems due to vfs splitting create into two
984 pieces - need to set mode after file created not while it is
985 being created */
986
987 /* BB FIXME BB */
988/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
989 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700990
991 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700992 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700993 count += name_len;
994 pSMB->hdr.smb_buf_length += count;
995
996 pSMB->ByteCount = cpu_to_le16(count);
997 /* long_op set to 1 to allow for oplock break timeouts */
998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
999 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1000 cifs_stats_inc(&tcon->num_opens);
1001 if (rc) {
1002 cFYI(1, ("Error in Open = %d", rc));
1003 } else {
1004 /* BB verify if wct == 15 */
1005
1006/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1007
1008 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1009 /* Let caller know file was created so we can set the mode. */
1010 /* Do we care about the CreateAction in any other cases? */
1011 /* BB FIXME BB */
1012/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1013 *pOplock |= CIFS_CREATE_ACTION; */
1014 /* BB FIXME END */
1015
1016 if(pfile_info) {
1017 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1018 pfile_info->LastAccessTime = 0; /* BB fixme */
1019 pfile_info->LastWriteTime = 0; /* BB fixme */
1020 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001021 pfile_info->Attributes =
1022 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001023 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001024 pfile_info->AllocationSize =
1025 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1026 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001027 pfile_info->NumberOfLinks = cpu_to_le32(1);
1028 }
1029 }
1030
1031 cifs_buf_release(pSMB);
1032 if (rc == -EAGAIN)
1033 goto OldOpenRetry;
1034 return rc;
1035}
1036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037int
1038CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1039 const char *fileName, const int openDisposition,
1040 const int access_flags, const int create_options, __u16 * netfid,
1041 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001042 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
1044 int rc = -EACCES;
1045 OPEN_REQ *pSMB = NULL;
1046 OPEN_RSP *pSMBr = NULL;
1047 int bytes_returned;
1048 int name_len;
1049 __u16 count;
1050
1051openRetry:
1052 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1053 (void **) &pSMBr);
1054 if (rc)
1055 return rc;
1056
1057 pSMB->AndXCommand = 0xFF; /* none */
1058
1059 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1060 count = 1; /* account for one byte pad to word boundary */
1061 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001062 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001063 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 name_len++; /* trailing null */
1065 name_len *= 2;
1066 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001067 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 count = 0; /* no pad */
1069 name_len = strnlen(fileName, PATH_MAX);
1070 name_len++; /* trailing null */
1071 pSMB->NameLength = cpu_to_le16(name_len);
1072 strncpy(pSMB->fileName, fileName, name_len);
1073 }
1074 if (*pOplock & REQ_OPLOCK)
1075 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1076 else if (*pOplock & REQ_BATCHOPLOCK) {
1077 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1078 }
1079 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1080 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001081 /* set file as system file if special file such
1082 as fifo and server expecting SFU style and
1083 no Unix extensions */
1084 if(create_options & CREATE_OPTION_SPECIAL)
1085 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1086 else
1087 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 /* XP does not handle ATTR_POSIX_SEMANTICS */
1089 /* but it helps speed up case sensitive checks for other
1090 servers such as Samba */
1091 if (tcon->ses->capabilities & CAP_UNIX)
1092 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1093
1094 /* if ((omode & S_IWUGO) == 0)
1095 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1096 /* Above line causes problems due to vfs splitting create into two
1097 pieces - need to set mode after file created not while it is
1098 being created */
1099 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1100 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001101 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001102 /* BB Expirement with various impersonation levels and verify */
1103 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 pSMB->SecurityFlags =
1105 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1106
1107 count += name_len;
1108 pSMB->hdr.smb_buf_length += count;
1109
1110 pSMB->ByteCount = cpu_to_le16(count);
1111 /* long_op set to 1 to allow for oplock break timeouts */
1112 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1113 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001114 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 if (rc) {
1116 cFYI(1, ("Error in Open = %d", rc));
1117 } else {
Steve French09d1db52005-04-28 22:41:08 -07001118 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1120 /* Let caller know file was created so we can set the mode. */
1121 /* Do we care about the CreateAction in any other cases? */
1122 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1123 *pOplock |= CIFS_CREATE_ACTION;
1124 if(pfile_info) {
1125 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1126 36 /* CreationTime to Attributes */);
1127 /* the file_info buf is endian converted by caller */
1128 pfile_info->AllocationSize = pSMBr->AllocationSize;
1129 pfile_info->EndOfFile = pSMBr->EndOfFile;
1130 pfile_info->NumberOfLinks = cpu_to_le32(1);
1131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 cifs_buf_release(pSMB);
1135 if (rc == -EAGAIN)
1136 goto openRetry;
1137 return rc;
1138}
1139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140int
1141CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001142 const int netfid, const unsigned int count,
1143 const __u64 lseek, unsigned int *nbytes, char **buf,
1144 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145{
1146 int rc = -EACCES;
1147 READ_REQ *pSMB = NULL;
1148 READ_RSP *pSMBr = NULL;
1149 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001150 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001151 int resp_buf_type = 0;
1152 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
1154 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001155 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1156 wct = 12;
1157 else
1158 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
1160 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001161 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 if (rc)
1163 return rc;
1164
1165 /* tcon and ses pointer are checked in smb_init */
1166 if (tcon->ses->server == NULL)
1167 return -ECONNABORTED;
1168
Steve Frenchec637e32005-12-12 20:53:18 -08001169 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 pSMB->Fid = netfid;
1171 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001172 if(wct == 12)
1173 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001174 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1175 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 pSMB->Remaining = 0;
1178 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1179 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001180 if(wct == 12)
1181 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1182 else {
1183 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001184 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001185 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001186 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001187 }
Steve Frenchec637e32005-12-12 20:53:18 -08001188
1189 iov[0].iov_base = (char *)pSMB;
1190 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1191 rc = SendReceive2(xid, tcon->ses, iov,
1192 1 /* num iovecs */,
1193 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001194 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001195 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 if (rc) {
1197 cERROR(1, ("Send error in read = %d", rc));
1198 } else {
1199 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1200 data_length = data_length << 16;
1201 data_length += le16_to_cpu(pSMBr->DataLength);
1202 *nbytes = data_length;
1203
1204 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001205 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 || (data_length > count)) {
1207 cFYI(1,("bad length %d for count %d",data_length,count));
1208 rc = -EIO;
1209 *nbytes = 0;
1210 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001211 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001213/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1214 cERROR(1,("Faulting on read rc = %d",rc));
1215 rc = -EFAULT;
1216 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001218 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 }
1220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
Steve French4b8f9302006-02-26 16:41:18 +00001222/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001223 if(*buf) {
1224 if(resp_buf_type == CIFS_SMALL_BUFFER)
1225 cifs_small_buf_release(iov[0].iov_base);
1226 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1227 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001228 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1229 /* return buffer to caller to free */
1230 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001231 if(resp_buf_type == CIFS_SMALL_BUFFER)
1232 *pbuf_type = CIFS_SMALL_BUFFER;
1233 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1234 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001235 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001236
1237 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 since file handle passed in no longer valid */
1239 return rc;
1240}
1241
Steve Frenchec637e32005-12-12 20:53:18 -08001242
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243int
1244CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1245 const int netfid, const unsigned int count,
1246 const __u64 offset, unsigned int *nbytes, const char *buf,
1247 const char __user * ubuf, const int long_op)
1248{
1249 int rc = -EACCES;
1250 WRITE_REQ *pSMB = NULL;
1251 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001252 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 __u32 bytes_sent;
1254 __u16 byte_count;
1255
1256 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001257 if(tcon->ses == NULL)
1258 return -ECONNABORTED;
1259
1260 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1261 wct = 14;
1262 else
1263 wct = 12;
1264
1265 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 (void **) &pSMBr);
1267 if (rc)
1268 return rc;
1269 /* tcon and ses pointer are checked in smb_init */
1270 if (tcon->ses->server == NULL)
1271 return -ECONNABORTED;
1272
1273 pSMB->AndXCommand = 0xFF; /* none */
1274 pSMB->Fid = netfid;
1275 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001276 if(wct == 14)
1277 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1278 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1279 return -EIO;
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 pSMB->Reserved = 0xFFFFFFFF;
1282 pSMB->WriteMode = 0;
1283 pSMB->Remaining = 0;
1284
1285 /* Can increase buffer size if buffer is big enough in some cases - ie we
1286 can send more if LARGE_WRITE_X capability returned by the server and if
1287 our buffer is big enough or if we convert to iovecs on socket writes
1288 and eliminate the copy to the CIFS buffer */
1289 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1290 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1291 } else {
1292 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1293 & ~0xFF;
1294 }
1295
1296 if (bytes_sent > count)
1297 bytes_sent = count;
1298 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001299 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if(buf)
1301 memcpy(pSMB->Data,buf,bytes_sent);
1302 else if(ubuf) {
1303 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1304 cifs_buf_release(pSMB);
1305 return -EFAULT;
1306 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001307 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 /* No buffer */
1309 cifs_buf_release(pSMB);
1310 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001311 } /* else setting file size with write of zero bytes */
1312 if(wct == 14)
1313 byte_count = bytes_sent + 1; /* pad */
1314 else /* wct == 12 */ {
1315 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1318 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001319 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001320
1321 if(wct == 14)
1322 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001323 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001324 struct smb_com_writex_req * pSMBW =
1325 (struct smb_com_writex_req *)pSMB;
1326 pSMBW->ByteCount = cpu_to_le16(byte_count);
1327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1330 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001331 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 if (rc) {
1333 cFYI(1, ("Send error in write = %d", rc));
1334 *nbytes = 0;
1335 } else {
1336 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1337 *nbytes = (*nbytes) << 16;
1338 *nbytes += le16_to_cpu(pSMBr->Count);
1339 }
1340
1341 cifs_buf_release(pSMB);
1342
1343 /* Note: On -EAGAIN error only caller can retry on handle based calls
1344 since file handle passed in no longer valid */
1345
1346 return rc;
1347}
1348
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001349int
1350CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001352 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1353 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354{
1355 int rc = -EACCES;
1356 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001357 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001358 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001359 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Steve Frenchff7feac2005-11-15 16:45:16 -08001361 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1362
Steve French8cc64c62005-10-03 13:49:43 -07001363 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1364 wct = 14;
1365 else
1366 wct = 12;
1367 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 if (rc)
1369 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 /* tcon and ses pointer are checked in smb_init */
1371 if (tcon->ses->server == NULL)
1372 return -ECONNABORTED;
1373
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001374 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 pSMB->Fid = netfid;
1376 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001377 if(wct == 14)
1378 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1379 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1380 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 pSMB->Reserved = 0xFFFFFFFF;
1382 pSMB->WriteMode = 0;
1383 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 pSMB->DataOffset =
1386 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1387
Steve French3e844692005-10-03 13:37:24 -07001388 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1389 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001390 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001391 if(wct == 14)
1392 pSMB->hdr.smb_buf_length += count+1;
1393 else /* wct == 12 */
1394 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1395 if(wct == 14)
1396 pSMB->ByteCount = cpu_to_le16(count + 1);
1397 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1398 struct smb_com_writex_req * pSMBW =
1399 (struct smb_com_writex_req *)pSMB;
1400 pSMBW->ByteCount = cpu_to_le16(count + 5);
1401 }
Steve French3e844692005-10-03 13:37:24 -07001402 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001403 if(wct == 14)
1404 iov[0].iov_len = smb_hdr_len + 4;
1405 else /* wct == 12 pad bigger by four bytes */
1406 iov[0].iov_len = smb_hdr_len + 8;
1407
Steve French3e844692005-10-03 13:37:24 -07001408
Steve Frenchec637e32005-12-12 20:53:18 -08001409 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001410 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001411 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001413 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001415 } else if(resp_buf_type == 0) {
1416 /* presumably this can not happen, but best to be safe */
1417 rc = -EIO;
1418 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001419 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001420 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001421 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1422 *nbytes = (*nbytes) << 16;
1423 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
Steve French4b8f9302006-02-26 16:41:18 +00001426/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001427 if(resp_buf_type == CIFS_SMALL_BUFFER)
1428 cifs_small_buf_release(iov[0].iov_base);
1429 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1430 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
1432 /* Note: On -EAGAIN error only caller can retry on handle based calls
1433 since file handle passed in no longer valid */
1434
1435 return rc;
1436}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001437
1438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439int
1440CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1441 const __u16 smb_file_id, const __u64 len,
1442 const __u64 offset, const __u32 numUnlock,
1443 const __u32 numLock, const __u8 lockType, const int waitFlag)
1444{
1445 int rc = 0;
1446 LOCK_REQ *pSMB = NULL;
1447 LOCK_RSP *pSMBr = NULL;
1448 int bytes_returned;
1449 int timeout = 0;
1450 __u16 count;
1451
1452 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001453 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 if (rc)
1456 return rc;
1457
Steve French46810cb2005-04-28 22:41:09 -07001458 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1461 timeout = -1; /* no response expected */
1462 pSMB->Timeout = 0;
1463 } else if (waitFlag == TRUE) {
1464 timeout = 3; /* blocking operation, no timeout */
1465 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1466 } else {
1467 pSMB->Timeout = 0;
1468 }
1469
1470 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1471 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1472 pSMB->LockType = lockType;
1473 pSMB->AndXCommand = 0xFF; /* none */
1474 pSMB->Fid = smb_file_id; /* netfid stays le */
1475
1476 if((numLock != 0) || (numUnlock != 0)) {
1477 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1478 /* BB where to store pid high? */
1479 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1480 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1481 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1482 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1483 count = sizeof(LOCKING_ANDX_RANGE);
1484 } else {
1485 /* oplock break */
1486 count = 0;
1487 }
1488 pSMB->hdr.smb_buf_length += count;
1489 pSMB->ByteCount = cpu_to_le16(count);
1490
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001491 if (waitFlag) {
1492 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1493 (struct smb_hdr *) pSMBr, &bytes_returned);
1494 } else {
1495 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001497 }
Steve Frencha4544342005-08-24 13:59:35 -07001498 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 if (rc) {
1500 cFYI(1, ("Send error in Lock = %d", rc));
1501 }
Steve French46810cb2005-04-28 22:41:09 -07001502 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
1504 /* Note: On -EAGAIN error only caller can retry on handle based calls
1505 since file handle passed in no longer valid */
1506 return rc;
1507}
1508
1509int
Steve French08547b02006-02-28 22:39:25 +00001510CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1511 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001512 struct file_lock *pLockData, const __u16 lock_type,
1513 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001514{
1515 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1516 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1517 char *data_offset;
1518 struct cifs_posix_lock *parm_data;
1519 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001520 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001521 int bytes_returned = 0;
1522 __u16 params, param_offset, offset, byte_count, count;
1523
1524 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001525
1526 if(pLockData == NULL)
1527 return EINVAL;
1528
Steve French08547b02006-02-28 22:39:25 +00001529 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1530
1531 if (rc)
1532 return rc;
1533
1534 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1535
1536 params = 6;
1537 pSMB->MaxSetupCount = 0;
1538 pSMB->Reserved = 0;
1539 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001540 pSMB->Reserved2 = 0;
1541 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1542 offset = param_offset + params;
1543
1544 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1545
1546 count = sizeof(struct cifs_posix_lock);
1547 pSMB->MaxParameterCount = cpu_to_le16(2);
1548 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1549 pSMB->SetupCount = 1;
1550 pSMB->Reserved3 = 0;
1551 if(get_flag)
1552 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1553 else
1554 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1555 byte_count = 3 /* pad */ + params + count;
1556 pSMB->DataCount = cpu_to_le16(count);
1557 pSMB->ParameterCount = cpu_to_le16(params);
1558 pSMB->TotalDataCount = pSMB->DataCount;
1559 pSMB->TotalParameterCount = pSMB->ParameterCount;
1560 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1561 parm_data = (struct cifs_posix_lock *)
1562 (((char *) &pSMB->hdr.Protocol) + offset);
1563
1564 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001565 if(waitFlag) {
1566 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001567 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001568 pSMB->Timeout = cpu_to_le32(-1);
1569 } else
1570 pSMB->Timeout = 0;
1571
Steve French08547b02006-02-28 22:39:25 +00001572 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001573 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001574 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001575
1576 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001577 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001578 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1579 pSMB->Reserved4 = 0;
1580 pSMB->hdr.smb_buf_length += byte_count;
1581 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001582 if (waitFlag) {
1583 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1584 (struct smb_hdr *) pSMBr, &bytes_returned);
1585 } else {
1586 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001587 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001588 }
1589
Steve French08547b02006-02-28 22:39:25 +00001590 if (rc) {
1591 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001592 } else if (get_flag) {
1593 /* lock structure can be returned on get */
1594 __u16 data_offset;
1595 __u16 data_count;
1596 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001597
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001598 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1599 rc = -EIO; /* bad smb */
1600 goto plk_err_exit;
1601 }
1602 if(pLockData == NULL) {
1603 rc = -EINVAL;
1604 goto plk_err_exit;
1605 }
1606 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1607 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1608 if(data_count < sizeof(struct cifs_posix_lock)) {
1609 rc = -EIO;
1610 goto plk_err_exit;
1611 }
1612 parm_data = (struct cifs_posix_lock *)
1613 ((char *)&pSMBr->hdr.Protocol + data_offset);
1614 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1615 pLockData->fl_type = F_UNLCK;
1616 }
1617
1618plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001619 if (pSMB)
1620 cifs_small_buf_release(pSMB);
1621
1622 /* Note: On -EAGAIN error only caller can retry on handle based calls
1623 since file handle passed in no longer valid */
1624
1625 return rc;
1626}
1627
1628
1629int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1631{
1632 int rc = 0;
1633 CLOSE_REQ *pSMB = NULL;
1634 CLOSE_RSP *pSMBr = NULL;
1635 int bytes_returned;
1636 cFYI(1, ("In CIFSSMBClose"));
1637
1638/* do not retry on dead session on close */
1639 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1640 if(rc == -EAGAIN)
1641 return 0;
1642 if (rc)
1643 return rc;
1644
1645 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1646
1647 pSMB->FileID = (__u16) smb_file_id;
1648 pSMB->LastWriteTime = 0;
1649 pSMB->ByteCount = 0;
1650 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1651 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001652 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 if (rc) {
1654 if(rc!=-EINTR) {
1655 /* EINTR is expected when user ctl-c to kill app */
1656 cERROR(1, ("Send error in Close = %d", rc));
1657 }
1658 }
1659
1660 cifs_small_buf_release(pSMB);
1661
1662 /* Since session is dead, file will be closed on server already */
1663 if(rc == -EAGAIN)
1664 rc = 0;
1665
1666 return rc;
1667}
1668
1669int
1670CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1671 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001672 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673{
1674 int rc = 0;
1675 RENAME_REQ *pSMB = NULL;
1676 RENAME_RSP *pSMBr = NULL;
1677 int bytes_returned;
1678 int name_len, name_len2;
1679 __u16 count;
1680
1681 cFYI(1, ("In CIFSSMBRename"));
1682renameRetry:
1683 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1684 (void **) &pSMBr);
1685 if (rc)
1686 return rc;
1687
1688 pSMB->BufferFormat = 0x04;
1689 pSMB->SearchAttributes =
1690 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1691 ATTR_DIRECTORY);
1692
1693 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1694 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001695 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001696 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 name_len++; /* trailing null */
1698 name_len *= 2;
1699 pSMB->OldFileName[name_len] = 0x04; /* pad */
1700 /* protocol requires ASCII signature byte on Unicode string */
1701 pSMB->OldFileName[name_len + 1] = 0x00;
1702 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001703 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001704 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1706 name_len2 *= 2; /* convert to bytes */
1707 } else { /* BB improve the check for buffer overruns BB */
1708 name_len = strnlen(fromName, PATH_MAX);
1709 name_len++; /* trailing null */
1710 strncpy(pSMB->OldFileName, fromName, name_len);
1711 name_len2 = strnlen(toName, PATH_MAX);
1712 name_len2++; /* trailing null */
1713 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1714 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1715 name_len2++; /* trailing null */
1716 name_len2++; /* signature byte */
1717 }
1718
1719 count = 1 /* 1st signature byte */ + name_len + name_len2;
1720 pSMB->hdr.smb_buf_length += count;
1721 pSMB->ByteCount = cpu_to_le16(count);
1722
1723 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001725 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (rc) {
1727 cFYI(1, ("Send error in rename = %d", rc));
1728 }
1729
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 cifs_buf_release(pSMB);
1731
1732 if (rc == -EAGAIN)
1733 goto renameRetry;
1734
1735 return rc;
1736}
1737
1738int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001739 int netfid, char * target_name,
1740 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741{
1742 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1743 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1744 struct set_file_rename * rename_info;
1745 char *data_offset;
1746 char dummy_string[30];
1747 int rc = 0;
1748 int bytes_returned = 0;
1749 int len_of_str;
1750 __u16 params, param_offset, offset, count, byte_count;
1751
1752 cFYI(1, ("Rename to File by handle"));
1753 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1754 (void **) &pSMBr);
1755 if (rc)
1756 return rc;
1757
1758 params = 6;
1759 pSMB->MaxSetupCount = 0;
1760 pSMB->Reserved = 0;
1761 pSMB->Flags = 0;
1762 pSMB->Timeout = 0;
1763 pSMB->Reserved2 = 0;
1764 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1765 offset = param_offset + params;
1766
1767 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1768 rename_info = (struct set_file_rename *) data_offset;
1769 pSMB->MaxParameterCount = cpu_to_le16(2);
1770 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1771 pSMB->SetupCount = 1;
1772 pSMB->Reserved3 = 0;
1773 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1774 byte_count = 3 /* pad */ + params;
1775 pSMB->ParameterCount = cpu_to_le16(params);
1776 pSMB->TotalParameterCount = pSMB->ParameterCount;
1777 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1778 pSMB->DataOffset = cpu_to_le16(offset);
1779 /* construct random name ".cifs_tmp<inodenum><mid>" */
1780 rename_info->overwrite = cpu_to_le32(1);
1781 rename_info->root_fid = 0;
1782 /* unicode only call */
1783 if(target_name == NULL) {
1784 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001785 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001786 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001788 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001789 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 }
1791 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1792 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1793 byte_count += count;
1794 pSMB->DataCount = cpu_to_le16(count);
1795 pSMB->TotalDataCount = pSMB->DataCount;
1796 pSMB->Fid = netfid;
1797 pSMB->InformationLevel =
1798 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1799 pSMB->Reserved4 = 0;
1800 pSMB->hdr.smb_buf_length += byte_count;
1801 pSMB->ByteCount = cpu_to_le16(byte_count);
1802 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1803 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001804 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 if (rc) {
1806 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1807 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 cifs_buf_release(pSMB);
1810
1811 /* Note: On -EAGAIN error only caller can retry on handle based calls
1812 since file handle passed in no longer valid */
1813
1814 return rc;
1815}
1816
1817int
1818CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1819 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001820 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821{
1822 int rc = 0;
1823 COPY_REQ *pSMB = NULL;
1824 COPY_RSP *pSMBr = NULL;
1825 int bytes_returned;
1826 int name_len, name_len2;
1827 __u16 count;
1828
1829 cFYI(1, ("In CIFSSMBCopy"));
1830copyRetry:
1831 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1832 (void **) &pSMBr);
1833 if (rc)
1834 return rc;
1835
1836 pSMB->BufferFormat = 0x04;
1837 pSMB->Tid2 = target_tid;
1838
1839 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1840
1841 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001842 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001843 fromName, PATH_MAX, nls_codepage,
1844 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 name_len++; /* trailing null */
1846 name_len *= 2;
1847 pSMB->OldFileName[name_len] = 0x04; /* pad */
1848 /* protocol requires ASCII signature byte on Unicode string */
1849 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001850 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001851 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1853 name_len2 *= 2; /* convert to bytes */
1854 } else { /* BB improve the check for buffer overruns BB */
1855 name_len = strnlen(fromName, PATH_MAX);
1856 name_len++; /* trailing null */
1857 strncpy(pSMB->OldFileName, fromName, name_len);
1858 name_len2 = strnlen(toName, PATH_MAX);
1859 name_len2++; /* trailing null */
1860 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1861 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1862 name_len2++; /* trailing null */
1863 name_len2++; /* signature byte */
1864 }
1865
1866 count = 1 /* 1st signature byte */ + name_len + name_len2;
1867 pSMB->hdr.smb_buf_length += count;
1868 pSMB->ByteCount = cpu_to_le16(count);
1869
1870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1872 if (rc) {
1873 cFYI(1, ("Send error in copy = %d with %d files copied",
1874 rc, le16_to_cpu(pSMBr->CopyCount)));
1875 }
1876 if (pSMB)
1877 cifs_buf_release(pSMB);
1878
1879 if (rc == -EAGAIN)
1880 goto copyRetry;
1881
1882 return rc;
1883}
1884
1885int
1886CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1887 const char *fromName, const char *toName,
1888 const struct nls_table *nls_codepage)
1889{
1890 TRANSACTION2_SPI_REQ *pSMB = NULL;
1891 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1892 char *data_offset;
1893 int name_len;
1894 int name_len_target;
1895 int rc = 0;
1896 int bytes_returned = 0;
1897 __u16 params, param_offset, offset, byte_count;
1898
1899 cFYI(1, ("In Symlink Unix style"));
1900createSymLinkRetry:
1901 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1902 (void **) &pSMBr);
1903 if (rc)
1904 return rc;
1905
1906 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1907 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001908 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 /* find define for this maxpathcomponent */
1910 , nls_codepage);
1911 name_len++; /* trailing null */
1912 name_len *= 2;
1913
1914 } else { /* BB improve the check for buffer overruns BB */
1915 name_len = strnlen(fromName, PATH_MAX);
1916 name_len++; /* trailing null */
1917 strncpy(pSMB->FileName, fromName, name_len);
1918 }
1919 params = 6 + name_len;
1920 pSMB->MaxSetupCount = 0;
1921 pSMB->Reserved = 0;
1922 pSMB->Flags = 0;
1923 pSMB->Timeout = 0;
1924 pSMB->Reserved2 = 0;
1925 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1926 InformationLevel) - 4;
1927 offset = param_offset + params;
1928
1929 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1930 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1931 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001932 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 /* find define for this maxpathcomponent */
1934 , nls_codepage);
1935 name_len_target++; /* trailing null */
1936 name_len_target *= 2;
1937 } else { /* BB improve the check for buffer overruns BB */
1938 name_len_target = strnlen(toName, PATH_MAX);
1939 name_len_target++; /* trailing null */
1940 strncpy(data_offset, toName, name_len_target);
1941 }
1942
1943 pSMB->MaxParameterCount = cpu_to_le16(2);
1944 /* BB find exact max on data count below from sess */
1945 pSMB->MaxDataCount = cpu_to_le16(1000);
1946 pSMB->SetupCount = 1;
1947 pSMB->Reserved3 = 0;
1948 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1949 byte_count = 3 /* pad */ + params + name_len_target;
1950 pSMB->DataCount = cpu_to_le16(name_len_target);
1951 pSMB->ParameterCount = cpu_to_le16(params);
1952 pSMB->TotalDataCount = pSMB->DataCount;
1953 pSMB->TotalParameterCount = pSMB->ParameterCount;
1954 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1955 pSMB->DataOffset = cpu_to_le16(offset);
1956 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1957 pSMB->Reserved4 = 0;
1958 pSMB->hdr.smb_buf_length += byte_count;
1959 pSMB->ByteCount = cpu_to_le16(byte_count);
1960 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1961 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001962 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (rc) {
1964 cFYI(1,
1965 ("Send error in SetPathInfo (create symlink) = %d",
1966 rc));
1967 }
1968
1969 if (pSMB)
1970 cifs_buf_release(pSMB);
1971
1972 if (rc == -EAGAIN)
1973 goto createSymLinkRetry;
1974
1975 return rc;
1976}
1977
1978int
1979CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1980 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001981 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982{
1983 TRANSACTION2_SPI_REQ *pSMB = NULL;
1984 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1985 char *data_offset;
1986 int name_len;
1987 int name_len_target;
1988 int rc = 0;
1989 int bytes_returned = 0;
1990 __u16 params, param_offset, offset, byte_count;
1991
1992 cFYI(1, ("In Create Hard link Unix style"));
1993createHardLinkRetry:
1994 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1995 (void **) &pSMBr);
1996 if (rc)
1997 return rc;
1998
1999 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002000 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002001 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 name_len++; /* trailing null */
2003 name_len *= 2;
2004
2005 } else { /* BB improve the check for buffer overruns BB */
2006 name_len = strnlen(toName, PATH_MAX);
2007 name_len++; /* trailing null */
2008 strncpy(pSMB->FileName, toName, name_len);
2009 }
2010 params = 6 + name_len;
2011 pSMB->MaxSetupCount = 0;
2012 pSMB->Reserved = 0;
2013 pSMB->Flags = 0;
2014 pSMB->Timeout = 0;
2015 pSMB->Reserved2 = 0;
2016 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2017 InformationLevel) - 4;
2018 offset = param_offset + params;
2019
2020 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2021 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2022 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002023 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002024 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 name_len_target++; /* trailing null */
2026 name_len_target *= 2;
2027 } else { /* BB improve the check for buffer overruns BB */
2028 name_len_target = strnlen(fromName, PATH_MAX);
2029 name_len_target++; /* trailing null */
2030 strncpy(data_offset, fromName, name_len_target);
2031 }
2032
2033 pSMB->MaxParameterCount = cpu_to_le16(2);
2034 /* BB find exact max on data count below from sess*/
2035 pSMB->MaxDataCount = cpu_to_le16(1000);
2036 pSMB->SetupCount = 1;
2037 pSMB->Reserved3 = 0;
2038 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2039 byte_count = 3 /* pad */ + params + name_len_target;
2040 pSMB->ParameterCount = cpu_to_le16(params);
2041 pSMB->TotalParameterCount = pSMB->ParameterCount;
2042 pSMB->DataCount = cpu_to_le16(name_len_target);
2043 pSMB->TotalDataCount = pSMB->DataCount;
2044 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2045 pSMB->DataOffset = cpu_to_le16(offset);
2046 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2047 pSMB->Reserved4 = 0;
2048 pSMB->hdr.smb_buf_length += byte_count;
2049 pSMB->ByteCount = cpu_to_le16(byte_count);
2050 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002052 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 if (rc) {
2054 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2055 }
2056
2057 cifs_buf_release(pSMB);
2058 if (rc == -EAGAIN)
2059 goto createHardLinkRetry;
2060
2061 return rc;
2062}
2063
2064int
2065CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2066 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002067 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068{
2069 int rc = 0;
2070 NT_RENAME_REQ *pSMB = NULL;
2071 RENAME_RSP *pSMBr = NULL;
2072 int bytes_returned;
2073 int name_len, name_len2;
2074 __u16 count;
2075
2076 cFYI(1, ("In CIFSCreateHardLink"));
2077winCreateHardLinkRetry:
2078
2079 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2080 (void **) &pSMBr);
2081 if (rc)
2082 return rc;
2083
2084 pSMB->SearchAttributes =
2085 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2086 ATTR_DIRECTORY);
2087 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2088 pSMB->ClusterCount = 0;
2089
2090 pSMB->BufferFormat = 0x04;
2091
2092 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2093 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002094 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002095 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 name_len++; /* trailing null */
2097 name_len *= 2;
2098 pSMB->OldFileName[name_len] = 0; /* pad */
2099 pSMB->OldFileName[name_len + 1] = 0x04;
2100 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002101 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002102 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2104 name_len2 *= 2; /* convert to bytes */
2105 } else { /* BB improve the check for buffer overruns BB */
2106 name_len = strnlen(fromName, PATH_MAX);
2107 name_len++; /* trailing null */
2108 strncpy(pSMB->OldFileName, fromName, name_len);
2109 name_len2 = strnlen(toName, PATH_MAX);
2110 name_len2++; /* trailing null */
2111 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2112 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2113 name_len2++; /* trailing null */
2114 name_len2++; /* signature byte */
2115 }
2116
2117 count = 1 /* string type byte */ + name_len + name_len2;
2118 pSMB->hdr.smb_buf_length += count;
2119 pSMB->ByteCount = cpu_to_le16(count);
2120
2121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002123 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 if (rc) {
2125 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2126 }
2127 cifs_buf_release(pSMB);
2128 if (rc == -EAGAIN)
2129 goto winCreateHardLinkRetry;
2130
2131 return rc;
2132}
2133
2134int
2135CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2136 const unsigned char *searchName,
2137 char *symlinkinfo, const int buflen,
2138 const struct nls_table *nls_codepage)
2139{
2140/* SMB_QUERY_FILE_UNIX_LINK */
2141 TRANSACTION2_QPI_REQ *pSMB = NULL;
2142 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2143 int rc = 0;
2144 int bytes_returned;
2145 int name_len;
2146 __u16 params, byte_count;
2147
2148 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2149
2150querySymLinkRetry:
2151 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2152 (void **) &pSMBr);
2153 if (rc)
2154 return rc;
2155
2156 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2157 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002158 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 /* find define for this maxpathcomponent */
2160 , nls_codepage);
2161 name_len++; /* trailing null */
2162 name_len *= 2;
2163 } else { /* BB improve the check for buffer overruns BB */
2164 name_len = strnlen(searchName, PATH_MAX);
2165 name_len++; /* trailing null */
2166 strncpy(pSMB->FileName, searchName, name_len);
2167 }
2168
2169 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2170 pSMB->TotalDataCount = 0;
2171 pSMB->MaxParameterCount = cpu_to_le16(2);
2172 /* BB find exact max data count below from sess structure BB */
2173 pSMB->MaxDataCount = cpu_to_le16(4000);
2174 pSMB->MaxSetupCount = 0;
2175 pSMB->Reserved = 0;
2176 pSMB->Flags = 0;
2177 pSMB->Timeout = 0;
2178 pSMB->Reserved2 = 0;
2179 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2180 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2181 pSMB->DataCount = 0;
2182 pSMB->DataOffset = 0;
2183 pSMB->SetupCount = 1;
2184 pSMB->Reserved3 = 0;
2185 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2186 byte_count = params + 1 /* pad */ ;
2187 pSMB->TotalParameterCount = cpu_to_le16(params);
2188 pSMB->ParameterCount = pSMB->TotalParameterCount;
2189 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2190 pSMB->Reserved4 = 0;
2191 pSMB->hdr.smb_buf_length += byte_count;
2192 pSMB->ByteCount = cpu_to_le16(byte_count);
2193
2194 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2195 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2196 if (rc) {
2197 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2198 } else {
2199 /* decode response */
2200
2201 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2202 if (rc || (pSMBr->ByteCount < 2))
2203 /* BB also check enough total bytes returned */
2204 rc = -EIO; /* bad smb */
2205 else {
2206 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2207 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2208
2209 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2210 name_len = UniStrnlen((wchar_t *) ((char *)
2211 &pSMBr->hdr.Protocol +data_offset),
2212 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002213 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002215 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 data_offset),
2217 name_len, nls_codepage);
2218 } else {
2219 strncpy(symlinkinfo,
2220 (char *) &pSMBr->hdr.Protocol +
2221 data_offset,
2222 min_t(const int, buflen, count));
2223 }
2224 symlinkinfo[buflen] = 0;
2225 /* just in case so calling code does not go off the end of buffer */
2226 }
2227 }
2228 cifs_buf_release(pSMB);
2229 if (rc == -EAGAIN)
2230 goto querySymLinkRetry;
2231 return rc;
2232}
2233
Steve French0a4b92c2006-01-12 15:44:21 -08002234/* Initialize NT TRANSACT SMB into small smb request buffer.
2235 This assumes that all NT TRANSACTS that we init here have
2236 total parm and data under about 400 bytes (to fit in small cifs
2237 buffer size), which is the case so far, it easily fits. NB:
2238 Setup words themselves and ByteCount
2239 MaxSetupCount (size of returned setup area) and
2240 MaxParameterCount (returned parms size) must be set by caller */
2241static int
2242smb_init_ntransact(const __u16 sub_command, const int setup_count,
2243 const int parm_len, struct cifsTconInfo *tcon,
2244 void ** ret_buf)
2245{
2246 int rc;
2247 __u32 temp_offset;
2248 struct smb_com_ntransact_req * pSMB;
2249
2250 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2251 (void **)&pSMB);
2252 if (rc)
2253 return rc;
2254 *ret_buf = (void *)pSMB;
2255 pSMB->Reserved = 0;
2256 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2257 pSMB->TotalDataCount = 0;
2258 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2259 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2260 pSMB->ParameterCount = pSMB->TotalParameterCount;
2261 pSMB->DataCount = pSMB->TotalDataCount;
2262 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2263 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2264 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2265 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2266 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2267 pSMB->SubCommand = cpu_to_le16(sub_command);
2268 return 0;
2269}
2270
2271static int
2272validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2273 int * pdatalen, int * pparmlen)
2274{
2275 char * end_of_smb;
2276 __u32 data_count, data_offset, parm_count, parm_offset;
2277 struct smb_com_ntransact_rsp * pSMBr;
2278
2279 if(buf == NULL)
2280 return -EINVAL;
2281
2282 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2283
2284 /* ByteCount was converted from little endian in SendReceive */
2285 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2286 (char *)&pSMBr->ByteCount;
2287
2288
2289 data_offset = le32_to_cpu(pSMBr->DataOffset);
2290 data_count = le32_to_cpu(pSMBr->DataCount);
2291 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2292 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2293
2294 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2295 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2296
2297 /* should we also check that parm and data areas do not overlap? */
2298 if(*ppparm > end_of_smb) {
2299 cFYI(1,("parms start after end of smb"));
2300 return -EINVAL;
2301 } else if(parm_count + *ppparm > end_of_smb) {
2302 cFYI(1,("parm end after end of smb"));
2303 return -EINVAL;
2304 } else if(*ppdata > end_of_smb) {
2305 cFYI(1,("data starts after end of smb"));
2306 return -EINVAL;
2307 } else if(data_count + *ppdata > end_of_smb) {
2308 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2309 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2310 return -EINVAL;
2311 } else if(parm_count + data_count > pSMBr->ByteCount) {
2312 cFYI(1,("parm count and data count larger than SMB"));
2313 return -EINVAL;
2314 }
2315 return 0;
2316}
2317
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318int
2319CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2320 const unsigned char *searchName,
2321 char *symlinkinfo, const int buflen,__u16 fid,
2322 const struct nls_table *nls_codepage)
2323{
2324 int rc = 0;
2325 int bytes_returned;
2326 int name_len;
2327 struct smb_com_transaction_ioctl_req * pSMB;
2328 struct smb_com_transaction_ioctl_rsp * pSMBr;
2329
2330 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2331 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2332 (void **) &pSMBr);
2333 if (rc)
2334 return rc;
2335
2336 pSMB->TotalParameterCount = 0 ;
2337 pSMB->TotalDataCount = 0;
2338 pSMB->MaxParameterCount = cpu_to_le32(2);
2339 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002340 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2341 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 pSMB->MaxSetupCount = 4;
2343 pSMB->Reserved = 0;
2344 pSMB->ParameterOffset = 0;
2345 pSMB->DataCount = 0;
2346 pSMB->DataOffset = 0;
2347 pSMB->SetupCount = 4;
2348 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2349 pSMB->ParameterCount = pSMB->TotalParameterCount;
2350 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2351 pSMB->IsFsctl = 1; /* FSCTL */
2352 pSMB->IsRootFlag = 0;
2353 pSMB->Fid = fid; /* file handle always le */
2354 pSMB->ByteCount = 0;
2355
2356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2358 if (rc) {
2359 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2360 } else { /* decode response */
2361 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2362 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2363 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2364 /* BB also check enough total bytes returned */
2365 rc = -EIO; /* bad smb */
2366 else {
2367 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002368 char * end_of_smb = 2 /* sizeof byte count */ +
2369 pSMBr->ByteCount +
2370 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
2372 struct reparse_data * reparse_buf = (struct reparse_data *)
2373 ((char *)&pSMBr->hdr.Protocol + data_offset);
2374 if((char*)reparse_buf >= end_of_smb) {
2375 rc = -EIO;
2376 goto qreparse_out;
2377 }
2378 if((reparse_buf->LinkNamesBuf +
2379 reparse_buf->TargetNameOffset +
2380 reparse_buf->TargetNameLen) >
2381 end_of_smb) {
2382 cFYI(1,("reparse buf extended beyond SMB"));
2383 rc = -EIO;
2384 goto qreparse_out;
2385 }
2386
2387 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2388 name_len = UniStrnlen((wchar_t *)
2389 (reparse_buf->LinkNamesBuf +
2390 reparse_buf->TargetNameOffset),
2391 min(buflen/2, reparse_buf->TargetNameLen / 2));
2392 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002393 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 reparse_buf->TargetNameOffset),
2395 name_len, nls_codepage);
2396 } else { /* ASCII names */
2397 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2398 reparse_buf->TargetNameOffset,
2399 min_t(const int, buflen, reparse_buf->TargetNameLen));
2400 }
2401 } else {
2402 rc = -EIO;
2403 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2404 }
2405 symlinkinfo[buflen] = 0; /* just in case so the caller
2406 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002407 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 }
2409 }
2410qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002411 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413 /* Note: On -EAGAIN error only caller can retry on handle based calls
2414 since file handle passed in no longer valid */
2415
2416 return rc;
2417}
2418
2419#ifdef CONFIG_CIFS_POSIX
2420
2421/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2422static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2423{
2424 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002425 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2426 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2427 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2429
2430 return;
2431}
2432
2433/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002434static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2435 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436{
2437 int size = 0;
2438 int i;
2439 __u16 count;
2440 struct cifs_posix_ace * pACE;
2441 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2442 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2443
2444 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2445 return -EOPNOTSUPP;
2446
2447 if(acl_type & ACL_TYPE_ACCESS) {
2448 count = le16_to_cpu(cifs_acl->access_entry_count);
2449 pACE = &cifs_acl->ace_array[0];
2450 size = sizeof(struct cifs_posix_acl);
2451 size += sizeof(struct cifs_posix_ace) * count;
2452 /* check if we would go beyond end of SMB */
2453 if(size_of_data_area < size) {
2454 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2455 return -EINVAL;
2456 }
2457 } else if(acl_type & ACL_TYPE_DEFAULT) {
2458 count = le16_to_cpu(cifs_acl->access_entry_count);
2459 size = sizeof(struct cifs_posix_acl);
2460 size += sizeof(struct cifs_posix_ace) * count;
2461/* skip past access ACEs to get to default ACEs */
2462 pACE = &cifs_acl->ace_array[count];
2463 count = le16_to_cpu(cifs_acl->default_entry_count);
2464 size += sizeof(struct cifs_posix_ace) * count;
2465 /* check if we would go beyond end of SMB */
2466 if(size_of_data_area < size)
2467 return -EINVAL;
2468 } else {
2469 /* illegal type */
2470 return -EINVAL;
2471 }
2472
2473 size = posix_acl_xattr_size(count);
2474 if((buflen == 0) || (local_acl == NULL)) {
2475 /* used to query ACL EA size */
2476 } else if(size > buflen) {
2477 return -ERANGE;
2478 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002479 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 for(i = 0;i < count ;i++) {
2481 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2482 pACE ++;
2483 }
2484 }
2485 return size;
2486}
2487
2488static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2489 const posix_acl_xattr_entry * local_ace)
2490{
2491 __u16 rc = 0; /* 0 = ACL converted ok */
2492
Steve Frenchff7feac2005-11-15 16:45:16 -08002493 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2494 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002496 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 /* Probably no need to le convert -1 on any arch but can not hurt */
2498 cifs_ace->cifs_uid = cpu_to_le64(-1);
2499 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002500 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2502 return rc;
2503}
2504
2505/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2506static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2507 const int acl_type)
2508{
2509 __u16 rc = 0;
2510 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2511 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2512 int count;
2513 int i;
2514
2515 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2516 return 0;
2517
2518 count = posix_acl_xattr_count((size_t)buflen);
2519 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002520 count, buflen, le32_to_cpu(local_acl->a_version)));
2521 if(le32_to_cpu(local_acl->a_version) != 2) {
2522 cFYI(1,("unknown POSIX ACL version %d",
2523 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 return 0;
2525 }
2526 cifs_acl->version = cpu_to_le16(1);
2527 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002528 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002530 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 else {
2532 cFYI(1,("unknown ACL type %d",acl_type));
2533 return 0;
2534 }
2535 for(i=0;i<count;i++) {
2536 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2537 &local_acl->a_entries[i]);
2538 if(rc != 0) {
2539 /* ACE not converted */
2540 break;
2541 }
2542 }
2543 if(rc == 0) {
2544 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2545 rc += sizeof(struct cifs_posix_acl);
2546 /* BB add check to make sure ACL does not overflow SMB */
2547 }
2548 return rc;
2549}
2550
2551int
2552CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2553 const unsigned char *searchName,
2554 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002555 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556{
2557/* SMB_QUERY_POSIX_ACL */
2558 TRANSACTION2_QPI_REQ *pSMB = NULL;
2559 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2560 int rc = 0;
2561 int bytes_returned;
2562 int name_len;
2563 __u16 params, byte_count;
2564
2565 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2566
2567queryAclRetry:
2568 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2569 (void **) &pSMBr);
2570 if (rc)
2571 return rc;
2572
2573 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2574 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002575 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002576 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 name_len++; /* trailing null */
2578 name_len *= 2;
2579 pSMB->FileName[name_len] = 0;
2580 pSMB->FileName[name_len+1] = 0;
2581 } else { /* BB improve the check for buffer overruns BB */
2582 name_len = strnlen(searchName, PATH_MAX);
2583 name_len++; /* trailing null */
2584 strncpy(pSMB->FileName, searchName, name_len);
2585 }
2586
2587 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2588 pSMB->TotalDataCount = 0;
2589 pSMB->MaxParameterCount = cpu_to_le16(2);
2590 /* BB find exact max data count below from sess structure BB */
2591 pSMB->MaxDataCount = cpu_to_le16(4000);
2592 pSMB->MaxSetupCount = 0;
2593 pSMB->Reserved = 0;
2594 pSMB->Flags = 0;
2595 pSMB->Timeout = 0;
2596 pSMB->Reserved2 = 0;
2597 pSMB->ParameterOffset = cpu_to_le16(
2598 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2599 pSMB->DataCount = 0;
2600 pSMB->DataOffset = 0;
2601 pSMB->SetupCount = 1;
2602 pSMB->Reserved3 = 0;
2603 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2604 byte_count = params + 1 /* pad */ ;
2605 pSMB->TotalParameterCount = cpu_to_le16(params);
2606 pSMB->ParameterCount = pSMB->TotalParameterCount;
2607 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2608 pSMB->Reserved4 = 0;
2609 pSMB->hdr.smb_buf_length += byte_count;
2610 pSMB->ByteCount = cpu_to_le16(byte_count);
2611
2612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002614 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 if (rc) {
2616 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2617 } else {
2618 /* decode response */
2619
2620 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2621 if (rc || (pSMBr->ByteCount < 2))
2622 /* BB also check enough total bytes returned */
2623 rc = -EIO; /* bad smb */
2624 else {
2625 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2626 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2627 rc = cifs_copy_posix_acl(acl_inf,
2628 (char *)&pSMBr->hdr.Protocol+data_offset,
2629 buflen,acl_type,count);
2630 }
2631 }
2632 cifs_buf_release(pSMB);
2633 if (rc == -EAGAIN)
2634 goto queryAclRetry;
2635 return rc;
2636}
2637
2638int
2639CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2640 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002641 const char *local_acl, const int buflen,
2642 const int acl_type,
2643 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644{
2645 struct smb_com_transaction2_spi_req *pSMB = NULL;
2646 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2647 char *parm_data;
2648 int name_len;
2649 int rc = 0;
2650 int bytes_returned = 0;
2651 __u16 params, byte_count, data_count, param_offset, offset;
2652
2653 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2654setAclRetry:
2655 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2656 (void **) &pSMBr);
2657 if (rc)
2658 return rc;
2659 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2660 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002661 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002662 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 name_len++; /* trailing null */
2664 name_len *= 2;
2665 } else { /* BB improve the check for buffer overruns BB */
2666 name_len = strnlen(fileName, PATH_MAX);
2667 name_len++; /* trailing null */
2668 strncpy(pSMB->FileName, fileName, name_len);
2669 }
2670 params = 6 + name_len;
2671 pSMB->MaxParameterCount = cpu_to_le16(2);
2672 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2673 pSMB->MaxSetupCount = 0;
2674 pSMB->Reserved = 0;
2675 pSMB->Flags = 0;
2676 pSMB->Timeout = 0;
2677 pSMB->Reserved2 = 0;
2678 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2679 InformationLevel) - 4;
2680 offset = param_offset + params;
2681 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2682 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2683
2684 /* convert to on the wire format for POSIX ACL */
2685 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2686
2687 if(data_count == 0) {
2688 rc = -EOPNOTSUPP;
2689 goto setACLerrorExit;
2690 }
2691 pSMB->DataOffset = cpu_to_le16(offset);
2692 pSMB->SetupCount = 1;
2693 pSMB->Reserved3 = 0;
2694 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2695 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2696 byte_count = 3 /* pad */ + params + data_count;
2697 pSMB->DataCount = cpu_to_le16(data_count);
2698 pSMB->TotalDataCount = pSMB->DataCount;
2699 pSMB->ParameterCount = cpu_to_le16(params);
2700 pSMB->TotalParameterCount = pSMB->ParameterCount;
2701 pSMB->Reserved4 = 0;
2702 pSMB->hdr.smb_buf_length += byte_count;
2703 pSMB->ByteCount = cpu_to_le16(byte_count);
2704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2706 if (rc) {
2707 cFYI(1, ("Set POSIX ACL returned %d", rc));
2708 }
2709
2710setACLerrorExit:
2711 cifs_buf_release(pSMB);
2712 if (rc == -EAGAIN)
2713 goto setAclRetry;
2714 return rc;
2715}
2716
Steve Frenchf654bac2005-04-28 22:41:04 -07002717/* BB fix tabs in this function FIXME BB */
2718int
2719CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2720 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2721{
2722 int rc = 0;
2723 struct smb_t2_qfi_req *pSMB = NULL;
2724 struct smb_t2_qfi_rsp *pSMBr = NULL;
2725 int bytes_returned;
2726 __u16 params, byte_count;
2727
2728 cFYI(1,("In GetExtAttr"));
2729 if(tcon == NULL)
2730 return -ENODEV;
2731
2732GetExtAttrRetry:
2733 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2734 (void **) &pSMBr);
2735 if (rc)
2736 return rc;
2737
Steve Frenchc67593a2005-04-28 22:41:04 -07002738 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002739 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002740 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002741 /* BB find exact max data count below from sess structure BB */
2742 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2743 pSMB->t2.MaxSetupCount = 0;
2744 pSMB->t2.Reserved = 0;
2745 pSMB->t2.Flags = 0;
2746 pSMB->t2.Timeout = 0;
2747 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002748 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2749 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002750 pSMB->t2.DataCount = 0;
2751 pSMB->t2.DataOffset = 0;
2752 pSMB->t2.SetupCount = 1;
2753 pSMB->t2.Reserved3 = 0;
2754 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002755 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002756 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2757 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2758 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002759 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002760 pSMB->Fid = netfid;
2761 pSMB->hdr.smb_buf_length += byte_count;
2762 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2763
2764 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2765 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2766 if (rc) {
2767 cFYI(1, ("error %d in GetExtAttr", rc));
2768 } else {
2769 /* decode response */
2770 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2771 if (rc || (pSMBr->ByteCount < 2))
2772 /* BB also check enough total bytes returned */
2773 /* If rc should we check for EOPNOSUPP and
2774 disable the srvino flag? or in caller? */
2775 rc = -EIO; /* bad smb */
2776 else {
2777 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2778 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2779 struct file_chattr_info * pfinfo;
2780 /* BB Do we need a cast or hash here ? */
2781 if(count != 16) {
2782 cFYI(1, ("Illegal size ret in GetExtAttr"));
2783 rc = -EIO;
2784 goto GetExtAttrOut;
2785 }
2786 pfinfo = (struct file_chattr_info *)
2787 (data_offset + (char *) &pSMBr->hdr.Protocol);
2788 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2789 *pMask = le64_to_cpu(pfinfo->mask);
2790 }
2791 }
2792GetExtAttrOut:
2793 cifs_buf_release(pSMB);
2794 if (rc == -EAGAIN)
2795 goto GetExtAttrRetry;
2796 return rc;
2797}
2798
2799
2800#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Steve Frencheeac8042006-01-13 21:34:58 -08002802
2803/* security id for everyone */
Steve French2cd646a2006-09-28 19:43:08 +00002804const static struct cifs_sid sid_everyone =
2805 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002806/* group users */
Steve French2cd646a2006-09-28 19:43:08 +00002807const static struct cifs_sid sid_user =
2808 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002809
Steve French0a4b92c2006-01-12 15:44:21 -08002810/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002811static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002812{
Steve French0a4b92c2006-01-12 15:44:21 -08002813 return 0;
2814}
2815
2816/* Get Security Descriptor (by handle) from remote server for a file or dir */
2817int
2818CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2819 /* BB fix up return info */ char *acl_inf, const int buflen,
2820 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2821{
2822 int rc = 0;
2823 int buf_type = 0;
2824 QUERY_SEC_DESC_REQ * pSMB;
2825 struct kvec iov[1];
2826
2827 cFYI(1, ("GetCifsACL"));
2828
2829 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2830 8 /* parm len */, tcon, (void **) &pSMB);
2831 if (rc)
2832 return rc;
2833
2834 pSMB->MaxParameterCount = cpu_to_le32(4);
2835 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2836 pSMB->MaxSetupCount = 0;
2837 pSMB->Fid = fid; /* file handle always le */
2838 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2839 CIFS_ACL_DACL);
2840 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2841 pSMB->hdr.smb_buf_length += 11;
2842 iov[0].iov_base = (char *)pSMB;
2843 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2844
2845 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2846 cifs_stats_inc(&tcon->num_acl_get);
2847 if (rc) {
2848 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2849 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002850 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002851 __le32 * parm;
2852 int parm_len;
2853 int data_len;
2854 int acl_len;
2855 struct smb_com_ntransact_rsp * pSMBr;
2856
2857/* validate_nttransact */
2858 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2859 (char **)&psec_desc,
2860 &parm_len, &data_len);
2861
2862 if(rc)
2863 goto qsec_out;
2864 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2865
2866 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2867
2868 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2869 rc = -EIO; /* bad smb */
2870 goto qsec_out;
2871 }
2872
2873/* BB check that data area is minimum length and as big as acl_len */
2874
2875 acl_len = le32_to_cpu(*(__le32 *)parm);
2876 /* BB check if(acl_len > bufsize) */
2877
2878 parse_sec_desc(psec_desc, acl_len);
2879 }
2880qsec_out:
2881 if(buf_type == CIFS_SMALL_BUFFER)
2882 cifs_small_buf_release(iov[0].iov_base);
2883 else if(buf_type == CIFS_LARGE_BUFFER)
2884 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002885/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002886 return rc;
2887}
2888
Steve French6b8edfe2005-08-23 20:26:03 -07002889/* Legacy Query Path Information call for lookup to old servers such
2890 as Win9x/WinME */
2891int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2892 const unsigned char *searchName,
2893 FILE_ALL_INFO * pFinfo,
2894 const struct nls_table *nls_codepage, int remap)
2895{
2896 QUERY_INFORMATION_REQ * pSMB;
2897 QUERY_INFORMATION_RSP * pSMBr;
2898 int rc = 0;
2899 int bytes_returned;
2900 int name_len;
2901
2902 cFYI(1, ("In SMBQPath path %s", searchName));
2903QInfRetry:
2904 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2905 (void **) &pSMBr);
2906 if (rc)
2907 return rc;
2908
2909 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2910 name_len =
2911 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2912 PATH_MAX, nls_codepage, remap);
2913 name_len++; /* trailing null */
2914 name_len *= 2;
2915 } else {
2916 name_len = strnlen(searchName, PATH_MAX);
2917 name_len++; /* trailing null */
2918 strncpy(pSMB->FileName, searchName, name_len);
2919 }
2920 pSMB->BufferFormat = 0x04;
2921 name_len++; /* account for buffer type byte */
2922 pSMB->hdr.smb_buf_length += (__u16) name_len;
2923 pSMB->ByteCount = cpu_to_le16(name_len);
2924
2925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2927 if (rc) {
2928 cFYI(1, ("Send error in QueryInfo = %d", rc));
2929 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00002930 struct timespec ts;
2931 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2932 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07002933 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00002934 ts.tv_nsec = 0;
2935 ts.tv_sec = time;
2936 /* decode time fields */
2937 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2938 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2939 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07002940 pFinfo->AllocationSize =
2941 cpu_to_le64(le32_to_cpu(pSMBr->size));
2942 pFinfo->EndOfFile = pFinfo->AllocationSize;
2943 pFinfo->Attributes =
2944 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002945 } else
2946 rc = -EIO; /* bad buffer passed in */
2947
2948 cifs_buf_release(pSMB);
2949
2950 if (rc == -EAGAIN)
2951 goto QInfRetry;
2952
2953 return rc;
2954}
2955
2956
2957
2958
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959int
2960CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2961 const unsigned char *searchName,
2962 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002963 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964{
2965/* level 263 SMB_QUERY_FILE_ALL_INFO */
2966 TRANSACTION2_QPI_REQ *pSMB = NULL;
2967 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2968 int rc = 0;
2969 int bytes_returned;
2970 int name_len;
2971 __u16 params, byte_count;
2972
2973/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2974QPathInfoRetry:
2975 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2976 (void **) &pSMBr);
2977 if (rc)
2978 return rc;
2979
2980 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2981 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002982 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002983 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 name_len++; /* trailing null */
2985 name_len *= 2;
2986 } else { /* BB improve the check for buffer overruns BB */
2987 name_len = strnlen(searchName, PATH_MAX);
2988 name_len++; /* trailing null */
2989 strncpy(pSMB->FileName, searchName, name_len);
2990 }
2991
2992 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2993 pSMB->TotalDataCount = 0;
2994 pSMB->MaxParameterCount = cpu_to_le16(2);
2995 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2996 pSMB->MaxSetupCount = 0;
2997 pSMB->Reserved = 0;
2998 pSMB->Flags = 0;
2999 pSMB->Timeout = 0;
3000 pSMB->Reserved2 = 0;
3001 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3002 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3003 pSMB->DataCount = 0;
3004 pSMB->DataOffset = 0;
3005 pSMB->SetupCount = 1;
3006 pSMB->Reserved3 = 0;
3007 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3008 byte_count = params + 1 /* pad */ ;
3009 pSMB->TotalParameterCount = cpu_to_le16(params);
3010 pSMB->ParameterCount = pSMB->TotalParameterCount;
3011 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3012 pSMB->Reserved4 = 0;
3013 pSMB->hdr.smb_buf_length += byte_count;
3014 pSMB->ByteCount = cpu_to_le16(byte_count);
3015
3016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3018 if (rc) {
3019 cFYI(1, ("Send error in QPathInfo = %d", rc));
3020 } else { /* decode response */
3021 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3022
3023 if (rc || (pSMBr->ByteCount < 40))
3024 rc = -EIO; /* bad smb */
3025 else if (pFindData){
3026 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3027 memcpy((char *) pFindData,
3028 (char *) &pSMBr->hdr.Protocol +
3029 data_offset, sizeof (FILE_ALL_INFO));
3030 } else
3031 rc = -ENOMEM;
3032 }
3033 cifs_buf_release(pSMB);
3034 if (rc == -EAGAIN)
3035 goto QPathInfoRetry;
3036
3037 return rc;
3038}
3039
3040int
3041CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3042 const unsigned char *searchName,
3043 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003044 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045{
3046/* SMB_QUERY_FILE_UNIX_BASIC */
3047 TRANSACTION2_QPI_REQ *pSMB = NULL;
3048 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3049 int rc = 0;
3050 int bytes_returned = 0;
3051 int name_len;
3052 __u16 params, byte_count;
3053
3054 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3055UnixQPathInfoRetry:
3056 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3057 (void **) &pSMBr);
3058 if (rc)
3059 return rc;
3060
3061 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3062 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003063 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003064 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 name_len++; /* trailing null */
3066 name_len *= 2;
3067 } else { /* BB improve the check for buffer overruns BB */
3068 name_len = strnlen(searchName, PATH_MAX);
3069 name_len++; /* trailing null */
3070 strncpy(pSMB->FileName, searchName, name_len);
3071 }
3072
3073 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3074 pSMB->TotalDataCount = 0;
3075 pSMB->MaxParameterCount = cpu_to_le16(2);
3076 /* BB find exact max SMB PDU from sess structure BB */
3077 pSMB->MaxDataCount = cpu_to_le16(4000);
3078 pSMB->MaxSetupCount = 0;
3079 pSMB->Reserved = 0;
3080 pSMB->Flags = 0;
3081 pSMB->Timeout = 0;
3082 pSMB->Reserved2 = 0;
3083 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3084 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3085 pSMB->DataCount = 0;
3086 pSMB->DataOffset = 0;
3087 pSMB->SetupCount = 1;
3088 pSMB->Reserved3 = 0;
3089 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3090 byte_count = params + 1 /* pad */ ;
3091 pSMB->TotalParameterCount = cpu_to_le16(params);
3092 pSMB->ParameterCount = pSMB->TotalParameterCount;
3093 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3094 pSMB->Reserved4 = 0;
3095 pSMB->hdr.smb_buf_length += byte_count;
3096 pSMB->ByteCount = cpu_to_le16(byte_count);
3097
3098 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3100 if (rc) {
3101 cFYI(1, ("Send error in QPathInfo = %d", rc));
3102 } else { /* decode response */
3103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3104
3105 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3106 rc = -EIO; /* bad smb */
3107 } else {
3108 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3109 memcpy((char *) pFindData,
3110 (char *) &pSMBr->hdr.Protocol +
3111 data_offset,
3112 sizeof (FILE_UNIX_BASIC_INFO));
3113 }
3114 }
3115 cifs_buf_release(pSMB);
3116 if (rc == -EAGAIN)
3117 goto UnixQPathInfoRetry;
3118
3119 return rc;
3120}
3121
3122#if 0 /* function unused at present */
3123int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3124 const char *searchName, FILE_ALL_INFO * findData,
3125 const struct nls_table *nls_codepage)
3126{
3127/* level 257 SMB_ */
3128 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3129 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3130 int rc = 0;
3131 int bytes_returned;
3132 int name_len;
3133 __u16 params, byte_count;
3134
3135 cFYI(1, ("In FindUnique"));
3136findUniqueRetry:
3137 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3138 (void **) &pSMBr);
3139 if (rc)
3140 return rc;
3141
3142 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3143 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003144 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 /* find define for this maxpathcomponent */
3146 , nls_codepage);
3147 name_len++; /* trailing null */
3148 name_len *= 2;
3149 } else { /* BB improve the check for buffer overruns BB */
3150 name_len = strnlen(searchName, PATH_MAX);
3151 name_len++; /* trailing null */
3152 strncpy(pSMB->FileName, searchName, name_len);
3153 }
3154
3155 params = 12 + name_len /* includes null */ ;
3156 pSMB->TotalDataCount = 0; /* no EAs */
3157 pSMB->MaxParameterCount = cpu_to_le16(2);
3158 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3159 pSMB->MaxSetupCount = 0;
3160 pSMB->Reserved = 0;
3161 pSMB->Flags = 0;
3162 pSMB->Timeout = 0;
3163 pSMB->Reserved2 = 0;
3164 pSMB->ParameterOffset = cpu_to_le16(
3165 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3166 pSMB->DataCount = 0;
3167 pSMB->DataOffset = 0;
3168 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3169 pSMB->Reserved3 = 0;
3170 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3171 byte_count = params + 1 /* pad */ ;
3172 pSMB->TotalParameterCount = cpu_to_le16(params);
3173 pSMB->ParameterCount = pSMB->TotalParameterCount;
3174 pSMB->SearchAttributes =
3175 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3176 ATTR_DIRECTORY);
3177 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3178 pSMB->SearchFlags = cpu_to_le16(1);
3179 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3180 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3181 pSMB->hdr.smb_buf_length += byte_count;
3182 pSMB->ByteCount = cpu_to_le16(byte_count);
3183
3184 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3185 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3186
3187 if (rc) {
3188 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3189 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003190 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 /* BB fill in */
3192 }
3193
3194 cifs_buf_release(pSMB);
3195 if (rc == -EAGAIN)
3196 goto findUniqueRetry;
3197
3198 return rc;
3199}
3200#endif /* end unused (temporarily) function */
3201
3202/* xid, tcon, searchName and codepage are input parms, rest are returned */
3203int
3204CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3205 const char *searchName,
3206 const struct nls_table *nls_codepage,
3207 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003208 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209{
3210/* level 257 SMB_ */
3211 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3212 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3213 T2_FFIRST_RSP_PARMS * parms;
3214 int rc = 0;
3215 int bytes_returned = 0;
3216 int name_len;
3217 __u16 params, byte_count;
3218
Steve French737b7582005-04-28 22:41:06 -07003219 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
3221findFirstRetry:
3222 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3223 (void **) &pSMBr);
3224 if (rc)
3225 return rc;
3226
3227 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3228 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003229 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003230 PATH_MAX, nls_codepage, remap);
3231 /* We can not add the asterik earlier in case
3232 it got remapped to 0xF03A as if it were part of the
3233 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003235 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003236 pSMB->FileName[name_len+1] = 0;
3237 pSMB->FileName[name_len+2] = '*';
3238 pSMB->FileName[name_len+3] = 0;
3239 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3241 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003242 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 } else { /* BB add check for overrun of SMB buf BB */
3244 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245/* BB fix here and in unicode clause above ie
3246 if(name_len > buffersize-header)
3247 free buffer exit; BB */
3248 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003249 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003250 pSMB->FileName[name_len+1] = '*';
3251 pSMB->FileName[name_len+2] = 0;
3252 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 }
3254
3255 params = 12 + name_len /* includes null */ ;
3256 pSMB->TotalDataCount = 0; /* no EAs */
3257 pSMB->MaxParameterCount = cpu_to_le16(10);
3258 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3259 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3260 pSMB->MaxSetupCount = 0;
3261 pSMB->Reserved = 0;
3262 pSMB->Flags = 0;
3263 pSMB->Timeout = 0;
3264 pSMB->Reserved2 = 0;
3265 byte_count = params + 1 /* pad */ ;
3266 pSMB->TotalParameterCount = cpu_to_le16(params);
3267 pSMB->ParameterCount = pSMB->TotalParameterCount;
3268 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003269 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3270 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 pSMB->DataCount = 0;
3272 pSMB->DataOffset = 0;
3273 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3274 pSMB->Reserved3 = 0;
3275 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3276 pSMB->SearchAttributes =
3277 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3278 ATTR_DIRECTORY);
3279 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3280 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3281 CIFS_SEARCH_RETURN_RESUME);
3282 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3283
3284 /* BB what should we set StorageType to? Does it matter? BB */
3285 pSMB->SearchStorageType = 0;
3286 pSMB->hdr.smb_buf_length += byte_count;
3287 pSMB->ByteCount = cpu_to_le16(byte_count);
3288
3289 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3290 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003291 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
Steve French88274812006-03-09 22:21:45 +00003293 if (rc) {/* BB add logic to retry regular search if Unix search
3294 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 /* BB Add code to handle unsupported level rc */
3296 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003297
Steve French88274812006-03-09 22:21:45 +00003298 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299
3300 /* BB eventually could optimize out free and realloc of buf */
3301 /* for this case */
3302 if (rc == -EAGAIN)
3303 goto findFirstRetry;
3304 } else { /* decode response */
3305 /* BB remember to free buffer if error BB */
3306 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3307 if(rc == 0) {
3308 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3309 psrch_inf->unicode = TRUE;
3310 else
3311 psrch_inf->unicode = FALSE;
3312
3313 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003314 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 psrch_inf->srch_entries_start =
3316 (char *) &pSMBr->hdr.Protocol +
3317 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3319 le16_to_cpu(pSMBr->t2.ParameterOffset));
3320
3321 if(parms->EndofSearch)
3322 psrch_inf->endOfSearch = TRUE;
3323 else
3324 psrch_inf->endOfSearch = FALSE;
3325
3326 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003327 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 *pnetfid = parms->SearchHandle;
3330 } else {
3331 cifs_buf_release(pSMB);
3332 }
3333 }
3334
3335 return rc;
3336}
3337
3338int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3339 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3340{
3341 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3342 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3343 T2_FNEXT_RSP_PARMS * parms;
3344 char *response_data;
3345 int rc = 0;
3346 int bytes_returned, name_len;
3347 __u16 params, byte_count;
3348
3349 cFYI(1, ("In FindNext"));
3350
3351 if(psrch_inf->endOfSearch == TRUE)
3352 return -ENOENT;
3353
3354 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3355 (void **) &pSMBr);
3356 if (rc)
3357 return rc;
3358
3359 params = 14; /* includes 2 bytes of null string, converted to LE below */
3360 byte_count = 0;
3361 pSMB->TotalDataCount = 0; /* no EAs */
3362 pSMB->MaxParameterCount = cpu_to_le16(8);
3363 pSMB->MaxDataCount =
3364 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3365 pSMB->MaxSetupCount = 0;
3366 pSMB->Reserved = 0;
3367 pSMB->Flags = 0;
3368 pSMB->Timeout = 0;
3369 pSMB->Reserved2 = 0;
3370 pSMB->ParameterOffset = cpu_to_le16(
3371 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3372 pSMB->DataCount = 0;
3373 pSMB->DataOffset = 0;
3374 pSMB->SetupCount = 1;
3375 pSMB->Reserved3 = 0;
3376 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3377 pSMB->SearchHandle = searchHandle; /* always kept as le */
3378 pSMB->SearchCount =
3379 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3380 /* test for Unix extensions */
3381/* if (tcon->ses->capabilities & CAP_UNIX) {
3382 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3383 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3384 } else {
3385 pSMB->InformationLevel =
3386 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3387 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3388 } */
3389 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3390 pSMB->ResumeKey = psrch_inf->resume_key;
3391 pSMB->SearchFlags =
3392 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3393
3394 name_len = psrch_inf->resume_name_len;
3395 params += name_len;
3396 if(name_len < PATH_MAX) {
3397 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3398 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003399 /* 14 byte parm len above enough for 2 byte null terminator */
3400 pSMB->ResumeFileName[name_len] = 0;
3401 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 } else {
3403 rc = -EINVAL;
3404 goto FNext2_err_exit;
3405 }
3406 byte_count = params + 1 /* pad */ ;
3407 pSMB->TotalParameterCount = cpu_to_le16(params);
3408 pSMB->ParameterCount = pSMB->TotalParameterCount;
3409 pSMB->hdr.smb_buf_length += byte_count;
3410 pSMB->ByteCount = cpu_to_le16(byte_count);
3411
3412 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3413 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003414 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 if (rc) {
3416 if (rc == -EBADF) {
3417 psrch_inf->endOfSearch = TRUE;
3418 rc = 0; /* search probably was closed at end of search above */
3419 } else
3420 cFYI(1, ("FindNext returned = %d", rc));
3421 } else { /* decode response */
3422 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3423
3424 if(rc == 0) {
3425 /* BB fixme add lock for file (srch_info) struct here */
3426 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3427 psrch_inf->unicode = TRUE;
3428 else
3429 psrch_inf->unicode = FALSE;
3430 response_data = (char *) &pSMBr->hdr.Protocol +
3431 le16_to_cpu(pSMBr->t2.ParameterOffset);
3432 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3433 response_data = (char *)&pSMBr->hdr.Protocol +
3434 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003435 if(psrch_inf->smallBuf)
3436 cifs_small_buf_release(
3437 psrch_inf->ntwrk_buf_start);
3438 else
3439 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 psrch_inf->srch_entries_start = response_data;
3441 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003442 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 if(parms->EndofSearch)
3444 psrch_inf->endOfSearch = TRUE;
3445 else
3446 psrch_inf->endOfSearch = FALSE;
3447
3448 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3449 psrch_inf->index_of_last_entry +=
3450 psrch_inf->entries_in_buffer;
3451/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3452
3453 /* BB fixme add unlock here */
3454 }
3455
3456 }
3457
3458 /* BB On error, should we leave previous search buf (and count and
3459 last entry fields) intact or free the previous one? */
3460
3461 /* Note: On -EAGAIN error only caller can retry on handle based calls
3462 since file handle passed in no longer valid */
3463FNext2_err_exit:
3464 if (rc != 0)
3465 cifs_buf_release(pSMB);
3466
3467 return rc;
3468}
3469
3470int
3471CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3472{
3473 int rc = 0;
3474 FINDCLOSE_REQ *pSMB = NULL;
3475 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3476 int bytes_returned;
3477
3478 cFYI(1, ("In CIFSSMBFindClose"));
3479 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3480
3481 /* no sense returning error if session restarted
3482 as file handle has been closed */
3483 if(rc == -EAGAIN)
3484 return 0;
3485 if (rc)
3486 return rc;
3487
3488 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3489 pSMB->FileID = searchHandle;
3490 pSMB->ByteCount = 0;
3491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3493 if (rc) {
3494 cERROR(1, ("Send error in FindClose = %d", rc));
3495 }
Steve Frencha4544342005-08-24 13:59:35 -07003496 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 cifs_small_buf_release(pSMB);
3498
3499 /* Since session is dead, search handle closed on server already */
3500 if (rc == -EAGAIN)
3501 rc = 0;
3502
3503 return rc;
3504}
3505
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506int
3507CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3508 const unsigned char *searchName,
3509 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003510 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511{
3512 int rc = 0;
3513 TRANSACTION2_QPI_REQ *pSMB = NULL;
3514 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3515 int name_len, bytes_returned;
3516 __u16 params, byte_count;
3517
3518 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3519 if(tcon == NULL)
3520 return -ENODEV;
3521
3522GetInodeNumberRetry:
3523 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3524 (void **) &pSMBr);
3525 if (rc)
3526 return rc;
3527
3528
3529 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3530 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003531 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003532 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 name_len++; /* trailing null */
3534 name_len *= 2;
3535 } else { /* BB improve the check for buffer overruns BB */
3536 name_len = strnlen(searchName, PATH_MAX);
3537 name_len++; /* trailing null */
3538 strncpy(pSMB->FileName, searchName, name_len);
3539 }
3540
3541 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3542 pSMB->TotalDataCount = 0;
3543 pSMB->MaxParameterCount = cpu_to_le16(2);
3544 /* BB find exact max data count below from sess structure BB */
3545 pSMB->MaxDataCount = cpu_to_le16(4000);
3546 pSMB->MaxSetupCount = 0;
3547 pSMB->Reserved = 0;
3548 pSMB->Flags = 0;
3549 pSMB->Timeout = 0;
3550 pSMB->Reserved2 = 0;
3551 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3552 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3553 pSMB->DataCount = 0;
3554 pSMB->DataOffset = 0;
3555 pSMB->SetupCount = 1;
3556 pSMB->Reserved3 = 0;
3557 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3558 byte_count = params + 1 /* pad */ ;
3559 pSMB->TotalParameterCount = cpu_to_le16(params);
3560 pSMB->ParameterCount = pSMB->TotalParameterCount;
3561 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3562 pSMB->Reserved4 = 0;
3563 pSMB->hdr.smb_buf_length += byte_count;
3564 pSMB->ByteCount = cpu_to_le16(byte_count);
3565
3566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3568 if (rc) {
3569 cFYI(1, ("error %d in QueryInternalInfo", rc));
3570 } else {
3571 /* decode response */
3572 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3573 if (rc || (pSMBr->ByteCount < 2))
3574 /* BB also check enough total bytes returned */
3575 /* If rc should we check for EOPNOSUPP and
3576 disable the srvino flag? or in caller? */
3577 rc = -EIO; /* bad smb */
3578 else {
3579 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3580 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3581 struct file_internal_info * pfinfo;
3582 /* BB Do we need a cast or hash here ? */
3583 if(count < 8) {
3584 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3585 rc = -EIO;
3586 goto GetInodeNumOut;
3587 }
3588 pfinfo = (struct file_internal_info *)
3589 (data_offset + (char *) &pSMBr->hdr.Protocol);
3590 *inode_number = pfinfo->UniqueId;
3591 }
3592 }
3593GetInodeNumOut:
3594 cifs_buf_release(pSMB);
3595 if (rc == -EAGAIN)
3596 goto GetInodeNumberRetry;
3597 return rc;
3598}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
3600int
3601CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3602 const unsigned char *searchName,
3603 unsigned char **targetUNCs,
3604 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003605 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606{
3607/* TRANS2_GET_DFS_REFERRAL */
3608 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3609 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3610 struct dfs_referral_level_3 * referrals = NULL;
3611 int rc = 0;
3612 int bytes_returned;
3613 int name_len;
3614 unsigned int i;
3615 char * temp;
3616 __u16 params, byte_count;
3617 *number_of_UNC_in_array = 0;
3618 *targetUNCs = NULL;
3619
3620 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3621 if (ses == NULL)
3622 return -ENODEV;
3623getDFSRetry:
3624 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3625 (void **) &pSMBr);
3626 if (rc)
3627 return rc;
Steve French1982c342005-08-17 12:38:22 -07003628
3629 /* server pointer checked in called function,
3630 but should never be null here anyway */
3631 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 pSMB->hdr.Tid = ses->ipc_tid;
3633 pSMB->hdr.Uid = ses->Suid;
3634 if (ses->capabilities & CAP_STATUS32) {
3635 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3636 }
3637 if (ses->capabilities & CAP_DFS) {
3638 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3639 }
3640
3641 if (ses->capabilities & CAP_UNICODE) {
3642 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3643 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003644 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003645 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 name_len++; /* trailing null */
3647 name_len *= 2;
3648 } else { /* BB improve the check for buffer overruns BB */
3649 name_len = strnlen(searchName, PATH_MAX);
3650 name_len++; /* trailing null */
3651 strncpy(pSMB->RequestFileName, searchName, name_len);
3652 }
3653
3654 params = 2 /* level */ + name_len /*includes null */ ;
3655 pSMB->TotalDataCount = 0;
3656 pSMB->DataCount = 0;
3657 pSMB->DataOffset = 0;
3658 pSMB->MaxParameterCount = 0;
3659 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3660 pSMB->MaxSetupCount = 0;
3661 pSMB->Reserved = 0;
3662 pSMB->Flags = 0;
3663 pSMB->Timeout = 0;
3664 pSMB->Reserved2 = 0;
3665 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3666 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3667 pSMB->SetupCount = 1;
3668 pSMB->Reserved3 = 0;
3669 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3670 byte_count = params + 3 /* pad */ ;
3671 pSMB->ParameterCount = cpu_to_le16(params);
3672 pSMB->TotalParameterCount = pSMB->ParameterCount;
3673 pSMB->MaxReferralLevel = cpu_to_le16(3);
3674 pSMB->hdr.smb_buf_length += byte_count;
3675 pSMB->ByteCount = cpu_to_le16(byte_count);
3676
3677 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3678 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3679 if (rc) {
3680 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3681 } else { /* decode response */
3682/* BB Add logic to parse referrals here */
3683 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3684
3685 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3686 rc = -EIO; /* bad smb */
3687 else {
3688 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3689 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3690
3691 cFYI(1,
3692 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3693 pSMBr->ByteCount, data_offset));
3694 referrals =
3695 (struct dfs_referral_level_3 *)
3696 (8 /* sizeof start of data block */ +
3697 data_offset +
3698 (char *) &pSMBr->hdr.Protocol);
3699 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",
3700 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)));
3701 /* BB This field is actually two bytes in from start of
3702 data block so we could do safety check that DataBlock
3703 begins at address of pSMBr->NumberOfReferrals */
3704 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3705
3706 /* BB Fix below so can return more than one referral */
3707 if(*number_of_UNC_in_array > 1)
3708 *number_of_UNC_in_array = 1;
3709
3710 /* get the length of the strings describing refs */
3711 name_len = 0;
3712 for(i=0;i<*number_of_UNC_in_array;i++) {
3713 /* make sure that DfsPathOffset not past end */
3714 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3715 if (offset > data_count) {
3716 /* if invalid referral, stop here and do
3717 not try to copy any more */
3718 *number_of_UNC_in_array = i;
3719 break;
3720 }
3721 temp = ((char *)referrals) + offset;
3722
3723 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3724 name_len += UniStrnlen((wchar_t *)temp,data_count);
3725 } else {
3726 name_len += strnlen(temp,data_count);
3727 }
3728 referrals++;
3729 /* BB add check that referral pointer does not fall off end PDU */
3730
3731 }
3732 /* BB add check for name_len bigger than bcc */
3733 *targetUNCs =
3734 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3735 if(*targetUNCs == NULL) {
3736 rc = -ENOMEM;
3737 goto GetDFSRefExit;
3738 }
3739 /* copy the ref strings */
3740 referrals =
3741 (struct dfs_referral_level_3 *)
3742 (8 /* sizeof data hdr */ +
3743 data_offset +
3744 (char *) &pSMBr->hdr.Protocol);
3745
3746 for(i=0;i<*number_of_UNC_in_array;i++) {
3747 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3748 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3749 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003750 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 } else {
3752 strncpy(*targetUNCs,temp,name_len);
3753 }
3754 /* BB update target_uncs pointers */
3755 referrals++;
3756 }
3757 temp = *targetUNCs;
3758 temp[name_len] = 0;
3759 }
3760
3761 }
3762GetDFSRefExit:
3763 if (pSMB)
3764 cifs_buf_release(pSMB);
3765
3766 if (rc == -EAGAIN)
3767 goto getDFSRetry;
3768
3769 return rc;
3770}
3771
Steve French20962432005-09-21 22:05:57 -07003772/* Query File System Info such as free space to old servers such as Win 9x */
3773int
3774SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3775{
3776/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3777 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3778 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3779 FILE_SYSTEM_ALLOC_INFO *response_data;
3780 int rc = 0;
3781 int bytes_returned = 0;
3782 __u16 params, byte_count;
3783
3784 cFYI(1, ("OldQFSInfo"));
3785oldQFSInfoRetry:
3786 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3787 (void **) &pSMBr);
3788 if (rc)
3789 return rc;
3790 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3791 (void **) &pSMBr);
3792 if (rc)
3793 return rc;
3794
3795 params = 2; /* level */
3796 pSMB->TotalDataCount = 0;
3797 pSMB->MaxParameterCount = cpu_to_le16(2);
3798 pSMB->MaxDataCount = cpu_to_le16(1000);
3799 pSMB->MaxSetupCount = 0;
3800 pSMB->Reserved = 0;
3801 pSMB->Flags = 0;
3802 pSMB->Timeout = 0;
3803 pSMB->Reserved2 = 0;
3804 byte_count = params + 1 /* pad */ ;
3805 pSMB->TotalParameterCount = cpu_to_le16(params);
3806 pSMB->ParameterCount = pSMB->TotalParameterCount;
3807 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3808 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3809 pSMB->DataCount = 0;
3810 pSMB->DataOffset = 0;
3811 pSMB->SetupCount = 1;
3812 pSMB->Reserved3 = 0;
3813 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3814 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3815 pSMB->hdr.smb_buf_length += byte_count;
3816 pSMB->ByteCount = cpu_to_le16(byte_count);
3817
3818 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3819 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3820 if (rc) {
3821 cFYI(1, ("Send error in QFSInfo = %d", rc));
3822 } else { /* decode response */
3823 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3824
3825 if (rc || (pSMBr->ByteCount < 18))
3826 rc = -EIO; /* bad smb */
3827 else {
3828 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3829 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3830 pSMBr->ByteCount, data_offset));
3831
3832 response_data =
3833 (FILE_SYSTEM_ALLOC_INFO *)
3834 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3835 FSData->f_bsize =
3836 le16_to_cpu(response_data->BytesPerSector) *
3837 le32_to_cpu(response_data->
3838 SectorsPerAllocationUnit);
3839 FSData->f_blocks =
3840 le32_to_cpu(response_data->TotalAllocationUnits);
3841 FSData->f_bfree = FSData->f_bavail =
3842 le32_to_cpu(response_data->FreeAllocationUnits);
3843 cFYI(1,
3844 ("Blocks: %lld Free: %lld Block size %ld",
3845 (unsigned long long)FSData->f_blocks,
3846 (unsigned long long)FSData->f_bfree,
3847 FSData->f_bsize));
3848 }
3849 }
3850 cifs_buf_release(pSMB);
3851
3852 if (rc == -EAGAIN)
3853 goto oldQFSInfoRetry;
3854
3855 return rc;
3856}
3857
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858int
Steve French737b7582005-04-28 22:41:06 -07003859CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860{
3861/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3862 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3863 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3864 FILE_SYSTEM_INFO *response_data;
3865 int rc = 0;
3866 int bytes_returned = 0;
3867 __u16 params, byte_count;
3868
3869 cFYI(1, ("In QFSInfo"));
3870QFSInfoRetry:
3871 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3872 (void **) &pSMBr);
3873 if (rc)
3874 return rc;
3875
3876 params = 2; /* level */
3877 pSMB->TotalDataCount = 0;
3878 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003879 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 pSMB->MaxSetupCount = 0;
3881 pSMB->Reserved = 0;
3882 pSMB->Flags = 0;
3883 pSMB->Timeout = 0;
3884 pSMB->Reserved2 = 0;
3885 byte_count = params + 1 /* pad */ ;
3886 pSMB->TotalParameterCount = cpu_to_le16(params);
3887 pSMB->ParameterCount = pSMB->TotalParameterCount;
3888 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3889 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3890 pSMB->DataCount = 0;
3891 pSMB->DataOffset = 0;
3892 pSMB->SetupCount = 1;
3893 pSMB->Reserved3 = 0;
3894 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3895 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3896 pSMB->hdr.smb_buf_length += byte_count;
3897 pSMB->ByteCount = cpu_to_le16(byte_count);
3898
3899 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3900 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3901 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003902 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 } else { /* decode response */
3904 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3905
Steve French20962432005-09-21 22:05:57 -07003906 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 rc = -EIO; /* bad smb */
3908 else {
3909 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910
3911 response_data =
3912 (FILE_SYSTEM_INFO
3913 *) (((char *) &pSMBr->hdr.Protocol) +
3914 data_offset);
3915 FSData->f_bsize =
3916 le32_to_cpu(response_data->BytesPerSector) *
3917 le32_to_cpu(response_data->
3918 SectorsPerAllocationUnit);
3919 FSData->f_blocks =
3920 le64_to_cpu(response_data->TotalAllocationUnits);
3921 FSData->f_bfree = FSData->f_bavail =
3922 le64_to_cpu(response_data->FreeAllocationUnits);
3923 cFYI(1,
3924 ("Blocks: %lld Free: %lld Block size %ld",
3925 (unsigned long long)FSData->f_blocks,
3926 (unsigned long long)FSData->f_bfree,
3927 FSData->f_bsize));
3928 }
3929 }
3930 cifs_buf_release(pSMB);
3931
3932 if (rc == -EAGAIN)
3933 goto QFSInfoRetry;
3934
3935 return rc;
3936}
3937
3938int
Steve French737b7582005-04-28 22:41:06 -07003939CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940{
3941/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3942 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3943 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3944 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3945 int rc = 0;
3946 int bytes_returned = 0;
3947 __u16 params, byte_count;
3948
3949 cFYI(1, ("In QFSAttributeInfo"));
3950QFSAttributeRetry:
3951 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3952 (void **) &pSMBr);
3953 if (rc)
3954 return rc;
3955
3956 params = 2; /* level */
3957 pSMB->TotalDataCount = 0;
3958 pSMB->MaxParameterCount = cpu_to_le16(2);
3959 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3960 pSMB->MaxSetupCount = 0;
3961 pSMB->Reserved = 0;
3962 pSMB->Flags = 0;
3963 pSMB->Timeout = 0;
3964 pSMB->Reserved2 = 0;
3965 byte_count = params + 1 /* pad */ ;
3966 pSMB->TotalParameterCount = cpu_to_le16(params);
3967 pSMB->ParameterCount = pSMB->TotalParameterCount;
3968 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3969 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3970 pSMB->DataCount = 0;
3971 pSMB->DataOffset = 0;
3972 pSMB->SetupCount = 1;
3973 pSMB->Reserved3 = 0;
3974 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3975 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3976 pSMB->hdr.smb_buf_length += byte_count;
3977 pSMB->ByteCount = cpu_to_le16(byte_count);
3978
3979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3981 if (rc) {
3982 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3983 } else { /* decode response */
3984 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3985
3986 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3987 rc = -EIO; /* bad smb */
3988 } else {
3989 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3990 response_data =
3991 (FILE_SYSTEM_ATTRIBUTE_INFO
3992 *) (((char *) &pSMBr->hdr.Protocol) +
3993 data_offset);
3994 memcpy(&tcon->fsAttrInfo, response_data,
3995 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3996 }
3997 }
3998 cifs_buf_release(pSMB);
3999
4000 if (rc == -EAGAIN)
4001 goto QFSAttributeRetry;
4002
4003 return rc;
4004}
4005
4006int
Steve French737b7582005-04-28 22:41:06 -07004007CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008{
4009/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4010 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4011 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4012 FILE_SYSTEM_DEVICE_INFO *response_data;
4013 int rc = 0;
4014 int bytes_returned = 0;
4015 __u16 params, byte_count;
4016
4017 cFYI(1, ("In QFSDeviceInfo"));
4018QFSDeviceRetry:
4019 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4020 (void **) &pSMBr);
4021 if (rc)
4022 return rc;
4023
4024 params = 2; /* level */
4025 pSMB->TotalDataCount = 0;
4026 pSMB->MaxParameterCount = cpu_to_le16(2);
4027 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4028 pSMB->MaxSetupCount = 0;
4029 pSMB->Reserved = 0;
4030 pSMB->Flags = 0;
4031 pSMB->Timeout = 0;
4032 pSMB->Reserved2 = 0;
4033 byte_count = params + 1 /* pad */ ;
4034 pSMB->TotalParameterCount = cpu_to_le16(params);
4035 pSMB->ParameterCount = pSMB->TotalParameterCount;
4036 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4037 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4038
4039 pSMB->DataCount = 0;
4040 pSMB->DataOffset = 0;
4041 pSMB->SetupCount = 1;
4042 pSMB->Reserved3 = 0;
4043 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4044 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4045 pSMB->hdr.smb_buf_length += byte_count;
4046 pSMB->ByteCount = cpu_to_le16(byte_count);
4047
4048 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4049 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4050 if (rc) {
4051 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4052 } else { /* decode response */
4053 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4054
4055 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4056 rc = -EIO; /* bad smb */
4057 else {
4058 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4059 response_data =
Steve French737b7582005-04-28 22:41:06 -07004060 (FILE_SYSTEM_DEVICE_INFO *)
4061 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 data_offset);
4063 memcpy(&tcon->fsDevInfo, response_data,
4064 sizeof (FILE_SYSTEM_DEVICE_INFO));
4065 }
4066 }
4067 cifs_buf_release(pSMB);
4068
4069 if (rc == -EAGAIN)
4070 goto QFSDeviceRetry;
4071
4072 return rc;
4073}
4074
4075int
Steve French737b7582005-04-28 22:41:06 -07004076CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077{
4078/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4079 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4080 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4081 FILE_SYSTEM_UNIX_INFO *response_data;
4082 int rc = 0;
4083 int bytes_returned = 0;
4084 __u16 params, byte_count;
4085
4086 cFYI(1, ("In QFSUnixInfo"));
4087QFSUnixRetry:
4088 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4089 (void **) &pSMBr);
4090 if (rc)
4091 return rc;
4092
4093 params = 2; /* level */
4094 pSMB->TotalDataCount = 0;
4095 pSMB->DataCount = 0;
4096 pSMB->DataOffset = 0;
4097 pSMB->MaxParameterCount = cpu_to_le16(2);
4098 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4099 pSMB->MaxSetupCount = 0;
4100 pSMB->Reserved = 0;
4101 pSMB->Flags = 0;
4102 pSMB->Timeout = 0;
4103 pSMB->Reserved2 = 0;
4104 byte_count = params + 1 /* pad */ ;
4105 pSMB->ParameterCount = cpu_to_le16(params);
4106 pSMB->TotalParameterCount = pSMB->ParameterCount;
4107 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4108 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4109 pSMB->SetupCount = 1;
4110 pSMB->Reserved3 = 0;
4111 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4112 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4113 pSMB->hdr.smb_buf_length += byte_count;
4114 pSMB->ByteCount = cpu_to_le16(byte_count);
4115
4116 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4117 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4118 if (rc) {
4119 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4120 } else { /* decode response */
4121 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4122
4123 if (rc || (pSMBr->ByteCount < 13)) {
4124 rc = -EIO; /* bad smb */
4125 } else {
4126 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4127 response_data =
4128 (FILE_SYSTEM_UNIX_INFO
4129 *) (((char *) &pSMBr->hdr.Protocol) +
4130 data_offset);
4131 memcpy(&tcon->fsUnixInfo, response_data,
4132 sizeof (FILE_SYSTEM_UNIX_INFO));
4133 }
4134 }
4135 cifs_buf_release(pSMB);
4136
4137 if (rc == -EAGAIN)
4138 goto QFSUnixRetry;
4139
4140
4141 return rc;
4142}
4143
Jeremy Allisonac670552005-06-22 17:26:35 -07004144int
Steve French45abc6e2005-06-23 13:42:03 -05004145CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004146{
4147/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4148 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4149 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4150 int rc = 0;
4151 int bytes_returned = 0;
4152 __u16 params, param_offset, offset, byte_count;
4153
4154 cFYI(1, ("In SETFSUnixInfo"));
4155SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004156 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004157 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4158 (void **) &pSMBr);
4159 if (rc)
4160 return rc;
4161
4162 params = 4; /* 2 bytes zero followed by info level. */
4163 pSMB->MaxSetupCount = 0;
4164 pSMB->Reserved = 0;
4165 pSMB->Flags = 0;
4166 pSMB->Timeout = 0;
4167 pSMB->Reserved2 = 0;
4168 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4169 offset = param_offset + params;
4170
4171 pSMB->MaxParameterCount = cpu_to_le16(4);
4172 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4173 pSMB->SetupCount = 1;
4174 pSMB->Reserved3 = 0;
4175 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4176 byte_count = 1 /* pad */ + params + 12;
4177
4178 pSMB->DataCount = cpu_to_le16(12);
4179 pSMB->ParameterCount = cpu_to_le16(params);
4180 pSMB->TotalDataCount = pSMB->DataCount;
4181 pSMB->TotalParameterCount = pSMB->ParameterCount;
4182 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4183 pSMB->DataOffset = cpu_to_le16(offset);
4184
4185 /* Params. */
4186 pSMB->FileNum = 0;
4187 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4188
4189 /* Data. */
4190 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4191 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4192 pSMB->ClientUnixCap = cpu_to_le64(cap);
4193
4194 pSMB->hdr.smb_buf_length += byte_count;
4195 pSMB->ByteCount = cpu_to_le16(byte_count);
4196
4197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4199 if (rc) {
4200 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4201 } else { /* decode response */
4202 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4203 if (rc) {
4204 rc = -EIO; /* bad smb */
4205 }
4206 }
4207 cifs_buf_release(pSMB);
4208
4209 if (rc == -EAGAIN)
4210 goto SETFSUnixRetry;
4211
4212 return rc;
4213}
4214
4215
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216
4217int
4218CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004219 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220{
4221/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4222 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4223 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4224 FILE_SYSTEM_POSIX_INFO *response_data;
4225 int rc = 0;
4226 int bytes_returned = 0;
4227 __u16 params, byte_count;
4228
4229 cFYI(1, ("In QFSPosixInfo"));
4230QFSPosixRetry:
4231 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4232 (void **) &pSMBr);
4233 if (rc)
4234 return rc;
4235
4236 params = 2; /* level */
4237 pSMB->TotalDataCount = 0;
4238 pSMB->DataCount = 0;
4239 pSMB->DataOffset = 0;
4240 pSMB->MaxParameterCount = cpu_to_le16(2);
4241 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4242 pSMB->MaxSetupCount = 0;
4243 pSMB->Reserved = 0;
4244 pSMB->Flags = 0;
4245 pSMB->Timeout = 0;
4246 pSMB->Reserved2 = 0;
4247 byte_count = params + 1 /* pad */ ;
4248 pSMB->ParameterCount = cpu_to_le16(params);
4249 pSMB->TotalParameterCount = pSMB->ParameterCount;
4250 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4251 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4252 pSMB->SetupCount = 1;
4253 pSMB->Reserved3 = 0;
4254 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4255 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4256 pSMB->hdr.smb_buf_length += byte_count;
4257 pSMB->ByteCount = cpu_to_le16(byte_count);
4258
4259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4261 if (rc) {
4262 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4263 } else { /* decode response */
4264 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4265
4266 if (rc || (pSMBr->ByteCount < 13)) {
4267 rc = -EIO; /* bad smb */
4268 } else {
4269 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4270 response_data =
4271 (FILE_SYSTEM_POSIX_INFO
4272 *) (((char *) &pSMBr->hdr.Protocol) +
4273 data_offset);
4274 FSData->f_bsize =
4275 le32_to_cpu(response_data->BlockSize);
4276 FSData->f_blocks =
4277 le64_to_cpu(response_data->TotalBlocks);
4278 FSData->f_bfree =
4279 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004280 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 FSData->f_bavail = FSData->f_bfree;
4282 } else {
4283 FSData->f_bavail =
4284 le64_to_cpu(response_data->UserBlocksAvail);
4285 }
Steve French70ca7342005-09-22 16:32:06 -07004286 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 FSData->f_files =
4288 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004289 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 FSData->f_ffree =
4291 le64_to_cpu(response_data->FreeFileNodes);
4292 }
4293 }
4294 cifs_buf_release(pSMB);
4295
4296 if (rc == -EAGAIN)
4297 goto QFSPosixRetry;
4298
4299 return rc;
4300}
4301
4302
4303/* We can not use write of zero bytes trick to
4304 set file size due to need for large file support. Also note that
4305 this SetPathInfo is preferred to SetFileInfo based method in next
4306 routine which is only needed to work around a sharing violation bug
4307 in Samba which this routine can run into */
4308
4309int
4310CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004311 __u64 size, int SetAllocation,
4312 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313{
4314 struct smb_com_transaction2_spi_req *pSMB = NULL;
4315 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4316 struct file_end_of_file_info *parm_data;
4317 int name_len;
4318 int rc = 0;
4319 int bytes_returned = 0;
4320 __u16 params, byte_count, data_count, param_offset, offset;
4321
4322 cFYI(1, ("In SetEOF"));
4323SetEOFRetry:
4324 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4325 (void **) &pSMBr);
4326 if (rc)
4327 return rc;
4328
4329 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4330 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004331 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004332 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 name_len++; /* trailing null */
4334 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004335 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 name_len = strnlen(fileName, PATH_MAX);
4337 name_len++; /* trailing null */
4338 strncpy(pSMB->FileName, fileName, name_len);
4339 }
4340 params = 6 + name_len;
4341 data_count = sizeof (struct file_end_of_file_info);
4342 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004343 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 pSMB->MaxSetupCount = 0;
4345 pSMB->Reserved = 0;
4346 pSMB->Flags = 0;
4347 pSMB->Timeout = 0;
4348 pSMB->Reserved2 = 0;
4349 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4350 InformationLevel) - 4;
4351 offset = param_offset + params;
4352 if(SetAllocation) {
4353 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4354 pSMB->InformationLevel =
4355 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4356 else
4357 pSMB->InformationLevel =
4358 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4359 } else /* Set File Size */ {
4360 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4361 pSMB->InformationLevel =
4362 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4363 else
4364 pSMB->InformationLevel =
4365 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4366 }
4367
4368 parm_data =
4369 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4370 offset);
4371 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4372 pSMB->DataOffset = cpu_to_le16(offset);
4373 pSMB->SetupCount = 1;
4374 pSMB->Reserved3 = 0;
4375 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4376 byte_count = 3 /* pad */ + params + data_count;
4377 pSMB->DataCount = cpu_to_le16(data_count);
4378 pSMB->TotalDataCount = pSMB->DataCount;
4379 pSMB->ParameterCount = cpu_to_le16(params);
4380 pSMB->TotalParameterCount = pSMB->ParameterCount;
4381 pSMB->Reserved4 = 0;
4382 pSMB->hdr.smb_buf_length += byte_count;
4383 parm_data->FileSize = cpu_to_le64(size);
4384 pSMB->ByteCount = cpu_to_le16(byte_count);
4385 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4386 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4387 if (rc) {
4388 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4389 }
4390
4391 cifs_buf_release(pSMB);
4392
4393 if (rc == -EAGAIN)
4394 goto SetEOFRetry;
4395
4396 return rc;
4397}
4398
4399int
4400CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4401 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4402{
4403 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4404 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4405 char *data_offset;
4406 struct file_end_of_file_info *parm_data;
4407 int rc = 0;
4408 int bytes_returned = 0;
4409 __u16 params, param_offset, offset, byte_count, count;
4410
4411 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4412 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004413 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4414
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 if (rc)
4416 return rc;
4417
Steve Frenchcd634992005-04-28 22:41:10 -07004418 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4419
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4421 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4422
4423 params = 6;
4424 pSMB->MaxSetupCount = 0;
4425 pSMB->Reserved = 0;
4426 pSMB->Flags = 0;
4427 pSMB->Timeout = 0;
4428 pSMB->Reserved2 = 0;
4429 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4430 offset = param_offset + params;
4431
4432 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4433
4434 count = sizeof(struct file_end_of_file_info);
4435 pSMB->MaxParameterCount = cpu_to_le16(2);
4436 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4437 pSMB->SetupCount = 1;
4438 pSMB->Reserved3 = 0;
4439 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4440 byte_count = 3 /* pad */ + params + count;
4441 pSMB->DataCount = cpu_to_le16(count);
4442 pSMB->ParameterCount = cpu_to_le16(params);
4443 pSMB->TotalDataCount = pSMB->DataCount;
4444 pSMB->TotalParameterCount = pSMB->ParameterCount;
4445 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4446 parm_data =
4447 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4448 offset);
4449 pSMB->DataOffset = cpu_to_le16(offset);
4450 parm_data->FileSize = cpu_to_le64(size);
4451 pSMB->Fid = fid;
4452 if(SetAllocation) {
4453 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4454 pSMB->InformationLevel =
4455 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4456 else
4457 pSMB->InformationLevel =
4458 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4459 } else /* Set File Size */ {
4460 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4461 pSMB->InformationLevel =
4462 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4463 else
4464 pSMB->InformationLevel =
4465 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4466 }
4467 pSMB->Reserved4 = 0;
4468 pSMB->hdr.smb_buf_length += byte_count;
4469 pSMB->ByteCount = cpu_to_le16(byte_count);
4470 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4472 if (rc) {
4473 cFYI(1,
4474 ("Send error in SetFileInfo (SetFileSize) = %d",
4475 rc));
4476 }
4477
4478 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004479 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480
4481 /* Note: On -EAGAIN error only caller can retry on handle based calls
4482 since file handle passed in no longer valid */
4483
4484 return rc;
4485}
4486
4487/* Some legacy servers such as NT4 require that the file times be set on
4488 an open handle, rather than by pathname - this is awkward due to
4489 potential access conflicts on the open, but it is unavoidable for these
4490 old servers since the only other choice is to go from 100 nanosecond DCE
4491 time and resort to the original setpathinfo level which takes the ancient
4492 DOS time format with 2 second granularity */
4493int
4494CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4495 __u16 fid)
4496{
4497 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4498 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4499 char *data_offset;
4500 int rc = 0;
4501 int bytes_returned = 0;
4502 __u16 params, param_offset, offset, byte_count, count;
4503
4504 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004505 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4506
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 if (rc)
4508 return rc;
4509
Steve Frenchcd634992005-04-28 22:41:10 -07004510 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4511
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 /* At this point there is no need to override the current pid
4513 with the pid of the opener, but that could change if we someday
4514 use an existing handle (rather than opening one on the fly) */
4515 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4516 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4517
4518 params = 6;
4519 pSMB->MaxSetupCount = 0;
4520 pSMB->Reserved = 0;
4521 pSMB->Flags = 0;
4522 pSMB->Timeout = 0;
4523 pSMB->Reserved2 = 0;
4524 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4525 offset = param_offset + params;
4526
4527 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4528
4529 count = sizeof (FILE_BASIC_INFO);
4530 pSMB->MaxParameterCount = cpu_to_le16(2);
4531 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4532 pSMB->SetupCount = 1;
4533 pSMB->Reserved3 = 0;
4534 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4535 byte_count = 3 /* pad */ + params + count;
4536 pSMB->DataCount = cpu_to_le16(count);
4537 pSMB->ParameterCount = cpu_to_le16(params);
4538 pSMB->TotalDataCount = pSMB->DataCount;
4539 pSMB->TotalParameterCount = pSMB->ParameterCount;
4540 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4541 pSMB->DataOffset = cpu_to_le16(offset);
4542 pSMB->Fid = fid;
4543 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4544 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4545 else
4546 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4547 pSMB->Reserved4 = 0;
4548 pSMB->hdr.smb_buf_length += byte_count;
4549 pSMB->ByteCount = cpu_to_le16(byte_count);
4550 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4551 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4552 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4553 if (rc) {
4554 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4555 }
4556
Steve Frenchcd634992005-04-28 22:41:10 -07004557 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
4559 /* Note: On -EAGAIN error only caller can retry on handle based calls
4560 since file handle passed in no longer valid */
4561
4562 return rc;
4563}
4564
4565
4566int
4567CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4568 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004569 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570{
4571 TRANSACTION2_SPI_REQ *pSMB = NULL;
4572 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4573 int name_len;
4574 int rc = 0;
4575 int bytes_returned = 0;
4576 char *data_offset;
4577 __u16 params, param_offset, offset, byte_count, count;
4578
4579 cFYI(1, ("In SetTimes"));
4580
4581SetTimesRetry:
4582 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4583 (void **) &pSMBr);
4584 if (rc)
4585 return rc;
4586
4587 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4588 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004589 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004590 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 name_len++; /* trailing null */
4592 name_len *= 2;
4593 } else { /* BB improve the check for buffer overruns BB */
4594 name_len = strnlen(fileName, PATH_MAX);
4595 name_len++; /* trailing null */
4596 strncpy(pSMB->FileName, fileName, name_len);
4597 }
4598
4599 params = 6 + name_len;
4600 count = sizeof (FILE_BASIC_INFO);
4601 pSMB->MaxParameterCount = cpu_to_le16(2);
4602 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4603 pSMB->MaxSetupCount = 0;
4604 pSMB->Reserved = 0;
4605 pSMB->Flags = 0;
4606 pSMB->Timeout = 0;
4607 pSMB->Reserved2 = 0;
4608 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4609 InformationLevel) - 4;
4610 offset = param_offset + params;
4611 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4612 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4613 pSMB->DataOffset = cpu_to_le16(offset);
4614 pSMB->SetupCount = 1;
4615 pSMB->Reserved3 = 0;
4616 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4617 byte_count = 3 /* pad */ + params + count;
4618
4619 pSMB->DataCount = cpu_to_le16(count);
4620 pSMB->ParameterCount = cpu_to_le16(params);
4621 pSMB->TotalDataCount = pSMB->DataCount;
4622 pSMB->TotalParameterCount = pSMB->ParameterCount;
4623 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4624 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4625 else
4626 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4627 pSMB->Reserved4 = 0;
4628 pSMB->hdr.smb_buf_length += byte_count;
4629 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4630 pSMB->ByteCount = cpu_to_le16(byte_count);
4631 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4632 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4633 if (rc) {
4634 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4635 }
4636
4637 cifs_buf_release(pSMB);
4638
4639 if (rc == -EAGAIN)
4640 goto SetTimesRetry;
4641
4642 return rc;
4643}
4644
4645/* Can not be used to set time stamps yet (due to old DOS time format) */
4646/* Can be used to set attributes */
4647#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4648 handling it anyway and NT4 was what we thought it would be needed for
4649 Do not delete it until we prove whether needed for Win9x though */
4650int
4651CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4652 __u16 dos_attrs, const struct nls_table *nls_codepage)
4653{
4654 SETATTR_REQ *pSMB = NULL;
4655 SETATTR_RSP *pSMBr = NULL;
4656 int rc = 0;
4657 int bytes_returned;
4658 int name_len;
4659
4660 cFYI(1, ("In SetAttrLegacy"));
4661
4662SetAttrLgcyRetry:
4663 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4664 (void **) &pSMBr);
4665 if (rc)
4666 return rc;
4667
4668 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4669 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004670 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 PATH_MAX, nls_codepage);
4672 name_len++; /* trailing null */
4673 name_len *= 2;
4674 } else { /* BB improve the check for buffer overruns BB */
4675 name_len = strnlen(fileName, PATH_MAX);
4676 name_len++; /* trailing null */
4677 strncpy(pSMB->fileName, fileName, name_len);
4678 }
4679 pSMB->attr = cpu_to_le16(dos_attrs);
4680 pSMB->BufferFormat = 0x04;
4681 pSMB->hdr.smb_buf_length += name_len + 1;
4682 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4683 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4684 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4685 if (rc) {
4686 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4687 }
4688
4689 cifs_buf_release(pSMB);
4690
4691 if (rc == -EAGAIN)
4692 goto SetAttrLgcyRetry;
4693
4694 return rc;
4695}
4696#endif /* temporarily unneeded SetAttr legacy function */
4697
4698int
4699CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004700 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4701 dev_t device, const struct nls_table *nls_codepage,
4702 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703{
4704 TRANSACTION2_SPI_REQ *pSMB = NULL;
4705 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4706 int name_len;
4707 int rc = 0;
4708 int bytes_returned = 0;
4709 FILE_UNIX_BASIC_INFO *data_offset;
4710 __u16 params, param_offset, offset, count, byte_count;
4711
4712 cFYI(1, ("In SetUID/GID/Mode"));
4713setPermsRetry:
4714 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4715 (void **) &pSMBr);
4716 if (rc)
4717 return rc;
4718
4719 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4720 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004721 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004722 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 name_len++; /* trailing null */
4724 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004725 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 name_len = strnlen(fileName, PATH_MAX);
4727 name_len++; /* trailing null */
4728 strncpy(pSMB->FileName, fileName, name_len);
4729 }
4730
4731 params = 6 + name_len;
4732 count = sizeof (FILE_UNIX_BASIC_INFO);
4733 pSMB->MaxParameterCount = cpu_to_le16(2);
4734 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4735 pSMB->MaxSetupCount = 0;
4736 pSMB->Reserved = 0;
4737 pSMB->Flags = 0;
4738 pSMB->Timeout = 0;
4739 pSMB->Reserved2 = 0;
4740 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4741 InformationLevel) - 4;
4742 offset = param_offset + params;
4743 data_offset =
4744 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4745 offset);
4746 memset(data_offset, 0, count);
4747 pSMB->DataOffset = cpu_to_le16(offset);
4748 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4749 pSMB->SetupCount = 1;
4750 pSMB->Reserved3 = 0;
4751 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4752 byte_count = 3 /* pad */ + params + count;
4753 pSMB->ParameterCount = cpu_to_le16(params);
4754 pSMB->DataCount = cpu_to_le16(count);
4755 pSMB->TotalParameterCount = pSMB->ParameterCount;
4756 pSMB->TotalDataCount = pSMB->DataCount;
4757 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4758 pSMB->Reserved4 = 0;
4759 pSMB->hdr.smb_buf_length += byte_count;
4760 data_offset->Uid = cpu_to_le64(uid);
4761 data_offset->Gid = cpu_to_le64(gid);
4762 /* better to leave device as zero when it is */
4763 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4764 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4765 data_offset->Permissions = cpu_to_le64(mode);
4766
4767 if(S_ISREG(mode))
4768 data_offset->Type = cpu_to_le32(UNIX_FILE);
4769 else if(S_ISDIR(mode))
4770 data_offset->Type = cpu_to_le32(UNIX_DIR);
4771 else if(S_ISLNK(mode))
4772 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4773 else if(S_ISCHR(mode))
4774 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4775 else if(S_ISBLK(mode))
4776 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4777 else if(S_ISFIFO(mode))
4778 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4779 else if(S_ISSOCK(mode))
4780 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4781
4782
4783 pSMB->ByteCount = cpu_to_le16(byte_count);
4784 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4785 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4786 if (rc) {
4787 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4788 }
4789
4790 if (pSMB)
4791 cifs_buf_release(pSMB);
4792 if (rc == -EAGAIN)
4793 goto setPermsRetry;
4794 return rc;
4795}
4796
4797int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004798 const int notify_subdirs, const __u16 netfid,
4799 __u32 filter, struct file * pfile, int multishot,
4800 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801{
4802 int rc = 0;
4803 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004804 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004805 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 int bytes_returned;
4807
4808 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4809 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4810 (void **) &pSMBr);
4811 if (rc)
4812 return rc;
4813
4814 pSMB->TotalParameterCount = 0 ;
4815 pSMB->TotalDataCount = 0;
4816 pSMB->MaxParameterCount = cpu_to_le32(2);
4817 /* BB find exact data count max from sess structure BB */
4818 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004819/* BB VERIFY verify which is correct for above BB */
4820 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4821 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4822
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 pSMB->MaxSetupCount = 4;
4824 pSMB->Reserved = 0;
4825 pSMB->ParameterOffset = 0;
4826 pSMB->DataCount = 0;
4827 pSMB->DataOffset = 0;
4828 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4829 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4830 pSMB->ParameterCount = pSMB->TotalParameterCount;
4831 if(notify_subdirs)
4832 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4833 pSMB->Reserved2 = 0;
4834 pSMB->CompletionFilter = cpu_to_le32(filter);
4835 pSMB->Fid = netfid; /* file handle always le */
4836 pSMB->ByteCount = 0;
4837
4838 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4839 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4840 if (rc) {
4841 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004842 } else {
4843 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004844 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004845 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004846 sizeof(struct dir_notify_req),
4847 GFP_KERNEL);
4848 if(dnotify_req) {
4849 dnotify_req->Pid = pSMB->hdr.Pid;
4850 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4851 dnotify_req->Mid = pSMB->hdr.Mid;
4852 dnotify_req->Tid = pSMB->hdr.Tid;
4853 dnotify_req->Uid = pSMB->hdr.Uid;
4854 dnotify_req->netfid = netfid;
4855 dnotify_req->pfile = pfile;
4856 dnotify_req->filter = filter;
4857 dnotify_req->multishot = multishot;
4858 spin_lock(&GlobalMid_Lock);
4859 list_add_tail(&dnotify_req->lhead,
4860 &GlobalDnotifyReqList);
4861 spin_unlock(&GlobalMid_Lock);
4862 } else
4863 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 }
4865 cifs_buf_release(pSMB);
4866 return rc;
4867}
4868#ifdef CONFIG_CIFS_XATTR
4869ssize_t
4870CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4871 const unsigned char *searchName,
4872 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004873 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874{
4875 /* BB assumes one setup word */
4876 TRANSACTION2_QPI_REQ *pSMB = NULL;
4877 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4878 int rc = 0;
4879 int bytes_returned;
4880 int name_len;
4881 struct fea * temp_fea;
4882 char * temp_ptr;
4883 __u16 params, byte_count;
4884
4885 cFYI(1, ("In Query All EAs path %s", searchName));
4886QAllEAsRetry:
4887 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4888 (void **) &pSMBr);
4889 if (rc)
4890 return rc;
4891
4892 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4893 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004894 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004895 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 name_len++; /* trailing null */
4897 name_len *= 2;
4898 } else { /* BB improve the check for buffer overruns BB */
4899 name_len = strnlen(searchName, PATH_MAX);
4900 name_len++; /* trailing null */
4901 strncpy(pSMB->FileName, searchName, name_len);
4902 }
4903
4904 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4905 pSMB->TotalDataCount = 0;
4906 pSMB->MaxParameterCount = cpu_to_le16(2);
4907 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4908 pSMB->MaxSetupCount = 0;
4909 pSMB->Reserved = 0;
4910 pSMB->Flags = 0;
4911 pSMB->Timeout = 0;
4912 pSMB->Reserved2 = 0;
4913 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4914 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4915 pSMB->DataCount = 0;
4916 pSMB->DataOffset = 0;
4917 pSMB->SetupCount = 1;
4918 pSMB->Reserved3 = 0;
4919 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4920 byte_count = params + 1 /* pad */ ;
4921 pSMB->TotalParameterCount = cpu_to_le16(params);
4922 pSMB->ParameterCount = pSMB->TotalParameterCount;
4923 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4924 pSMB->Reserved4 = 0;
4925 pSMB->hdr.smb_buf_length += byte_count;
4926 pSMB->ByteCount = cpu_to_le16(byte_count);
4927
4928 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4929 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4930 if (rc) {
4931 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4932 } else { /* decode response */
4933 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4934
4935 /* BB also check enough total bytes returned */
4936 /* BB we need to improve the validity checking
4937 of these trans2 responses */
4938 if (rc || (pSMBr->ByteCount < 4))
4939 rc = -EIO; /* bad smb */
4940 /* else if (pFindData){
4941 memcpy((char *) pFindData,
4942 (char *) &pSMBr->hdr.Protocol +
4943 data_offset, kl);
4944 }*/ else {
4945 /* check that length of list is not more than bcc */
4946 /* check that each entry does not go beyond length
4947 of list */
4948 /* check that each element of each entry does not
4949 go beyond end of list */
4950 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4951 struct fealist * ea_response_data;
4952 rc = 0;
4953 /* validate_trans2_offsets() */
4954 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4955 ea_response_data = (struct fealist *)
4956 (((char *) &pSMBr->hdr.Protocol) +
4957 data_offset);
4958 name_len = le32_to_cpu(ea_response_data->list_len);
4959 cFYI(1,("ea length %d", name_len));
4960 if(name_len <= 8) {
4961 /* returned EA size zeroed at top of function */
4962 cFYI(1,("empty EA list returned from server"));
4963 } else {
4964 /* account for ea list len */
4965 name_len -= 4;
4966 temp_fea = ea_response_data->list;
4967 temp_ptr = (char *)temp_fea;
4968 while(name_len > 0) {
4969 __u16 value_len;
4970 name_len -= 4;
4971 temp_ptr += 4;
4972 rc += temp_fea->name_len;
4973 /* account for prefix user. and trailing null */
4974 rc = rc + 5 + 1;
4975 if(rc<(int)buf_size) {
4976 memcpy(EAData,"user.",5);
4977 EAData+=5;
4978 memcpy(EAData,temp_ptr,temp_fea->name_len);
4979 EAData+=temp_fea->name_len;
4980 /* null terminate name */
4981 *EAData = 0;
4982 EAData = EAData + 1;
4983 } else if(buf_size == 0) {
4984 /* skip copy - calc size only */
4985 } else {
4986 /* stop before overrun buffer */
4987 rc = -ERANGE;
4988 break;
4989 }
4990 name_len -= temp_fea->name_len;
4991 temp_ptr += temp_fea->name_len;
4992 /* account for trailing null */
4993 name_len--;
4994 temp_ptr++;
4995 value_len = le16_to_cpu(temp_fea->value_len);
4996 name_len -= value_len;
4997 temp_ptr += value_len;
4998 /* BB check that temp_ptr is still within smb BB*/
4999 /* no trailing null to account for in value len */
5000 /* go on to next EA */
5001 temp_fea = (struct fea *)temp_ptr;
5002 }
5003 }
5004 }
5005 }
5006 if (pSMB)
5007 cifs_buf_release(pSMB);
5008 if (rc == -EAGAIN)
5009 goto QAllEAsRetry;
5010
5011 return (ssize_t)rc;
5012}
5013
5014ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5015 const unsigned char * searchName,const unsigned char * ea_name,
5016 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005017 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018{
5019 TRANSACTION2_QPI_REQ *pSMB = NULL;
5020 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5021 int rc = 0;
5022 int bytes_returned;
5023 int name_len;
5024 struct fea * temp_fea;
5025 char * temp_ptr;
5026 __u16 params, byte_count;
5027
5028 cFYI(1, ("In Query EA path %s", searchName));
5029QEARetry:
5030 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5031 (void **) &pSMBr);
5032 if (rc)
5033 return rc;
5034
5035 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5036 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005037 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005038 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 name_len++; /* trailing null */
5040 name_len *= 2;
5041 } else { /* BB improve the check for buffer overruns BB */
5042 name_len = strnlen(searchName, PATH_MAX);
5043 name_len++; /* trailing null */
5044 strncpy(pSMB->FileName, searchName, name_len);
5045 }
5046
5047 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5048 pSMB->TotalDataCount = 0;
5049 pSMB->MaxParameterCount = cpu_to_le16(2);
5050 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5051 pSMB->MaxSetupCount = 0;
5052 pSMB->Reserved = 0;
5053 pSMB->Flags = 0;
5054 pSMB->Timeout = 0;
5055 pSMB->Reserved2 = 0;
5056 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5057 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5058 pSMB->DataCount = 0;
5059 pSMB->DataOffset = 0;
5060 pSMB->SetupCount = 1;
5061 pSMB->Reserved3 = 0;
5062 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5063 byte_count = params + 1 /* pad */ ;
5064 pSMB->TotalParameterCount = cpu_to_le16(params);
5065 pSMB->ParameterCount = pSMB->TotalParameterCount;
5066 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5067 pSMB->Reserved4 = 0;
5068 pSMB->hdr.smb_buf_length += byte_count;
5069 pSMB->ByteCount = cpu_to_le16(byte_count);
5070
5071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5073 if (rc) {
5074 cFYI(1, ("Send error in Query EA = %d", rc));
5075 } else { /* decode response */
5076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5077
5078 /* BB also check enough total bytes returned */
5079 /* BB we need to improve the validity checking
5080 of these trans2 responses */
5081 if (rc || (pSMBr->ByteCount < 4))
5082 rc = -EIO; /* bad smb */
5083 /* else if (pFindData){
5084 memcpy((char *) pFindData,
5085 (char *) &pSMBr->hdr.Protocol +
5086 data_offset, kl);
5087 }*/ else {
5088 /* check that length of list is not more than bcc */
5089 /* check that each entry does not go beyond length
5090 of list */
5091 /* check that each element of each entry does not
5092 go beyond end of list */
5093 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5094 struct fealist * ea_response_data;
5095 rc = -ENODATA;
5096 /* validate_trans2_offsets() */
5097 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5098 ea_response_data = (struct fealist *)
5099 (((char *) &pSMBr->hdr.Protocol) +
5100 data_offset);
5101 name_len = le32_to_cpu(ea_response_data->list_len);
5102 cFYI(1,("ea length %d", name_len));
5103 if(name_len <= 8) {
5104 /* returned EA size zeroed at top of function */
5105 cFYI(1,("empty EA list returned from server"));
5106 } else {
5107 /* account for ea list len */
5108 name_len -= 4;
5109 temp_fea = ea_response_data->list;
5110 temp_ptr = (char *)temp_fea;
5111 /* loop through checking if we have a matching
5112 name and then return the associated value */
5113 while(name_len > 0) {
5114 __u16 value_len;
5115 name_len -= 4;
5116 temp_ptr += 4;
5117 value_len = le16_to_cpu(temp_fea->value_len);
5118 /* BB validate that value_len falls within SMB,
5119 even though maximum for name_len is 255 */
5120 if(memcmp(temp_fea->name,ea_name,
5121 temp_fea->name_len) == 0) {
5122 /* found a match */
5123 rc = value_len;
5124 /* account for prefix user. and trailing null */
5125 if(rc<=(int)buf_size) {
5126 memcpy(ea_value,
5127 temp_fea->name+temp_fea->name_len+1,
5128 rc);
5129 /* ea values, unlike ea names,
5130 are not null terminated */
5131 } else if(buf_size == 0) {
5132 /* skip copy - calc size only */
5133 } else {
5134 /* stop before overrun buffer */
5135 rc = -ERANGE;
5136 }
5137 break;
5138 }
5139 name_len -= temp_fea->name_len;
5140 temp_ptr += temp_fea->name_len;
5141 /* account for trailing null */
5142 name_len--;
5143 temp_ptr++;
5144 name_len -= value_len;
5145 temp_ptr += value_len;
5146 /* no trailing null to account for in value len */
5147 /* go on to next EA */
5148 temp_fea = (struct fea *)temp_ptr;
5149 }
5150 }
5151 }
5152 }
5153 if (pSMB)
5154 cifs_buf_release(pSMB);
5155 if (rc == -EAGAIN)
5156 goto QEARetry;
5157
5158 return (ssize_t)rc;
5159}
5160
5161int
5162CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5163 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005164 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5165 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166{
5167 struct smb_com_transaction2_spi_req *pSMB = NULL;
5168 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5169 struct fealist *parm_data;
5170 int name_len;
5171 int rc = 0;
5172 int bytes_returned = 0;
5173 __u16 params, param_offset, byte_count, offset, count;
5174
5175 cFYI(1, ("In SetEA"));
5176SetEARetry:
5177 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5178 (void **) &pSMBr);
5179 if (rc)
5180 return rc;
5181
5182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5183 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005184 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005185 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 name_len++; /* trailing null */
5187 name_len *= 2;
5188 } else { /* BB improve the check for buffer overruns BB */
5189 name_len = strnlen(fileName, PATH_MAX);
5190 name_len++; /* trailing null */
5191 strncpy(pSMB->FileName, fileName, name_len);
5192 }
5193
5194 params = 6 + name_len;
5195
5196 /* done calculating parms using name_len of file name,
5197 now use name_len to calculate length of ea name
5198 we are going to create in the inode xattrs */
5199 if(ea_name == NULL)
5200 name_len = 0;
5201 else
5202 name_len = strnlen(ea_name,255);
5203
5204 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5205 pSMB->MaxParameterCount = cpu_to_le16(2);
5206 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5207 pSMB->MaxSetupCount = 0;
5208 pSMB->Reserved = 0;
5209 pSMB->Flags = 0;
5210 pSMB->Timeout = 0;
5211 pSMB->Reserved2 = 0;
5212 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5213 InformationLevel) - 4;
5214 offset = param_offset + params;
5215 pSMB->InformationLevel =
5216 cpu_to_le16(SMB_SET_FILE_EA);
5217
5218 parm_data =
5219 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5220 offset);
5221 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5222 pSMB->DataOffset = cpu_to_le16(offset);
5223 pSMB->SetupCount = 1;
5224 pSMB->Reserved3 = 0;
5225 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5226 byte_count = 3 /* pad */ + params + count;
5227 pSMB->DataCount = cpu_to_le16(count);
5228 parm_data->list_len = cpu_to_le32(count);
5229 parm_data->list[0].EA_flags = 0;
5230 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005231 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 /* EA names are always ASCII */
5233 if(ea_name)
5234 strncpy(parm_data->list[0].name,ea_name,name_len);
5235 parm_data->list[0].name[name_len] = 0;
5236 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5237 /* caller ensures that ea_value_len is less than 64K but
5238 we need to ensure that it fits within the smb */
5239
5240 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5241 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5242 if(ea_value_len)
5243 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5244
5245 pSMB->TotalDataCount = pSMB->DataCount;
5246 pSMB->ParameterCount = cpu_to_le16(params);
5247 pSMB->TotalParameterCount = pSMB->ParameterCount;
5248 pSMB->Reserved4 = 0;
5249 pSMB->hdr.smb_buf_length += byte_count;
5250 pSMB->ByteCount = cpu_to_le16(byte_count);
5251 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5252 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5253 if (rc) {
5254 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5255 }
5256
5257 cifs_buf_release(pSMB);
5258
5259 if (rc == -EAGAIN)
5260 goto SetEARetry;
5261
5262 return rc;
5263}
5264
5265#endif