blob: 098790eb2aa161967538c91b734c3fe45fa5d8b7 [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;
Al Viro733f99a2006-10-14 16:48:26 +0100402 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 if(ses->server)
405 server = ses->server;
406 else {
407 rc = -EIO;
408 return rc;
409 }
410 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
411 (void **) &pSMB, (void **) &pSMBr);
412 if (rc)
413 return rc;
Steve French750d1152006-06-27 06:28:30 +0000414
415 /* if any of auth flags (ie not sign or seal) are overriden use them */
416 if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
417 secFlags = ses->overrideSecFlg;
418 else /* if override flags set only sign/seal OR them with global auth */
419 secFlags = extended_security | ses->overrideSecFlg;
420
Steve Frenchf40c5622006-06-28 00:13:38 +0000421 cFYI(1,("secFlags 0x%x",secFlags));
422
Steve French1982c342005-08-17 12:38:22 -0700423 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French750d1152006-06-27 06:28:30 +0000425 if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000426 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000427
428 count = 0;
429 for(i=0;i<CIFS_NUM_PROT;i++) {
430 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
431 count += strlen(protocols[i].name) + 1;
432 /* null at end of source and target buffers anyway */
433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 pSMB->hdr.smb_buf_length += count;
435 pSMB->ByteCount = cpu_to_le16(count);
436
437 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000439 if (rc != 0)
440 goto neg_err_exit;
441
Al Viro733f99a2006-10-14 16:48:26 +0100442 dialect = le16_to_cpu(pSMBr->DialectIndex);
443 cFYI(1,("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000444 /* Check wct = 1 error case */
Al Viro733f99a2006-10-14 16:48:26 +0100445 if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000446 /* core returns wct = 1, but we do not ask for core - otherwise
447 small wct just comes when dialect index is -1 indicating we
448 could not negotiate a common dialect */
449 rc = -EOPNOTSUPP;
450 goto neg_err_exit;
451#ifdef CONFIG_CIFS_WEAK_PW_HASH
452 } else if((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100453 && ((dialect == LANMAN_PROT)
454 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000455 __s16 tmp;
Steve French254e55e2006-06-04 05:53:15 +0000456 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
457
Steve French750d1152006-06-27 06:28:30 +0000458 if((secFlags & CIFSSEC_MAY_LANMAN) ||
459 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000460 server->secType = LANMAN;
461 else {
462 cERROR(1, ("mount failed weak security disabled"
463 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000464 rc = -EOPNOTSUPP;
465 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000466 }
467 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
468 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
469 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000470 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000471 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
472 /* even though we do not use raw we might as well set this
473 accurately, in case we ever find a need for it */
474 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
475 server->maxRw = 0xFF00;
476 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
477 } else {
478 server->maxRw = 0;/* we do not need to use raw anyway */
479 server->capabilities = CAP_MPX_MODE;
480 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000481 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000482 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000483 /* OS/2 often does not set timezone therefore
484 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000485 * Could deviate slightly from the right zone.
486 * Smallest defined timezone difference is 15 minutes
487 * (i.e. Nepal). Rounding up/down is done to match
488 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000489 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000490 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000491 struct timespec ts, utc;
492 utc = CURRENT_TIME;
493 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
494 le16_to_cpu(rsp->SrvTime.Time));
495 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
496 (int)ts.tv_sec, (int)utc.tv_sec,
497 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000498 val = (int)(utc.tv_sec - ts.tv_sec);
499 seconds = val < 0 ? -val : val;
Steve French947a5062006-10-02 05:55:25 +0000500 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000501 remain = seconds % MIN_TZ_ADJ;
502 if(remain >= (MIN_TZ_ADJ / 2))
503 result += MIN_TZ_ADJ;
504 if(val < 0)
505 result = - result;
506 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000507 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000508 server->timeAdj = (int)tmp;
509 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000510 }
Steve French175ec9e2006-09-30 01:07:38 +0000511 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000512
Steve French39798772006-05-31 22:40:51 +0000513
Steve French254e55e2006-06-04 05:53:15 +0000514 /* BB get server time for time conversions and add
515 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000516
Steve French25ee4a92006-09-30 00:54:23 +0000517 if (rsp->EncryptionKeyLength ==
518 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000519 memcpy(server->cryptKey, rsp->EncryptionKey,
520 CIFS_CRYPTO_KEY_SIZE);
521 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
522 rc = -EIO; /* need cryptkey unless plain text */
523 goto neg_err_exit;
524 }
Steve French39798772006-05-31 22:40:51 +0000525
Steve French254e55e2006-06-04 05:53:15 +0000526 cFYI(1,("LANMAN negotiated"));
527 /* we will not end up setting signing flags - as no signing
528 was in LANMAN and server did not return the flags on */
529 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000530#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000531 } else if(pSMBr->hdr.WordCount == 13) {
532 cERROR(1,("mount failed, cifs module not built "
533 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000534 rc = -EOPNOTSUPP;
535#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000536 goto neg_err_exit;
537 } else if(pSMBr->hdr.WordCount != 17) {
538 /* unknown wct */
539 rc = -EOPNOTSUPP;
540 goto neg_err_exit;
541 }
542 /* else wct == 17 NTLM */
543 server->secMode = pSMBr->SecurityMode;
544 if((server->secMode & SECMODE_USER) == 0)
545 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000546
Steve French254e55e2006-06-04 05:53:15 +0000547 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000548#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000549 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000550#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000551 cERROR(1,("Server requests plain text password"
552 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000553
Steve Frenchf40c5622006-06-28 00:13:38 +0000554 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000555 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000556 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000557 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000558 else if(secFlags & CIFSSEC_MAY_NTLMV2)
559 server->secType = NTLMv2;
560 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000561
Steve French254e55e2006-06-04 05:53:15 +0000562 /* one byte, so no need to convert this or EncryptionKeyLen from
563 little endian */
564 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
565 /* probably no need to store and check maxvcs */
566 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000568 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
569 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
570 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
571 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000572 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
573 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000574 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
575 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
576 CIFS_CRYPTO_KEY_SIZE);
577 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
578 && (pSMBr->EncryptionKeyLength == 0)) {
579 /* decode security blob */
580 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
581 rc = -EIO; /* no crypt key only if plain text pwd */
582 goto neg_err_exit;
583 }
584
585 /* BB might be helpful to save off the domain of server here */
586
587 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
588 (server->capabilities & CAP_EXTENDED_SECURITY)) {
589 count = pSMBr->ByteCount;
590 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000592 else if (count == 16) {
593 server->secType = RawNTLMSSP;
594 if (server->socketUseCount.counter > 1) {
595 if (memcmp(server->server_GUID,
596 pSMBr->u.extended_response.
597 GUID, 16) != 0) {
598 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000600 pSMBr->u.extended_response.GUID,
601 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 }
Steve French254e55e2006-06-04 05:53:15 +0000603 } else
604 memcpy(server->server_GUID,
605 pSMBr->u.extended_response.GUID, 16);
606 } else {
607 rc = decode_negTokenInit(pSMBr->u.extended_response.
608 SecurityBlob,
609 count - 16,
610 &server->secType);
611 if(rc == 1) {
612 /* BB Need to fill struct for sessetup here */
613 rc = -EOPNOTSUPP;
614 } else {
615 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Steve French254e55e2006-06-04 05:53:15 +0000618 } else
619 server->capabilities &= ~CAP_EXTENDED_SECURITY;
620
Steve French6344a422006-06-12 04:18:35 +0000621#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000622signing_check:
Steve French6344a422006-06-12 04:18:35 +0000623#endif
Steve French254e55e2006-06-04 05:53:15 +0000624 if(sign_CIFS_PDUs == FALSE) {
625 if(server->secMode & SECMODE_SIGN_REQUIRED)
626 cERROR(1,("Server requires "
627 "/proc/fs/cifs/PacketSigningEnabled to be on"));
628 server->secMode &=
629 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
630 } else if(sign_CIFS_PDUs == 1) {
631 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
632 server->secMode &=
633 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
634 } else if(sign_CIFS_PDUs == 2) {
635 if((server->secMode &
636 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
637 cERROR(1,("signing required but server lacks support"));
638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 }
Steve French39798772006-05-31 22:40:51 +0000640neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700641 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000642
643 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return rc;
645}
646
647int
648CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
649{
650 struct smb_hdr *smb_buffer;
651 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
652 int rc = 0;
653 int length;
654
655 cFYI(1, ("In tree disconnect"));
656 /*
657 * If last user of the connection and
658 * connection alive - disconnect it
659 * If this is the last connection on the server session disconnect it
660 * (and inside session disconnect we should check if tcp socket needs
661 * to be freed and kernel thread woken up).
662 */
663 if (tcon)
664 down(&tcon->tconSem);
665 else
666 return -EIO;
667
668 atomic_dec(&tcon->useCount);
669 if (atomic_read(&tcon->useCount) > 0) {
670 up(&tcon->tconSem);
671 return -EBUSY;
672 }
673
674 /* No need to return error on this operation if tid invalidated and
675 closed on server already e.g. due to tcp session crashing */
676 if(tcon->tidStatus == CifsNeedReconnect) {
677 up(&tcon->tconSem);
678 return 0;
679 }
680
681 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
682 up(&tcon->tconSem);
683 return -EIO;
684 }
Steve French09d1db52005-04-28 22:41:08 -0700685 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
686 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (rc) {
688 up(&tcon->tconSem);
689 return rc;
690 } else {
691 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
694 &length, 0);
695 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700696 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 if (smb_buffer)
699 cifs_small_buf_release(smb_buffer);
700 up(&tcon->tconSem);
701
702 /* No need to return error on this operation if tid invalidated and
703 closed on server already e.g. due to tcp session crashing */
704 if (rc == -EAGAIN)
705 rc = 0;
706
707 return rc;
708}
709
710int
711CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
712{
713 struct smb_hdr *smb_buffer_response;
714 LOGOFF_ANDX_REQ *pSMB;
715 int rc = 0;
716 int length;
717
718 cFYI(1, ("In SMBLogoff for session disconnect"));
719 if (ses)
720 down(&ses->sesSem);
721 else
722 return -EIO;
723
724 atomic_dec(&ses->inUse);
725 if (atomic_read(&ses->inUse) > 0) {
726 up(&ses->sesSem);
727 return -EBUSY;
728 }
729 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
730 if (rc) {
731 up(&ses->sesSem);
732 return rc;
733 }
734
735 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
736
737 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700738 pSMB->hdr.Mid = GetNextMid(ses->server);
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if(ses->server->secMode &
741 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
742 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
743 }
744
745 pSMB->hdr.Uid = ses->Suid;
746
747 pSMB->AndXCommand = 0xFF;
748 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
749 smb_buffer_response, &length, 0);
750 if (ses->server) {
751 atomic_dec(&ses->server->socketUseCount);
752 if (atomic_read(&ses->server->socketUseCount) == 0) {
753 spin_lock(&GlobalMid_Lock);
754 ses->server->tcpStatus = CifsExiting;
755 spin_unlock(&GlobalMid_Lock);
756 rc = -ESHUTDOWN;
757 }
758 }
Steve Frencha59c6582005-08-17 12:12:19 -0700759 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700760 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 /* if session dead then we do not need to do ulogoff,
763 since server closed smb session, no sense reporting
764 error */
765 if (rc == -EAGAIN)
766 rc = 0;
767 return rc;
768}
769
770int
Steve French737b7582005-04-28 22:41:06 -0700771CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
772 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
774 DELETE_FILE_REQ *pSMB = NULL;
775 DELETE_FILE_RSP *pSMBr = NULL;
776 int rc = 0;
777 int bytes_returned;
778 int name_len;
779
780DelFileRetry:
781 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
782 (void **) &pSMBr);
783 if (rc)
784 return rc;
785
786 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
787 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500788 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700789 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 name_len++; /* trailing null */
791 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700792 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 name_len = strnlen(fileName, PATH_MAX);
794 name_len++; /* trailing null */
795 strncpy(pSMB->fileName, fileName, name_len);
796 }
797 pSMB->SearchAttributes =
798 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
799 pSMB->BufferFormat = 0x04;
800 pSMB->hdr.smb_buf_length += name_len + 1;
801 pSMB->ByteCount = cpu_to_le16(name_len + 1);
802 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
803 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700804 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 if (rc) {
806 cFYI(1, ("Error in RMFile = %d", rc));
807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
809 cifs_buf_release(pSMB);
810 if (rc == -EAGAIN)
811 goto DelFileRetry;
812
813 return rc;
814}
815
816int
Steve French737b7582005-04-28 22:41:06 -0700817CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
818 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819{
820 DELETE_DIRECTORY_REQ *pSMB = NULL;
821 DELETE_DIRECTORY_RSP *pSMBr = NULL;
822 int rc = 0;
823 int bytes_returned;
824 int name_len;
825
826 cFYI(1, ("In CIFSSMBRmDir"));
827RmDirRetry:
828 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
829 (void **) &pSMBr);
830 if (rc)
831 return rc;
832
833 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700834 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
835 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 name_len++; /* trailing null */
837 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700838 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 name_len = strnlen(dirName, PATH_MAX);
840 name_len++; /* trailing null */
841 strncpy(pSMB->DirName, dirName, name_len);
842 }
843
844 pSMB->BufferFormat = 0x04;
845 pSMB->hdr.smb_buf_length += name_len + 1;
846 pSMB->ByteCount = cpu_to_le16(name_len + 1);
847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700849 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (rc) {
851 cFYI(1, ("Error in RMDir = %d", rc));
852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854 cifs_buf_release(pSMB);
855 if (rc == -EAGAIN)
856 goto RmDirRetry;
857 return rc;
858}
859
860int
861CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700862 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
864 int rc = 0;
865 CREATE_DIRECTORY_REQ *pSMB = NULL;
866 CREATE_DIRECTORY_RSP *pSMBr = NULL;
867 int bytes_returned;
868 int name_len;
869
870 cFYI(1, ("In CIFSSMBMkDir"));
871MkDirRetry:
872 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
873 (void **) &pSMBr);
874 if (rc)
875 return rc;
876
877 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500878 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700879 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 name_len++; /* trailing null */
881 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700882 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 name_len = strnlen(name, PATH_MAX);
884 name_len++; /* trailing null */
885 strncpy(pSMB->DirName, name, name_len);
886 }
887
888 pSMB->BufferFormat = 0x04;
889 pSMB->hdr.smb_buf_length += name_len + 1;
890 pSMB->ByteCount = cpu_to_le16(name_len + 1);
891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700893 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 if (rc) {
895 cFYI(1, ("Error in Mkdir = %d", rc));
896 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700897
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 cifs_buf_release(pSMB);
899 if (rc == -EAGAIN)
900 goto MkDirRetry;
901 return rc;
902}
903
Steve Frencha9d02ad2005-08-24 23:06:05 -0700904static __u16 convert_disposition(int disposition)
905{
906 __u16 ofun = 0;
907
908 switch (disposition) {
909 case FILE_SUPERSEDE:
910 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
911 break;
912 case FILE_OPEN:
913 ofun = SMBOPEN_OAPPEND;
914 break;
915 case FILE_CREATE:
916 ofun = SMBOPEN_OCREATE;
917 break;
918 case FILE_OPEN_IF:
919 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
920 break;
921 case FILE_OVERWRITE:
922 ofun = SMBOPEN_OTRUNC;
923 break;
924 case FILE_OVERWRITE_IF:
925 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
926 break;
927 default:
928 cFYI(1,("unknown disposition %d",disposition));
929 ofun = SMBOPEN_OAPPEND; /* regular open */
930 }
931 return ofun;
932}
933
934int
935SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
936 const char *fileName, const int openDisposition,
937 const int access_flags, const int create_options, __u16 * netfid,
938 int *pOplock, FILE_ALL_INFO * pfile_info,
939 const struct nls_table *nls_codepage, int remap)
940{
941 int rc = -EACCES;
942 OPENX_REQ *pSMB = NULL;
943 OPENX_RSP *pSMBr = NULL;
944 int bytes_returned;
945 int name_len;
946 __u16 count;
947
948OldOpenRetry:
949 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
950 (void **) &pSMBr);
951 if (rc)
952 return rc;
953
954 pSMB->AndXCommand = 0xFF; /* none */
955
956 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
957 count = 1; /* account for one byte pad to word boundary */
958 name_len =
959 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
960 fileName, PATH_MAX, nls_codepage, remap);
961 name_len++; /* trailing null */
962 name_len *= 2;
963 } else { /* BB improve check for buffer overruns BB */
964 count = 0; /* no pad */
965 name_len = strnlen(fileName, PATH_MAX);
966 name_len++; /* trailing null */
967 strncpy(pSMB->fileName, fileName, name_len);
968 }
969 if (*pOplock & REQ_OPLOCK)
970 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
971 else if (*pOplock & REQ_BATCHOPLOCK) {
972 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
973 }
974 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
975 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
976 /* 0 = read
977 1 = write
978 2 = rw
979 3 = execute
980 */
981 pSMB->Mode = cpu_to_le16(2);
982 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
983 /* set file as system file if special file such
984 as fifo and server expecting SFU style and
985 no Unix extensions */
986
987 if(create_options & CREATE_OPTION_SPECIAL)
988 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
989 else
Steve French3e87d802005-09-18 20:49:21 -0700990 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700991
992 /* if ((omode & S_IWUGO) == 0)
993 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
994 /* Above line causes problems due to vfs splitting create into two
995 pieces - need to set mode after file created not while it is
996 being created */
997
998 /* BB FIXME BB */
999/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
1000 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001001
1002 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001003 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001004 count += name_len;
1005 pSMB->hdr.smb_buf_length += count;
1006
1007 pSMB->ByteCount = cpu_to_le16(count);
1008 /* long_op set to 1 to allow for oplock break timeouts */
1009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1010 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1011 cifs_stats_inc(&tcon->num_opens);
1012 if (rc) {
1013 cFYI(1, ("Error in Open = %d", rc));
1014 } else {
1015 /* BB verify if wct == 15 */
1016
1017/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1018
1019 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1020 /* Let caller know file was created so we can set the mode. */
1021 /* Do we care about the CreateAction in any other cases? */
1022 /* BB FIXME BB */
1023/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1024 *pOplock |= CIFS_CREATE_ACTION; */
1025 /* BB FIXME END */
1026
1027 if(pfile_info) {
1028 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1029 pfile_info->LastAccessTime = 0; /* BB fixme */
1030 pfile_info->LastWriteTime = 0; /* BB fixme */
1031 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001032 pfile_info->Attributes =
1033 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001034 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001035 pfile_info->AllocationSize =
1036 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1037 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001038 pfile_info->NumberOfLinks = cpu_to_le32(1);
1039 }
1040 }
1041
1042 cifs_buf_release(pSMB);
1043 if (rc == -EAGAIN)
1044 goto OldOpenRetry;
1045 return rc;
1046}
1047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048int
1049CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1050 const char *fileName, const int openDisposition,
1051 const int access_flags, const int create_options, __u16 * netfid,
1052 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001053 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054{
1055 int rc = -EACCES;
1056 OPEN_REQ *pSMB = NULL;
1057 OPEN_RSP *pSMBr = NULL;
1058 int bytes_returned;
1059 int name_len;
1060 __u16 count;
1061
1062openRetry:
1063 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1064 (void **) &pSMBr);
1065 if (rc)
1066 return rc;
1067
1068 pSMB->AndXCommand = 0xFF; /* none */
1069
1070 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1071 count = 1; /* account for one byte pad to word boundary */
1072 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001073 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001074 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 name_len++; /* trailing null */
1076 name_len *= 2;
1077 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001078 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 count = 0; /* no pad */
1080 name_len = strnlen(fileName, PATH_MAX);
1081 name_len++; /* trailing null */
1082 pSMB->NameLength = cpu_to_le16(name_len);
1083 strncpy(pSMB->fileName, fileName, name_len);
1084 }
1085 if (*pOplock & REQ_OPLOCK)
1086 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1087 else if (*pOplock & REQ_BATCHOPLOCK) {
1088 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1089 }
1090 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1091 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001092 /* set file as system file if special file such
1093 as fifo and server expecting SFU style and
1094 no Unix extensions */
1095 if(create_options & CREATE_OPTION_SPECIAL)
1096 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1097 else
1098 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 /* XP does not handle ATTR_POSIX_SEMANTICS */
1100 /* but it helps speed up case sensitive checks for other
1101 servers such as Samba */
1102 if (tcon->ses->capabilities & CAP_UNIX)
1103 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1104
1105 /* if ((omode & S_IWUGO) == 0)
1106 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1107 /* Above line causes problems due to vfs splitting create into two
1108 pieces - need to set mode after file created not while it is
1109 being created */
1110 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1111 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001112 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001113 /* BB Expirement with various impersonation levels and verify */
1114 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 pSMB->SecurityFlags =
1116 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1117
1118 count += name_len;
1119 pSMB->hdr.smb_buf_length += count;
1120
1121 pSMB->ByteCount = cpu_to_le16(count);
1122 /* long_op set to 1 to allow for oplock break timeouts */
1123 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1124 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001125 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 if (rc) {
1127 cFYI(1, ("Error in Open = %d", rc));
1128 } else {
Steve French09d1db52005-04-28 22:41:08 -07001129 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1131 /* Let caller know file was created so we can set the mode. */
1132 /* Do we care about the CreateAction in any other cases? */
1133 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1134 *pOplock |= CIFS_CREATE_ACTION;
1135 if(pfile_info) {
1136 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1137 36 /* CreationTime to Attributes */);
1138 /* the file_info buf is endian converted by caller */
1139 pfile_info->AllocationSize = pSMBr->AllocationSize;
1140 pfile_info->EndOfFile = pSMBr->EndOfFile;
1141 pfile_info->NumberOfLinks = cpu_to_le32(1);
1142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 cifs_buf_release(pSMB);
1146 if (rc == -EAGAIN)
1147 goto openRetry;
1148 return rc;
1149}
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151int
1152CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001153 const int netfid, const unsigned int count,
1154 const __u64 lseek, unsigned int *nbytes, char **buf,
1155 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156{
1157 int rc = -EACCES;
1158 READ_REQ *pSMB = NULL;
1159 READ_RSP *pSMBr = NULL;
1160 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001161 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001162 int resp_buf_type = 0;
1163 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
1165 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001166 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1167 wct = 12;
1168 else
1169 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
1171 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001172 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 if (rc)
1174 return rc;
1175
1176 /* tcon and ses pointer are checked in smb_init */
1177 if (tcon->ses->server == NULL)
1178 return -ECONNABORTED;
1179
Steve Frenchec637e32005-12-12 20:53:18 -08001180 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 pSMB->Fid = netfid;
1182 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001183 if(wct == 12)
1184 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001185 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1186 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 pSMB->Remaining = 0;
1189 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1190 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001191 if(wct == 12)
1192 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1193 else {
1194 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001195 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001196 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001197 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001198 }
Steve Frenchec637e32005-12-12 20:53:18 -08001199
1200 iov[0].iov_base = (char *)pSMB;
1201 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1202 rc = SendReceive2(xid, tcon->ses, iov,
1203 1 /* num iovecs */,
1204 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001205 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001206 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 if (rc) {
1208 cERROR(1, ("Send error in read = %d", rc));
1209 } else {
1210 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1211 data_length = data_length << 16;
1212 data_length += le16_to_cpu(pSMBr->DataLength);
1213 *nbytes = data_length;
1214
1215 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001216 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 || (data_length > count)) {
1218 cFYI(1,("bad length %d for count %d",data_length,count));
1219 rc = -EIO;
1220 *nbytes = 0;
1221 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001222 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001224/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1225 cERROR(1,("Faulting on read rc = %d",rc));
1226 rc = -EFAULT;
1227 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001229 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 }
1231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
Steve French4b8f9302006-02-26 16:41:18 +00001233/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001234 if(*buf) {
1235 if(resp_buf_type == CIFS_SMALL_BUFFER)
1236 cifs_small_buf_release(iov[0].iov_base);
1237 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1238 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001239 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1240 /* return buffer to caller to free */
1241 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001242 if(resp_buf_type == CIFS_SMALL_BUFFER)
1243 *pbuf_type = CIFS_SMALL_BUFFER;
1244 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1245 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001246 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001247
1248 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 since file handle passed in no longer valid */
1250 return rc;
1251}
1252
Steve Frenchec637e32005-12-12 20:53:18 -08001253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254int
1255CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1256 const int netfid, const unsigned int count,
1257 const __u64 offset, unsigned int *nbytes, const char *buf,
1258 const char __user * ubuf, const int long_op)
1259{
1260 int rc = -EACCES;
1261 WRITE_REQ *pSMB = NULL;
1262 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001263 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 __u32 bytes_sent;
1265 __u16 byte_count;
1266
1267 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001268 if(tcon->ses == NULL)
1269 return -ECONNABORTED;
1270
1271 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1272 wct = 14;
1273 else
1274 wct = 12;
1275
1276 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 (void **) &pSMBr);
1278 if (rc)
1279 return rc;
1280 /* tcon and ses pointer are checked in smb_init */
1281 if (tcon->ses->server == NULL)
1282 return -ECONNABORTED;
1283
1284 pSMB->AndXCommand = 0xFF; /* none */
1285 pSMB->Fid = netfid;
1286 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001287 if(wct == 14)
1288 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1289 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1290 return -EIO;
1291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 pSMB->Reserved = 0xFFFFFFFF;
1293 pSMB->WriteMode = 0;
1294 pSMB->Remaining = 0;
1295
1296 /* Can increase buffer size if buffer is big enough in some cases - ie we
1297 can send more if LARGE_WRITE_X capability returned by the server and if
1298 our buffer is big enough or if we convert to iovecs on socket writes
1299 and eliminate the copy to the CIFS buffer */
1300 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1301 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1302 } else {
1303 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1304 & ~0xFF;
1305 }
1306
1307 if (bytes_sent > count)
1308 bytes_sent = count;
1309 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001310 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if(buf)
1312 memcpy(pSMB->Data,buf,bytes_sent);
1313 else if(ubuf) {
1314 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1315 cifs_buf_release(pSMB);
1316 return -EFAULT;
1317 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001318 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 /* No buffer */
1320 cifs_buf_release(pSMB);
1321 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001322 } /* else setting file size with write of zero bytes */
1323 if(wct == 14)
1324 byte_count = bytes_sent + 1; /* pad */
1325 else /* wct == 12 */ {
1326 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1329 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001330 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001331
1332 if(wct == 14)
1333 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001334 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001335 struct smb_com_writex_req * pSMBW =
1336 (struct smb_com_writex_req *)pSMB;
1337 pSMBW->ByteCount = cpu_to_le16(byte_count);
1338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
1340 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1341 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001342 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 if (rc) {
1344 cFYI(1, ("Send error in write = %d", rc));
1345 *nbytes = 0;
1346 } else {
1347 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1348 *nbytes = (*nbytes) << 16;
1349 *nbytes += le16_to_cpu(pSMBr->Count);
1350 }
1351
1352 cifs_buf_release(pSMB);
1353
1354 /* Note: On -EAGAIN error only caller can retry on handle based calls
1355 since file handle passed in no longer valid */
1356
1357 return rc;
1358}
1359
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001360int
1361CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001363 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1364 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
1366 int rc = -EACCES;
1367 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001368 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001369 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001370 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Steve Frenchff7feac2005-11-15 16:45:16 -08001372 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1373
Steve French8cc64c62005-10-03 13:49:43 -07001374 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1375 wct = 14;
1376 else
1377 wct = 12;
1378 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 if (rc)
1380 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 /* tcon and ses pointer are checked in smb_init */
1382 if (tcon->ses->server == NULL)
1383 return -ECONNABORTED;
1384
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001385 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 pSMB->Fid = netfid;
1387 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001388 if(wct == 14)
1389 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1390 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1391 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 pSMB->Reserved = 0xFFFFFFFF;
1393 pSMB->WriteMode = 0;
1394 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 pSMB->DataOffset =
1397 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1398
Steve French3e844692005-10-03 13:37:24 -07001399 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1400 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001401 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001402 if(wct == 14)
1403 pSMB->hdr.smb_buf_length += count+1;
1404 else /* wct == 12 */
1405 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1406 if(wct == 14)
1407 pSMB->ByteCount = cpu_to_le16(count + 1);
1408 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1409 struct smb_com_writex_req * pSMBW =
1410 (struct smb_com_writex_req *)pSMB;
1411 pSMBW->ByteCount = cpu_to_le16(count + 5);
1412 }
Steve French3e844692005-10-03 13:37:24 -07001413 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001414 if(wct == 14)
1415 iov[0].iov_len = smb_hdr_len + 4;
1416 else /* wct == 12 pad bigger by four bytes */
1417 iov[0].iov_len = smb_hdr_len + 8;
1418
Steve French3e844692005-10-03 13:37:24 -07001419
Steve Frenchec637e32005-12-12 20:53:18 -08001420 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001421 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001422 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001424 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001426 } else if(resp_buf_type == 0) {
1427 /* presumably this can not happen, but best to be safe */
1428 rc = -EIO;
1429 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001430 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001431 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001432 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1433 *nbytes = (*nbytes) << 16;
1434 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
Steve French4b8f9302006-02-26 16:41:18 +00001437/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001438 if(resp_buf_type == CIFS_SMALL_BUFFER)
1439 cifs_small_buf_release(iov[0].iov_base);
1440 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1441 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
1443 /* Note: On -EAGAIN error only caller can retry on handle based calls
1444 since file handle passed in no longer valid */
1445
1446 return rc;
1447}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001448
1449
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450int
1451CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1452 const __u16 smb_file_id, const __u64 len,
1453 const __u64 offset, const __u32 numUnlock,
1454 const __u32 numLock, const __u8 lockType, const int waitFlag)
1455{
1456 int rc = 0;
1457 LOCK_REQ *pSMB = NULL;
1458 LOCK_RSP *pSMBr = NULL;
1459 int bytes_returned;
1460 int timeout = 0;
1461 __u16 count;
1462
1463 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001464 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1465
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 if (rc)
1467 return rc;
1468
Steve French46810cb2005-04-28 22:41:09 -07001469 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1470
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1472 timeout = -1; /* no response expected */
1473 pSMB->Timeout = 0;
1474 } else if (waitFlag == TRUE) {
1475 timeout = 3; /* blocking operation, no timeout */
1476 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1477 } else {
1478 pSMB->Timeout = 0;
1479 }
1480
1481 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1482 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1483 pSMB->LockType = lockType;
1484 pSMB->AndXCommand = 0xFF; /* none */
1485 pSMB->Fid = smb_file_id; /* netfid stays le */
1486
1487 if((numLock != 0) || (numUnlock != 0)) {
1488 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1489 /* BB where to store pid high? */
1490 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1491 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1492 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1493 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1494 count = sizeof(LOCKING_ANDX_RANGE);
1495 } else {
1496 /* oplock break */
1497 count = 0;
1498 }
1499 pSMB->hdr.smb_buf_length += count;
1500 pSMB->ByteCount = cpu_to_le16(count);
1501
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001502 if (waitFlag) {
1503 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1504 (struct smb_hdr *) pSMBr, &bytes_returned);
1505 } else {
1506 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001508 }
Steve Frencha4544342005-08-24 13:59:35 -07001509 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 if (rc) {
1511 cFYI(1, ("Send error in Lock = %d", rc));
1512 }
Steve French46810cb2005-04-28 22:41:09 -07001513 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
1515 /* Note: On -EAGAIN error only caller can retry on handle based calls
1516 since file handle passed in no longer valid */
1517 return rc;
1518}
1519
1520int
Steve French08547b02006-02-28 22:39:25 +00001521CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1522 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001523 struct file_lock *pLockData, const __u16 lock_type,
1524 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001525{
1526 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1527 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1528 char *data_offset;
1529 struct cifs_posix_lock *parm_data;
1530 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001531 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001532 int bytes_returned = 0;
1533 __u16 params, param_offset, offset, byte_count, count;
1534
1535 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001536
1537 if(pLockData == NULL)
1538 return EINVAL;
1539
Steve French08547b02006-02-28 22:39:25 +00001540 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1541
1542 if (rc)
1543 return rc;
1544
1545 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1546
1547 params = 6;
1548 pSMB->MaxSetupCount = 0;
1549 pSMB->Reserved = 0;
1550 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001551 pSMB->Reserved2 = 0;
1552 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1553 offset = param_offset + params;
1554
1555 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1556
1557 count = sizeof(struct cifs_posix_lock);
1558 pSMB->MaxParameterCount = cpu_to_le16(2);
1559 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1560 pSMB->SetupCount = 1;
1561 pSMB->Reserved3 = 0;
1562 if(get_flag)
1563 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1564 else
1565 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1566 byte_count = 3 /* pad */ + params + count;
1567 pSMB->DataCount = cpu_to_le16(count);
1568 pSMB->ParameterCount = cpu_to_le16(params);
1569 pSMB->TotalDataCount = pSMB->DataCount;
1570 pSMB->TotalParameterCount = pSMB->ParameterCount;
1571 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1572 parm_data = (struct cifs_posix_lock *)
1573 (((char *) &pSMB->hdr.Protocol) + offset);
1574
1575 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001576 if(waitFlag) {
1577 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001578 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001579 pSMB->Timeout = cpu_to_le32(-1);
1580 } else
1581 pSMB->Timeout = 0;
1582
Steve French08547b02006-02-28 22:39:25 +00001583 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001584 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001585 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001586
1587 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001588 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001589 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1590 pSMB->Reserved4 = 0;
1591 pSMB->hdr.smb_buf_length += byte_count;
1592 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001593 if (waitFlag) {
1594 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1595 (struct smb_hdr *) pSMBr, &bytes_returned);
1596 } else {
1597 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001598 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001599 }
1600
Steve French08547b02006-02-28 22:39:25 +00001601 if (rc) {
1602 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001603 } else if (get_flag) {
1604 /* lock structure can be returned on get */
1605 __u16 data_offset;
1606 __u16 data_count;
1607 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001608
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001609 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1610 rc = -EIO; /* bad smb */
1611 goto plk_err_exit;
1612 }
1613 if(pLockData == NULL) {
1614 rc = -EINVAL;
1615 goto plk_err_exit;
1616 }
1617 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1618 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1619 if(data_count < sizeof(struct cifs_posix_lock)) {
1620 rc = -EIO;
1621 goto plk_err_exit;
1622 }
1623 parm_data = (struct cifs_posix_lock *)
1624 ((char *)&pSMBr->hdr.Protocol + data_offset);
1625 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1626 pLockData->fl_type = F_UNLCK;
1627 }
1628
1629plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001630 if (pSMB)
1631 cifs_small_buf_release(pSMB);
1632
1633 /* Note: On -EAGAIN error only caller can retry on handle based calls
1634 since file handle passed in no longer valid */
1635
1636 return rc;
1637}
1638
1639
1640int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1642{
1643 int rc = 0;
1644 CLOSE_REQ *pSMB = NULL;
1645 CLOSE_RSP *pSMBr = NULL;
1646 int bytes_returned;
1647 cFYI(1, ("In CIFSSMBClose"));
1648
1649/* do not retry on dead session on close */
1650 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1651 if(rc == -EAGAIN)
1652 return 0;
1653 if (rc)
1654 return rc;
1655
1656 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1657
1658 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001659 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 pSMB->ByteCount = 0;
1661 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1662 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001663 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 if (rc) {
1665 if(rc!=-EINTR) {
1666 /* EINTR is expected when user ctl-c to kill app */
1667 cERROR(1, ("Send error in Close = %d", rc));
1668 }
1669 }
1670
1671 cifs_small_buf_release(pSMB);
1672
1673 /* Since session is dead, file will be closed on server already */
1674 if(rc == -EAGAIN)
1675 rc = 0;
1676
1677 return rc;
1678}
1679
1680int
1681CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1682 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001683 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684{
1685 int rc = 0;
1686 RENAME_REQ *pSMB = NULL;
1687 RENAME_RSP *pSMBr = NULL;
1688 int bytes_returned;
1689 int name_len, name_len2;
1690 __u16 count;
1691
1692 cFYI(1, ("In CIFSSMBRename"));
1693renameRetry:
1694 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1695 (void **) &pSMBr);
1696 if (rc)
1697 return rc;
1698
1699 pSMB->BufferFormat = 0x04;
1700 pSMB->SearchAttributes =
1701 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1702 ATTR_DIRECTORY);
1703
1704 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1705 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001706 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001707 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 name_len++; /* trailing null */
1709 name_len *= 2;
1710 pSMB->OldFileName[name_len] = 0x04; /* pad */
1711 /* protocol requires ASCII signature byte on Unicode string */
1712 pSMB->OldFileName[name_len + 1] = 0x00;
1713 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001714 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001715 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1717 name_len2 *= 2; /* convert to bytes */
1718 } else { /* BB improve the check for buffer overruns BB */
1719 name_len = strnlen(fromName, PATH_MAX);
1720 name_len++; /* trailing null */
1721 strncpy(pSMB->OldFileName, fromName, name_len);
1722 name_len2 = strnlen(toName, PATH_MAX);
1723 name_len2++; /* trailing null */
1724 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1725 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1726 name_len2++; /* trailing null */
1727 name_len2++; /* signature byte */
1728 }
1729
1730 count = 1 /* 1st signature byte */ + name_len + name_len2;
1731 pSMB->hdr.smb_buf_length += count;
1732 pSMB->ByteCount = cpu_to_le16(count);
1733
1734 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1735 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001736 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 if (rc) {
1738 cFYI(1, ("Send error in rename = %d", rc));
1739 }
1740
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 cifs_buf_release(pSMB);
1742
1743 if (rc == -EAGAIN)
1744 goto renameRetry;
1745
1746 return rc;
1747}
1748
1749int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001750 int netfid, char * target_name,
1751 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752{
1753 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1754 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1755 struct set_file_rename * rename_info;
1756 char *data_offset;
1757 char dummy_string[30];
1758 int rc = 0;
1759 int bytes_returned = 0;
1760 int len_of_str;
1761 __u16 params, param_offset, offset, count, byte_count;
1762
1763 cFYI(1, ("Rename to File by handle"));
1764 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1765 (void **) &pSMBr);
1766 if (rc)
1767 return rc;
1768
1769 params = 6;
1770 pSMB->MaxSetupCount = 0;
1771 pSMB->Reserved = 0;
1772 pSMB->Flags = 0;
1773 pSMB->Timeout = 0;
1774 pSMB->Reserved2 = 0;
1775 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1776 offset = param_offset + params;
1777
1778 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1779 rename_info = (struct set_file_rename *) data_offset;
1780 pSMB->MaxParameterCount = cpu_to_le16(2);
1781 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1782 pSMB->SetupCount = 1;
1783 pSMB->Reserved3 = 0;
1784 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1785 byte_count = 3 /* pad */ + params;
1786 pSMB->ParameterCount = cpu_to_le16(params);
1787 pSMB->TotalParameterCount = pSMB->ParameterCount;
1788 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1789 pSMB->DataOffset = cpu_to_le16(offset);
1790 /* construct random name ".cifs_tmp<inodenum><mid>" */
1791 rename_info->overwrite = cpu_to_le32(1);
1792 rename_info->root_fid = 0;
1793 /* unicode only call */
1794 if(target_name == NULL) {
1795 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001796 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001797 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001799 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001800 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 }
1802 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1803 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1804 byte_count += count;
1805 pSMB->DataCount = cpu_to_le16(count);
1806 pSMB->TotalDataCount = pSMB->DataCount;
1807 pSMB->Fid = netfid;
1808 pSMB->InformationLevel =
1809 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1810 pSMB->Reserved4 = 0;
1811 pSMB->hdr.smb_buf_length += byte_count;
1812 pSMB->ByteCount = cpu_to_le16(byte_count);
1813 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1814 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001815 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 if (rc) {
1817 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1818 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 cifs_buf_release(pSMB);
1821
1822 /* Note: On -EAGAIN error only caller can retry on handle based calls
1823 since file handle passed in no longer valid */
1824
1825 return rc;
1826}
1827
1828int
1829CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1830 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001831 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832{
1833 int rc = 0;
1834 COPY_REQ *pSMB = NULL;
1835 COPY_RSP *pSMBr = NULL;
1836 int bytes_returned;
1837 int name_len, name_len2;
1838 __u16 count;
1839
1840 cFYI(1, ("In CIFSSMBCopy"));
1841copyRetry:
1842 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1843 (void **) &pSMBr);
1844 if (rc)
1845 return rc;
1846
1847 pSMB->BufferFormat = 0x04;
1848 pSMB->Tid2 = target_tid;
1849
1850 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1851
1852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001853 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001854 fromName, PATH_MAX, nls_codepage,
1855 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 name_len++; /* trailing null */
1857 name_len *= 2;
1858 pSMB->OldFileName[name_len] = 0x04; /* pad */
1859 /* protocol requires ASCII signature byte on Unicode string */
1860 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001861 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001862 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1864 name_len2 *= 2; /* convert to bytes */
1865 } else { /* BB improve the check for buffer overruns BB */
1866 name_len = strnlen(fromName, PATH_MAX);
1867 name_len++; /* trailing null */
1868 strncpy(pSMB->OldFileName, fromName, name_len);
1869 name_len2 = strnlen(toName, PATH_MAX);
1870 name_len2++; /* trailing null */
1871 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1872 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1873 name_len2++; /* trailing null */
1874 name_len2++; /* signature byte */
1875 }
1876
1877 count = 1 /* 1st signature byte */ + name_len + name_len2;
1878 pSMB->hdr.smb_buf_length += count;
1879 pSMB->ByteCount = cpu_to_le16(count);
1880
1881 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1882 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1883 if (rc) {
1884 cFYI(1, ("Send error in copy = %d with %d files copied",
1885 rc, le16_to_cpu(pSMBr->CopyCount)));
1886 }
1887 if (pSMB)
1888 cifs_buf_release(pSMB);
1889
1890 if (rc == -EAGAIN)
1891 goto copyRetry;
1892
1893 return rc;
1894}
1895
1896int
1897CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1898 const char *fromName, const char *toName,
1899 const struct nls_table *nls_codepage)
1900{
1901 TRANSACTION2_SPI_REQ *pSMB = NULL;
1902 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1903 char *data_offset;
1904 int name_len;
1905 int name_len_target;
1906 int rc = 0;
1907 int bytes_returned = 0;
1908 __u16 params, param_offset, offset, byte_count;
1909
1910 cFYI(1, ("In Symlink Unix style"));
1911createSymLinkRetry:
1912 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1913 (void **) &pSMBr);
1914 if (rc)
1915 return rc;
1916
1917 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1918 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001919 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 /* find define for this maxpathcomponent */
1921 , nls_codepage);
1922 name_len++; /* trailing null */
1923 name_len *= 2;
1924
1925 } else { /* BB improve the check for buffer overruns BB */
1926 name_len = strnlen(fromName, PATH_MAX);
1927 name_len++; /* trailing null */
1928 strncpy(pSMB->FileName, fromName, name_len);
1929 }
1930 params = 6 + name_len;
1931 pSMB->MaxSetupCount = 0;
1932 pSMB->Reserved = 0;
1933 pSMB->Flags = 0;
1934 pSMB->Timeout = 0;
1935 pSMB->Reserved2 = 0;
1936 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1937 InformationLevel) - 4;
1938 offset = param_offset + params;
1939
1940 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1941 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1942 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001943 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 /* find define for this maxpathcomponent */
1945 , nls_codepage);
1946 name_len_target++; /* trailing null */
1947 name_len_target *= 2;
1948 } else { /* BB improve the check for buffer overruns BB */
1949 name_len_target = strnlen(toName, PATH_MAX);
1950 name_len_target++; /* trailing null */
1951 strncpy(data_offset, toName, name_len_target);
1952 }
1953
1954 pSMB->MaxParameterCount = cpu_to_le16(2);
1955 /* BB find exact max on data count below from sess */
1956 pSMB->MaxDataCount = cpu_to_le16(1000);
1957 pSMB->SetupCount = 1;
1958 pSMB->Reserved3 = 0;
1959 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1960 byte_count = 3 /* pad */ + params + name_len_target;
1961 pSMB->DataCount = cpu_to_le16(name_len_target);
1962 pSMB->ParameterCount = cpu_to_le16(params);
1963 pSMB->TotalDataCount = pSMB->DataCount;
1964 pSMB->TotalParameterCount = pSMB->ParameterCount;
1965 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1966 pSMB->DataOffset = cpu_to_le16(offset);
1967 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1968 pSMB->Reserved4 = 0;
1969 pSMB->hdr.smb_buf_length += byte_count;
1970 pSMB->ByteCount = cpu_to_le16(byte_count);
1971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001973 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 if (rc) {
1975 cFYI(1,
1976 ("Send error in SetPathInfo (create symlink) = %d",
1977 rc));
1978 }
1979
1980 if (pSMB)
1981 cifs_buf_release(pSMB);
1982
1983 if (rc == -EAGAIN)
1984 goto createSymLinkRetry;
1985
1986 return rc;
1987}
1988
1989int
1990CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1991 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001992 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993{
1994 TRANSACTION2_SPI_REQ *pSMB = NULL;
1995 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1996 char *data_offset;
1997 int name_len;
1998 int name_len_target;
1999 int rc = 0;
2000 int bytes_returned = 0;
2001 __u16 params, param_offset, offset, byte_count;
2002
2003 cFYI(1, ("In Create Hard link Unix style"));
2004createHardLinkRetry:
2005 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2006 (void **) &pSMBr);
2007 if (rc)
2008 return rc;
2009
2010 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002011 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002012 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 name_len++; /* trailing null */
2014 name_len *= 2;
2015
2016 } else { /* BB improve the check for buffer overruns BB */
2017 name_len = strnlen(toName, PATH_MAX);
2018 name_len++; /* trailing null */
2019 strncpy(pSMB->FileName, toName, name_len);
2020 }
2021 params = 6 + name_len;
2022 pSMB->MaxSetupCount = 0;
2023 pSMB->Reserved = 0;
2024 pSMB->Flags = 0;
2025 pSMB->Timeout = 0;
2026 pSMB->Reserved2 = 0;
2027 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2028 InformationLevel) - 4;
2029 offset = param_offset + params;
2030
2031 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2032 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2033 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002034 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002035 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 name_len_target++; /* trailing null */
2037 name_len_target *= 2;
2038 } else { /* BB improve the check for buffer overruns BB */
2039 name_len_target = strnlen(fromName, PATH_MAX);
2040 name_len_target++; /* trailing null */
2041 strncpy(data_offset, fromName, name_len_target);
2042 }
2043
2044 pSMB->MaxParameterCount = cpu_to_le16(2);
2045 /* BB find exact max on data count below from sess*/
2046 pSMB->MaxDataCount = cpu_to_le16(1000);
2047 pSMB->SetupCount = 1;
2048 pSMB->Reserved3 = 0;
2049 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2050 byte_count = 3 /* pad */ + params + name_len_target;
2051 pSMB->ParameterCount = cpu_to_le16(params);
2052 pSMB->TotalParameterCount = pSMB->ParameterCount;
2053 pSMB->DataCount = cpu_to_le16(name_len_target);
2054 pSMB->TotalDataCount = pSMB->DataCount;
2055 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2056 pSMB->DataOffset = cpu_to_le16(offset);
2057 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2058 pSMB->Reserved4 = 0;
2059 pSMB->hdr.smb_buf_length += byte_count;
2060 pSMB->ByteCount = cpu_to_le16(byte_count);
2061 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2062 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002063 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 if (rc) {
2065 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2066 }
2067
2068 cifs_buf_release(pSMB);
2069 if (rc == -EAGAIN)
2070 goto createHardLinkRetry;
2071
2072 return rc;
2073}
2074
2075int
2076CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2077 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002078 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079{
2080 int rc = 0;
2081 NT_RENAME_REQ *pSMB = NULL;
2082 RENAME_RSP *pSMBr = NULL;
2083 int bytes_returned;
2084 int name_len, name_len2;
2085 __u16 count;
2086
2087 cFYI(1, ("In CIFSCreateHardLink"));
2088winCreateHardLinkRetry:
2089
2090 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2091 (void **) &pSMBr);
2092 if (rc)
2093 return rc;
2094
2095 pSMB->SearchAttributes =
2096 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2097 ATTR_DIRECTORY);
2098 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2099 pSMB->ClusterCount = 0;
2100
2101 pSMB->BufferFormat = 0x04;
2102
2103 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2104 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002105 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002106 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 name_len++; /* trailing null */
2108 name_len *= 2;
2109 pSMB->OldFileName[name_len] = 0; /* pad */
2110 pSMB->OldFileName[name_len + 1] = 0x04;
2111 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002112 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002113 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2115 name_len2 *= 2; /* convert to bytes */
2116 } else { /* BB improve the check for buffer overruns BB */
2117 name_len = strnlen(fromName, PATH_MAX);
2118 name_len++; /* trailing null */
2119 strncpy(pSMB->OldFileName, fromName, name_len);
2120 name_len2 = strnlen(toName, PATH_MAX);
2121 name_len2++; /* trailing null */
2122 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2123 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2124 name_len2++; /* trailing null */
2125 name_len2++; /* signature byte */
2126 }
2127
2128 count = 1 /* string type byte */ + name_len + name_len2;
2129 pSMB->hdr.smb_buf_length += count;
2130 pSMB->ByteCount = cpu_to_le16(count);
2131
2132 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2133 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002134 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (rc) {
2136 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2137 }
2138 cifs_buf_release(pSMB);
2139 if (rc == -EAGAIN)
2140 goto winCreateHardLinkRetry;
2141
2142 return rc;
2143}
2144
2145int
2146CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2147 const unsigned char *searchName,
2148 char *symlinkinfo, const int buflen,
2149 const struct nls_table *nls_codepage)
2150{
2151/* SMB_QUERY_FILE_UNIX_LINK */
2152 TRANSACTION2_QPI_REQ *pSMB = NULL;
2153 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2154 int rc = 0;
2155 int bytes_returned;
2156 int name_len;
2157 __u16 params, byte_count;
2158
2159 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2160
2161querySymLinkRetry:
2162 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2163 (void **) &pSMBr);
2164 if (rc)
2165 return rc;
2166
2167 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2168 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002169 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 /* find define for this maxpathcomponent */
2171 , nls_codepage);
2172 name_len++; /* trailing null */
2173 name_len *= 2;
2174 } else { /* BB improve the check for buffer overruns BB */
2175 name_len = strnlen(searchName, PATH_MAX);
2176 name_len++; /* trailing null */
2177 strncpy(pSMB->FileName, searchName, name_len);
2178 }
2179
2180 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2181 pSMB->TotalDataCount = 0;
2182 pSMB->MaxParameterCount = cpu_to_le16(2);
2183 /* BB find exact max data count below from sess structure BB */
2184 pSMB->MaxDataCount = cpu_to_le16(4000);
2185 pSMB->MaxSetupCount = 0;
2186 pSMB->Reserved = 0;
2187 pSMB->Flags = 0;
2188 pSMB->Timeout = 0;
2189 pSMB->Reserved2 = 0;
2190 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2191 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2192 pSMB->DataCount = 0;
2193 pSMB->DataOffset = 0;
2194 pSMB->SetupCount = 1;
2195 pSMB->Reserved3 = 0;
2196 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2197 byte_count = params + 1 /* pad */ ;
2198 pSMB->TotalParameterCount = cpu_to_le16(params);
2199 pSMB->ParameterCount = pSMB->TotalParameterCount;
2200 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2201 pSMB->Reserved4 = 0;
2202 pSMB->hdr.smb_buf_length += byte_count;
2203 pSMB->ByteCount = cpu_to_le16(byte_count);
2204
2205 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2206 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2207 if (rc) {
2208 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2209 } else {
2210 /* decode response */
2211
2212 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2213 if (rc || (pSMBr->ByteCount < 2))
2214 /* BB also check enough total bytes returned */
2215 rc = -EIO; /* bad smb */
2216 else {
2217 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2218 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2219
2220 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2221 name_len = UniStrnlen((wchar_t *) ((char *)
2222 &pSMBr->hdr.Protocol +data_offset),
2223 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002224 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002226 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 data_offset),
2228 name_len, nls_codepage);
2229 } else {
2230 strncpy(symlinkinfo,
2231 (char *) &pSMBr->hdr.Protocol +
2232 data_offset,
2233 min_t(const int, buflen, count));
2234 }
2235 symlinkinfo[buflen] = 0;
2236 /* just in case so calling code does not go off the end of buffer */
2237 }
2238 }
2239 cifs_buf_release(pSMB);
2240 if (rc == -EAGAIN)
2241 goto querySymLinkRetry;
2242 return rc;
2243}
2244
Steve French0a4b92c2006-01-12 15:44:21 -08002245/* Initialize NT TRANSACT SMB into small smb request buffer.
2246 This assumes that all NT TRANSACTS that we init here have
2247 total parm and data under about 400 bytes (to fit in small cifs
2248 buffer size), which is the case so far, it easily fits. NB:
2249 Setup words themselves and ByteCount
2250 MaxSetupCount (size of returned setup area) and
2251 MaxParameterCount (returned parms size) must be set by caller */
2252static int
2253smb_init_ntransact(const __u16 sub_command, const int setup_count,
2254 const int parm_len, struct cifsTconInfo *tcon,
2255 void ** ret_buf)
2256{
2257 int rc;
2258 __u32 temp_offset;
2259 struct smb_com_ntransact_req * pSMB;
2260
2261 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2262 (void **)&pSMB);
2263 if (rc)
2264 return rc;
2265 *ret_buf = (void *)pSMB;
2266 pSMB->Reserved = 0;
2267 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2268 pSMB->TotalDataCount = 0;
2269 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2270 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2271 pSMB->ParameterCount = pSMB->TotalParameterCount;
2272 pSMB->DataCount = pSMB->TotalDataCount;
2273 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2274 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2275 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2276 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2277 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2278 pSMB->SubCommand = cpu_to_le16(sub_command);
2279 return 0;
2280}
2281
2282static int
2283validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2284 int * pdatalen, int * pparmlen)
2285{
2286 char * end_of_smb;
2287 __u32 data_count, data_offset, parm_count, parm_offset;
2288 struct smb_com_ntransact_rsp * pSMBr;
2289
2290 if(buf == NULL)
2291 return -EINVAL;
2292
2293 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2294
2295 /* ByteCount was converted from little endian in SendReceive */
2296 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2297 (char *)&pSMBr->ByteCount;
2298
2299
2300 data_offset = le32_to_cpu(pSMBr->DataOffset);
2301 data_count = le32_to_cpu(pSMBr->DataCount);
2302 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2303 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2304
2305 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2306 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2307
2308 /* should we also check that parm and data areas do not overlap? */
2309 if(*ppparm > end_of_smb) {
2310 cFYI(1,("parms start after end of smb"));
2311 return -EINVAL;
2312 } else if(parm_count + *ppparm > end_of_smb) {
2313 cFYI(1,("parm end after end of smb"));
2314 return -EINVAL;
2315 } else if(*ppdata > end_of_smb) {
2316 cFYI(1,("data starts after end of smb"));
2317 return -EINVAL;
2318 } else if(data_count + *ppdata > end_of_smb) {
2319 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2320 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2321 return -EINVAL;
2322 } else if(parm_count + data_count > pSMBr->ByteCount) {
2323 cFYI(1,("parm count and data count larger than SMB"));
2324 return -EINVAL;
2325 }
2326 return 0;
2327}
2328
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329int
2330CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2331 const unsigned char *searchName,
2332 char *symlinkinfo, const int buflen,__u16 fid,
2333 const struct nls_table *nls_codepage)
2334{
2335 int rc = 0;
2336 int bytes_returned;
2337 int name_len;
2338 struct smb_com_transaction_ioctl_req * pSMB;
2339 struct smb_com_transaction_ioctl_rsp * pSMBr;
2340
2341 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2342 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2343 (void **) &pSMBr);
2344 if (rc)
2345 return rc;
2346
2347 pSMB->TotalParameterCount = 0 ;
2348 pSMB->TotalDataCount = 0;
2349 pSMB->MaxParameterCount = cpu_to_le32(2);
2350 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002351 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2352 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 pSMB->MaxSetupCount = 4;
2354 pSMB->Reserved = 0;
2355 pSMB->ParameterOffset = 0;
2356 pSMB->DataCount = 0;
2357 pSMB->DataOffset = 0;
2358 pSMB->SetupCount = 4;
2359 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2360 pSMB->ParameterCount = pSMB->TotalParameterCount;
2361 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2362 pSMB->IsFsctl = 1; /* FSCTL */
2363 pSMB->IsRootFlag = 0;
2364 pSMB->Fid = fid; /* file handle always le */
2365 pSMB->ByteCount = 0;
2366
2367 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2368 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2369 if (rc) {
2370 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2371 } else { /* decode response */
2372 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2373 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2374 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2375 /* BB also check enough total bytes returned */
2376 rc = -EIO; /* bad smb */
2377 else {
2378 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002379 char * end_of_smb = 2 /* sizeof byte count */ +
2380 pSMBr->ByteCount +
2381 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
2383 struct reparse_data * reparse_buf = (struct reparse_data *)
2384 ((char *)&pSMBr->hdr.Protocol + data_offset);
2385 if((char*)reparse_buf >= end_of_smb) {
2386 rc = -EIO;
2387 goto qreparse_out;
2388 }
2389 if((reparse_buf->LinkNamesBuf +
2390 reparse_buf->TargetNameOffset +
2391 reparse_buf->TargetNameLen) >
2392 end_of_smb) {
2393 cFYI(1,("reparse buf extended beyond SMB"));
2394 rc = -EIO;
2395 goto qreparse_out;
2396 }
2397
2398 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2399 name_len = UniStrnlen((wchar_t *)
2400 (reparse_buf->LinkNamesBuf +
2401 reparse_buf->TargetNameOffset),
2402 min(buflen/2, reparse_buf->TargetNameLen / 2));
2403 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002404 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 reparse_buf->TargetNameOffset),
2406 name_len, nls_codepage);
2407 } else { /* ASCII names */
2408 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2409 reparse_buf->TargetNameOffset,
2410 min_t(const int, buflen, reparse_buf->TargetNameLen));
2411 }
2412 } else {
2413 rc = -EIO;
2414 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2415 }
2416 symlinkinfo[buflen] = 0; /* just in case so the caller
2417 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002418 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 }
2420 }
2421qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002422 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424 /* Note: On -EAGAIN error only caller can retry on handle based calls
2425 since file handle passed in no longer valid */
2426
2427 return rc;
2428}
2429
2430#ifdef CONFIG_CIFS_POSIX
2431
2432/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2433static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2434{
2435 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002436 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2437 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2438 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2440
2441 return;
2442}
2443
2444/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002445static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2446 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447{
2448 int size = 0;
2449 int i;
2450 __u16 count;
2451 struct cifs_posix_ace * pACE;
2452 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2453 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2454
2455 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2456 return -EOPNOTSUPP;
2457
2458 if(acl_type & ACL_TYPE_ACCESS) {
2459 count = le16_to_cpu(cifs_acl->access_entry_count);
2460 pACE = &cifs_acl->ace_array[0];
2461 size = sizeof(struct cifs_posix_acl);
2462 size += sizeof(struct cifs_posix_ace) * count;
2463 /* check if we would go beyond end of SMB */
2464 if(size_of_data_area < size) {
2465 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2466 return -EINVAL;
2467 }
2468 } else if(acl_type & ACL_TYPE_DEFAULT) {
2469 count = le16_to_cpu(cifs_acl->access_entry_count);
2470 size = sizeof(struct cifs_posix_acl);
2471 size += sizeof(struct cifs_posix_ace) * count;
2472/* skip past access ACEs to get to default ACEs */
2473 pACE = &cifs_acl->ace_array[count];
2474 count = le16_to_cpu(cifs_acl->default_entry_count);
2475 size += sizeof(struct cifs_posix_ace) * count;
2476 /* check if we would go beyond end of SMB */
2477 if(size_of_data_area < size)
2478 return -EINVAL;
2479 } else {
2480 /* illegal type */
2481 return -EINVAL;
2482 }
2483
2484 size = posix_acl_xattr_size(count);
2485 if((buflen == 0) || (local_acl == NULL)) {
2486 /* used to query ACL EA size */
2487 } else if(size > buflen) {
2488 return -ERANGE;
2489 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002490 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 for(i = 0;i < count ;i++) {
2492 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2493 pACE ++;
2494 }
2495 }
2496 return size;
2497}
2498
2499static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2500 const posix_acl_xattr_entry * local_ace)
2501{
2502 __u16 rc = 0; /* 0 = ACL converted ok */
2503
Steve Frenchff7feac2005-11-15 16:45:16 -08002504 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2505 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002507 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 /* Probably no need to le convert -1 on any arch but can not hurt */
2509 cifs_ace->cifs_uid = cpu_to_le64(-1);
2510 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002511 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2513 return rc;
2514}
2515
2516/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2517static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2518 const int acl_type)
2519{
2520 __u16 rc = 0;
2521 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2522 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2523 int count;
2524 int i;
2525
2526 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2527 return 0;
2528
2529 count = posix_acl_xattr_count((size_t)buflen);
2530 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002531 count, buflen, le32_to_cpu(local_acl->a_version)));
2532 if(le32_to_cpu(local_acl->a_version) != 2) {
2533 cFYI(1,("unknown POSIX ACL version %d",
2534 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 return 0;
2536 }
2537 cifs_acl->version = cpu_to_le16(1);
2538 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002539 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002541 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 else {
2543 cFYI(1,("unknown ACL type %d",acl_type));
2544 return 0;
2545 }
2546 for(i=0;i<count;i++) {
2547 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2548 &local_acl->a_entries[i]);
2549 if(rc != 0) {
2550 /* ACE not converted */
2551 break;
2552 }
2553 }
2554 if(rc == 0) {
2555 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2556 rc += sizeof(struct cifs_posix_acl);
2557 /* BB add check to make sure ACL does not overflow SMB */
2558 }
2559 return rc;
2560}
2561
2562int
2563CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2564 const unsigned char *searchName,
2565 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002566 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567{
2568/* SMB_QUERY_POSIX_ACL */
2569 TRANSACTION2_QPI_REQ *pSMB = NULL;
2570 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2571 int rc = 0;
2572 int bytes_returned;
2573 int name_len;
2574 __u16 params, byte_count;
2575
2576 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2577
2578queryAclRetry:
2579 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2580 (void **) &pSMBr);
2581 if (rc)
2582 return rc;
2583
2584 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2585 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002586 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002587 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 name_len++; /* trailing null */
2589 name_len *= 2;
2590 pSMB->FileName[name_len] = 0;
2591 pSMB->FileName[name_len+1] = 0;
2592 } else { /* BB improve the check for buffer overruns BB */
2593 name_len = strnlen(searchName, PATH_MAX);
2594 name_len++; /* trailing null */
2595 strncpy(pSMB->FileName, searchName, name_len);
2596 }
2597
2598 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2599 pSMB->TotalDataCount = 0;
2600 pSMB->MaxParameterCount = cpu_to_le16(2);
2601 /* BB find exact max data count below from sess structure BB */
2602 pSMB->MaxDataCount = cpu_to_le16(4000);
2603 pSMB->MaxSetupCount = 0;
2604 pSMB->Reserved = 0;
2605 pSMB->Flags = 0;
2606 pSMB->Timeout = 0;
2607 pSMB->Reserved2 = 0;
2608 pSMB->ParameterOffset = cpu_to_le16(
2609 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2610 pSMB->DataCount = 0;
2611 pSMB->DataOffset = 0;
2612 pSMB->SetupCount = 1;
2613 pSMB->Reserved3 = 0;
2614 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2615 byte_count = params + 1 /* pad */ ;
2616 pSMB->TotalParameterCount = cpu_to_le16(params);
2617 pSMB->ParameterCount = pSMB->TotalParameterCount;
2618 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2619 pSMB->Reserved4 = 0;
2620 pSMB->hdr.smb_buf_length += byte_count;
2621 pSMB->ByteCount = cpu_to_le16(byte_count);
2622
2623 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2624 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002625 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 if (rc) {
2627 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2628 } else {
2629 /* decode response */
2630
2631 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2632 if (rc || (pSMBr->ByteCount < 2))
2633 /* BB also check enough total bytes returned */
2634 rc = -EIO; /* bad smb */
2635 else {
2636 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2637 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2638 rc = cifs_copy_posix_acl(acl_inf,
2639 (char *)&pSMBr->hdr.Protocol+data_offset,
2640 buflen,acl_type,count);
2641 }
2642 }
2643 cifs_buf_release(pSMB);
2644 if (rc == -EAGAIN)
2645 goto queryAclRetry;
2646 return rc;
2647}
2648
2649int
2650CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2651 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002652 const char *local_acl, const int buflen,
2653 const int acl_type,
2654 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655{
2656 struct smb_com_transaction2_spi_req *pSMB = NULL;
2657 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2658 char *parm_data;
2659 int name_len;
2660 int rc = 0;
2661 int bytes_returned = 0;
2662 __u16 params, byte_count, data_count, param_offset, offset;
2663
2664 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2665setAclRetry:
2666 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2667 (void **) &pSMBr);
2668 if (rc)
2669 return rc;
2670 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2671 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002672 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002673 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 name_len++; /* trailing null */
2675 name_len *= 2;
2676 } else { /* BB improve the check for buffer overruns BB */
2677 name_len = strnlen(fileName, PATH_MAX);
2678 name_len++; /* trailing null */
2679 strncpy(pSMB->FileName, fileName, name_len);
2680 }
2681 params = 6 + name_len;
2682 pSMB->MaxParameterCount = cpu_to_le16(2);
2683 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2684 pSMB->MaxSetupCount = 0;
2685 pSMB->Reserved = 0;
2686 pSMB->Flags = 0;
2687 pSMB->Timeout = 0;
2688 pSMB->Reserved2 = 0;
2689 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2690 InformationLevel) - 4;
2691 offset = param_offset + params;
2692 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2693 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2694
2695 /* convert to on the wire format for POSIX ACL */
2696 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2697
2698 if(data_count == 0) {
2699 rc = -EOPNOTSUPP;
2700 goto setACLerrorExit;
2701 }
2702 pSMB->DataOffset = cpu_to_le16(offset);
2703 pSMB->SetupCount = 1;
2704 pSMB->Reserved3 = 0;
2705 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2706 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2707 byte_count = 3 /* pad */ + params + data_count;
2708 pSMB->DataCount = cpu_to_le16(data_count);
2709 pSMB->TotalDataCount = pSMB->DataCount;
2710 pSMB->ParameterCount = cpu_to_le16(params);
2711 pSMB->TotalParameterCount = pSMB->ParameterCount;
2712 pSMB->Reserved4 = 0;
2713 pSMB->hdr.smb_buf_length += byte_count;
2714 pSMB->ByteCount = cpu_to_le16(byte_count);
2715 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2716 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2717 if (rc) {
2718 cFYI(1, ("Set POSIX ACL returned %d", rc));
2719 }
2720
2721setACLerrorExit:
2722 cifs_buf_release(pSMB);
2723 if (rc == -EAGAIN)
2724 goto setAclRetry;
2725 return rc;
2726}
2727
Steve Frenchf654bac2005-04-28 22:41:04 -07002728/* BB fix tabs in this function FIXME BB */
2729int
2730CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2731 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2732{
2733 int rc = 0;
2734 struct smb_t2_qfi_req *pSMB = NULL;
2735 struct smb_t2_qfi_rsp *pSMBr = NULL;
2736 int bytes_returned;
2737 __u16 params, byte_count;
2738
2739 cFYI(1,("In GetExtAttr"));
2740 if(tcon == NULL)
2741 return -ENODEV;
2742
2743GetExtAttrRetry:
2744 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2745 (void **) &pSMBr);
2746 if (rc)
2747 return rc;
2748
Steve Frenchc67593a2005-04-28 22:41:04 -07002749 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002750 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002751 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002752 /* BB find exact max data count below from sess structure BB */
2753 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2754 pSMB->t2.MaxSetupCount = 0;
2755 pSMB->t2.Reserved = 0;
2756 pSMB->t2.Flags = 0;
2757 pSMB->t2.Timeout = 0;
2758 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002759 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2760 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002761 pSMB->t2.DataCount = 0;
2762 pSMB->t2.DataOffset = 0;
2763 pSMB->t2.SetupCount = 1;
2764 pSMB->t2.Reserved3 = 0;
2765 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002766 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002767 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2768 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2769 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002770 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002771 pSMB->Fid = netfid;
2772 pSMB->hdr.smb_buf_length += byte_count;
2773 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2774
2775 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2776 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2777 if (rc) {
2778 cFYI(1, ("error %d in GetExtAttr", rc));
2779 } else {
2780 /* decode response */
2781 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2782 if (rc || (pSMBr->ByteCount < 2))
2783 /* BB also check enough total bytes returned */
2784 /* If rc should we check for EOPNOSUPP and
2785 disable the srvino flag? or in caller? */
2786 rc = -EIO; /* bad smb */
2787 else {
2788 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2789 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2790 struct file_chattr_info * pfinfo;
2791 /* BB Do we need a cast or hash here ? */
2792 if(count != 16) {
2793 cFYI(1, ("Illegal size ret in GetExtAttr"));
2794 rc = -EIO;
2795 goto GetExtAttrOut;
2796 }
2797 pfinfo = (struct file_chattr_info *)
2798 (data_offset + (char *) &pSMBr->hdr.Protocol);
2799 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2800 *pMask = le64_to_cpu(pfinfo->mask);
2801 }
2802 }
2803GetExtAttrOut:
2804 cifs_buf_release(pSMB);
2805 if (rc == -EAGAIN)
2806 goto GetExtAttrRetry;
2807 return rc;
2808}
2809
2810
2811#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812
Steve Frencheeac8042006-01-13 21:34:58 -08002813
2814/* security id for everyone */
Steve French2cd646a2006-09-28 19:43:08 +00002815const static struct cifs_sid sid_everyone =
2816 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002817/* group users */
Steve French2cd646a2006-09-28 19:43:08 +00002818const static struct cifs_sid sid_user =
2819 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002820
Steve French0a4b92c2006-01-12 15:44:21 -08002821/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002822static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002823{
Steve French0a4b92c2006-01-12 15:44:21 -08002824 return 0;
2825}
2826
2827/* Get Security Descriptor (by handle) from remote server for a file or dir */
2828int
2829CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2830 /* BB fix up return info */ char *acl_inf, const int buflen,
2831 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2832{
2833 int rc = 0;
2834 int buf_type = 0;
2835 QUERY_SEC_DESC_REQ * pSMB;
2836 struct kvec iov[1];
2837
2838 cFYI(1, ("GetCifsACL"));
2839
2840 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2841 8 /* parm len */, tcon, (void **) &pSMB);
2842 if (rc)
2843 return rc;
2844
2845 pSMB->MaxParameterCount = cpu_to_le32(4);
2846 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2847 pSMB->MaxSetupCount = 0;
2848 pSMB->Fid = fid; /* file handle always le */
2849 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2850 CIFS_ACL_DACL);
2851 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2852 pSMB->hdr.smb_buf_length += 11;
2853 iov[0].iov_base = (char *)pSMB;
2854 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2855
2856 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2857 cifs_stats_inc(&tcon->num_acl_get);
2858 if (rc) {
2859 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2860 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002861 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002862 __le32 * parm;
2863 int parm_len;
2864 int data_len;
2865 int acl_len;
2866 struct smb_com_ntransact_rsp * pSMBr;
2867
2868/* validate_nttransact */
2869 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2870 (char **)&psec_desc,
2871 &parm_len, &data_len);
2872
2873 if(rc)
2874 goto qsec_out;
2875 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2876
2877 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2878
2879 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2880 rc = -EIO; /* bad smb */
2881 goto qsec_out;
2882 }
2883
2884/* BB check that data area is minimum length and as big as acl_len */
2885
2886 acl_len = le32_to_cpu(*(__le32 *)parm);
2887 /* BB check if(acl_len > bufsize) */
2888
2889 parse_sec_desc(psec_desc, acl_len);
2890 }
2891qsec_out:
2892 if(buf_type == CIFS_SMALL_BUFFER)
2893 cifs_small_buf_release(iov[0].iov_base);
2894 else if(buf_type == CIFS_LARGE_BUFFER)
2895 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002896/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002897 return rc;
2898}
2899
Steve French6b8edfe2005-08-23 20:26:03 -07002900/* Legacy Query Path Information call for lookup to old servers such
2901 as Win9x/WinME */
2902int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2903 const unsigned char *searchName,
2904 FILE_ALL_INFO * pFinfo,
2905 const struct nls_table *nls_codepage, int remap)
2906{
2907 QUERY_INFORMATION_REQ * pSMB;
2908 QUERY_INFORMATION_RSP * pSMBr;
2909 int rc = 0;
2910 int bytes_returned;
2911 int name_len;
2912
2913 cFYI(1, ("In SMBQPath path %s", searchName));
2914QInfRetry:
2915 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2916 (void **) &pSMBr);
2917 if (rc)
2918 return rc;
2919
2920 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2921 name_len =
2922 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2923 PATH_MAX, nls_codepage, remap);
2924 name_len++; /* trailing null */
2925 name_len *= 2;
2926 } else {
2927 name_len = strnlen(searchName, PATH_MAX);
2928 name_len++; /* trailing null */
2929 strncpy(pSMB->FileName, searchName, name_len);
2930 }
2931 pSMB->BufferFormat = 0x04;
2932 name_len++; /* account for buffer type byte */
2933 pSMB->hdr.smb_buf_length += (__u16) name_len;
2934 pSMB->ByteCount = cpu_to_le16(name_len);
2935
2936 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2937 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2938 if (rc) {
2939 cFYI(1, ("Send error in QueryInfo = %d", rc));
2940 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00002941 struct timespec ts;
2942 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2943 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07002944 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00002945 ts.tv_nsec = 0;
2946 ts.tv_sec = time;
2947 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01002948 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00002949 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2950 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07002951 pFinfo->AllocationSize =
2952 cpu_to_le64(le32_to_cpu(pSMBr->size));
2953 pFinfo->EndOfFile = pFinfo->AllocationSize;
2954 pFinfo->Attributes =
2955 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002956 } else
2957 rc = -EIO; /* bad buffer passed in */
2958
2959 cifs_buf_release(pSMB);
2960
2961 if (rc == -EAGAIN)
2962 goto QInfRetry;
2963
2964 return rc;
2965}
2966
2967
2968
2969
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970int
2971CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2972 const unsigned char *searchName,
2973 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00002974 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07002975 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976{
2977/* level 263 SMB_QUERY_FILE_ALL_INFO */
2978 TRANSACTION2_QPI_REQ *pSMB = NULL;
2979 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2980 int rc = 0;
2981 int bytes_returned;
2982 int name_len;
2983 __u16 params, byte_count;
2984
2985/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2986QPathInfoRetry:
2987 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2988 (void **) &pSMBr);
2989 if (rc)
2990 return rc;
2991
2992 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2993 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002994 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002995 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 name_len++; /* trailing null */
2997 name_len *= 2;
2998 } else { /* BB improve the check for buffer overruns BB */
2999 name_len = strnlen(searchName, PATH_MAX);
3000 name_len++; /* trailing null */
3001 strncpy(pSMB->FileName, searchName, name_len);
3002 }
3003
3004 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3005 pSMB->TotalDataCount = 0;
3006 pSMB->MaxParameterCount = cpu_to_le16(2);
3007 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3008 pSMB->MaxSetupCount = 0;
3009 pSMB->Reserved = 0;
3010 pSMB->Flags = 0;
3011 pSMB->Timeout = 0;
3012 pSMB->Reserved2 = 0;
3013 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3014 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3015 pSMB->DataCount = 0;
3016 pSMB->DataOffset = 0;
3017 pSMB->SetupCount = 1;
3018 pSMB->Reserved3 = 0;
3019 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3020 byte_count = params + 1 /* pad */ ;
3021 pSMB->TotalParameterCount = cpu_to_le16(params);
3022 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003023 if(legacy)
3024 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3025 else
3026 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 pSMB->Reserved4 = 0;
3028 pSMB->hdr.smb_buf_length += byte_count;
3029 pSMB->ByteCount = cpu_to_le16(byte_count);
3030
3031 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3033 if (rc) {
3034 cFYI(1, ("Send error in QPathInfo = %d", rc));
3035 } else { /* decode response */
3036 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3037
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003038 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3039 rc = -EIO;
3040 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 rc = -EIO; /* bad smb */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003042 else if(legacy && (pSMBr->ByteCount < 24))
3043 rc = -EIO; /* 24 or 26 expected but we do not read last field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 else if (pFindData){
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003045 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003047 if(legacy) /* we do not read the last field, EAsize, fortunately
3048 since it varies by subdialect and on Set vs. Get, is
3049 two bytes or 4 bytes depending but we don't care here */
3050 size = sizeof(FILE_INFO_STANDARD);
3051 else
3052 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 memcpy((char *) pFindData,
3054 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003055 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 } else
3057 rc = -ENOMEM;
3058 }
3059 cifs_buf_release(pSMB);
3060 if (rc == -EAGAIN)
3061 goto QPathInfoRetry;
3062
3063 return rc;
3064}
3065
3066int
3067CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3068 const unsigned char *searchName,
3069 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003070 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071{
3072/* SMB_QUERY_FILE_UNIX_BASIC */
3073 TRANSACTION2_QPI_REQ *pSMB = NULL;
3074 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3075 int rc = 0;
3076 int bytes_returned = 0;
3077 int name_len;
3078 __u16 params, byte_count;
3079
3080 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3081UnixQPathInfoRetry:
3082 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3083 (void **) &pSMBr);
3084 if (rc)
3085 return rc;
3086
3087 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3088 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003089 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003090 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 name_len++; /* trailing null */
3092 name_len *= 2;
3093 } else { /* BB improve the check for buffer overruns BB */
3094 name_len = strnlen(searchName, PATH_MAX);
3095 name_len++; /* trailing null */
3096 strncpy(pSMB->FileName, searchName, name_len);
3097 }
3098
3099 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3100 pSMB->TotalDataCount = 0;
3101 pSMB->MaxParameterCount = cpu_to_le16(2);
3102 /* BB find exact max SMB PDU from sess structure BB */
3103 pSMB->MaxDataCount = cpu_to_le16(4000);
3104 pSMB->MaxSetupCount = 0;
3105 pSMB->Reserved = 0;
3106 pSMB->Flags = 0;
3107 pSMB->Timeout = 0;
3108 pSMB->Reserved2 = 0;
3109 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3110 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3111 pSMB->DataCount = 0;
3112 pSMB->DataOffset = 0;
3113 pSMB->SetupCount = 1;
3114 pSMB->Reserved3 = 0;
3115 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3116 byte_count = params + 1 /* pad */ ;
3117 pSMB->TotalParameterCount = cpu_to_le16(params);
3118 pSMB->ParameterCount = pSMB->TotalParameterCount;
3119 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3120 pSMB->Reserved4 = 0;
3121 pSMB->hdr.smb_buf_length += byte_count;
3122 pSMB->ByteCount = cpu_to_le16(byte_count);
3123
3124 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3125 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3126 if (rc) {
3127 cFYI(1, ("Send error in QPathInfo = %d", rc));
3128 } else { /* decode response */
3129 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3130
3131 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3132 rc = -EIO; /* bad smb */
3133 } else {
3134 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3135 memcpy((char *) pFindData,
3136 (char *) &pSMBr->hdr.Protocol +
3137 data_offset,
3138 sizeof (FILE_UNIX_BASIC_INFO));
3139 }
3140 }
3141 cifs_buf_release(pSMB);
3142 if (rc == -EAGAIN)
3143 goto UnixQPathInfoRetry;
3144
3145 return rc;
3146}
3147
3148#if 0 /* function unused at present */
3149int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3150 const char *searchName, FILE_ALL_INFO * findData,
3151 const struct nls_table *nls_codepage)
3152{
3153/* level 257 SMB_ */
3154 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3155 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3156 int rc = 0;
3157 int bytes_returned;
3158 int name_len;
3159 __u16 params, byte_count;
3160
3161 cFYI(1, ("In FindUnique"));
3162findUniqueRetry:
3163 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3164 (void **) &pSMBr);
3165 if (rc)
3166 return rc;
3167
3168 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3169 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003170 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 /* find define for this maxpathcomponent */
3172 , nls_codepage);
3173 name_len++; /* trailing null */
3174 name_len *= 2;
3175 } else { /* BB improve the check for buffer overruns BB */
3176 name_len = strnlen(searchName, PATH_MAX);
3177 name_len++; /* trailing null */
3178 strncpy(pSMB->FileName, searchName, name_len);
3179 }
3180
3181 params = 12 + name_len /* includes null */ ;
3182 pSMB->TotalDataCount = 0; /* no EAs */
3183 pSMB->MaxParameterCount = cpu_to_le16(2);
3184 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3185 pSMB->MaxSetupCount = 0;
3186 pSMB->Reserved = 0;
3187 pSMB->Flags = 0;
3188 pSMB->Timeout = 0;
3189 pSMB->Reserved2 = 0;
3190 pSMB->ParameterOffset = cpu_to_le16(
3191 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3192 pSMB->DataCount = 0;
3193 pSMB->DataOffset = 0;
3194 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3195 pSMB->Reserved3 = 0;
3196 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3197 byte_count = params + 1 /* pad */ ;
3198 pSMB->TotalParameterCount = cpu_to_le16(params);
3199 pSMB->ParameterCount = pSMB->TotalParameterCount;
3200 pSMB->SearchAttributes =
3201 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3202 ATTR_DIRECTORY);
3203 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3204 pSMB->SearchFlags = cpu_to_le16(1);
3205 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3206 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3207 pSMB->hdr.smb_buf_length += byte_count;
3208 pSMB->ByteCount = cpu_to_le16(byte_count);
3209
3210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3212
3213 if (rc) {
3214 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3215 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003216 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 /* BB fill in */
3218 }
3219
3220 cifs_buf_release(pSMB);
3221 if (rc == -EAGAIN)
3222 goto findUniqueRetry;
3223
3224 return rc;
3225}
3226#endif /* end unused (temporarily) function */
3227
3228/* xid, tcon, searchName and codepage are input parms, rest are returned */
3229int
3230CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3231 const char *searchName,
3232 const struct nls_table *nls_codepage,
3233 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003234 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235{
3236/* level 257 SMB_ */
3237 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3238 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3239 T2_FFIRST_RSP_PARMS * parms;
3240 int rc = 0;
3241 int bytes_returned = 0;
3242 int name_len;
3243 __u16 params, byte_count;
3244
Steve French737b7582005-04-28 22:41:06 -07003245 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246
3247findFirstRetry:
3248 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3249 (void **) &pSMBr);
3250 if (rc)
3251 return rc;
3252
3253 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3254 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003255 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003256 PATH_MAX, nls_codepage, remap);
3257 /* We can not add the asterik earlier in case
3258 it got remapped to 0xF03A as if it were part of the
3259 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003261 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003262 pSMB->FileName[name_len+1] = 0;
3263 pSMB->FileName[name_len+2] = '*';
3264 pSMB->FileName[name_len+3] = 0;
3265 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3267 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003268 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 } else { /* BB add check for overrun of SMB buf BB */
3270 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271/* BB fix here and in unicode clause above ie
3272 if(name_len > buffersize-header)
3273 free buffer exit; BB */
3274 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003275 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003276 pSMB->FileName[name_len+1] = '*';
3277 pSMB->FileName[name_len+2] = 0;
3278 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 }
3280
3281 params = 12 + name_len /* includes null */ ;
3282 pSMB->TotalDataCount = 0; /* no EAs */
3283 pSMB->MaxParameterCount = cpu_to_le16(10);
3284 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3285 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3286 pSMB->MaxSetupCount = 0;
3287 pSMB->Reserved = 0;
3288 pSMB->Flags = 0;
3289 pSMB->Timeout = 0;
3290 pSMB->Reserved2 = 0;
3291 byte_count = params + 1 /* pad */ ;
3292 pSMB->TotalParameterCount = cpu_to_le16(params);
3293 pSMB->ParameterCount = pSMB->TotalParameterCount;
3294 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003295 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3296 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 pSMB->DataCount = 0;
3298 pSMB->DataOffset = 0;
3299 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3300 pSMB->Reserved3 = 0;
3301 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3302 pSMB->SearchAttributes =
3303 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3304 ATTR_DIRECTORY);
3305 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3306 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3307 CIFS_SEARCH_RETURN_RESUME);
3308 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3309
3310 /* BB what should we set StorageType to? Does it matter? BB */
3311 pSMB->SearchStorageType = 0;
3312 pSMB->hdr.smb_buf_length += byte_count;
3313 pSMB->ByteCount = cpu_to_le16(byte_count);
3314
3315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003317 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318
Steve French88274812006-03-09 22:21:45 +00003319 if (rc) {/* BB add logic to retry regular search if Unix search
3320 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 /* BB Add code to handle unsupported level rc */
3322 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003323
Steve French88274812006-03-09 22:21:45 +00003324 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325
3326 /* BB eventually could optimize out free and realloc of buf */
3327 /* for this case */
3328 if (rc == -EAGAIN)
3329 goto findFirstRetry;
3330 } else { /* decode response */
3331 /* BB remember to free buffer if error BB */
3332 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3333 if(rc == 0) {
3334 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3335 psrch_inf->unicode = TRUE;
3336 else
3337 psrch_inf->unicode = FALSE;
3338
3339 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003340 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 psrch_inf->srch_entries_start =
3342 (char *) &pSMBr->hdr.Protocol +
3343 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3345 le16_to_cpu(pSMBr->t2.ParameterOffset));
3346
3347 if(parms->EndofSearch)
3348 psrch_inf->endOfSearch = TRUE;
3349 else
3350 psrch_inf->endOfSearch = FALSE;
3351
3352 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003353 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 *pnetfid = parms->SearchHandle;
3356 } else {
3357 cifs_buf_release(pSMB);
3358 }
3359 }
3360
3361 return rc;
3362}
3363
3364int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3365 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3366{
3367 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3368 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3369 T2_FNEXT_RSP_PARMS * parms;
3370 char *response_data;
3371 int rc = 0;
3372 int bytes_returned, name_len;
3373 __u16 params, byte_count;
3374
3375 cFYI(1, ("In FindNext"));
3376
3377 if(psrch_inf->endOfSearch == TRUE)
3378 return -ENOENT;
3379
3380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3381 (void **) &pSMBr);
3382 if (rc)
3383 return rc;
3384
3385 params = 14; /* includes 2 bytes of null string, converted to LE below */
3386 byte_count = 0;
3387 pSMB->TotalDataCount = 0; /* no EAs */
3388 pSMB->MaxParameterCount = cpu_to_le16(8);
3389 pSMB->MaxDataCount =
3390 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3391 pSMB->MaxSetupCount = 0;
3392 pSMB->Reserved = 0;
3393 pSMB->Flags = 0;
3394 pSMB->Timeout = 0;
3395 pSMB->Reserved2 = 0;
3396 pSMB->ParameterOffset = cpu_to_le16(
3397 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3398 pSMB->DataCount = 0;
3399 pSMB->DataOffset = 0;
3400 pSMB->SetupCount = 1;
3401 pSMB->Reserved3 = 0;
3402 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3403 pSMB->SearchHandle = searchHandle; /* always kept as le */
3404 pSMB->SearchCount =
3405 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3406 /* test for Unix extensions */
3407/* if (tcon->ses->capabilities & CAP_UNIX) {
3408 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3409 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3410 } else {
3411 pSMB->InformationLevel =
3412 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3413 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3414 } */
3415 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3416 pSMB->ResumeKey = psrch_inf->resume_key;
3417 pSMB->SearchFlags =
3418 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3419
3420 name_len = psrch_inf->resume_name_len;
3421 params += name_len;
3422 if(name_len < PATH_MAX) {
3423 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3424 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003425 /* 14 byte parm len above enough for 2 byte null terminator */
3426 pSMB->ResumeFileName[name_len] = 0;
3427 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 } else {
3429 rc = -EINVAL;
3430 goto FNext2_err_exit;
3431 }
3432 byte_count = params + 1 /* pad */ ;
3433 pSMB->TotalParameterCount = cpu_to_le16(params);
3434 pSMB->ParameterCount = pSMB->TotalParameterCount;
3435 pSMB->hdr.smb_buf_length += byte_count;
3436 pSMB->ByteCount = cpu_to_le16(byte_count);
3437
3438 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3439 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003440 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 if (rc) {
3442 if (rc == -EBADF) {
3443 psrch_inf->endOfSearch = TRUE;
3444 rc = 0; /* search probably was closed at end of search above */
3445 } else
3446 cFYI(1, ("FindNext returned = %d", rc));
3447 } else { /* decode response */
3448 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3449
3450 if(rc == 0) {
3451 /* BB fixme add lock for file (srch_info) struct here */
3452 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3453 psrch_inf->unicode = TRUE;
3454 else
3455 psrch_inf->unicode = FALSE;
3456 response_data = (char *) &pSMBr->hdr.Protocol +
3457 le16_to_cpu(pSMBr->t2.ParameterOffset);
3458 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3459 response_data = (char *)&pSMBr->hdr.Protocol +
3460 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003461 if(psrch_inf->smallBuf)
3462 cifs_small_buf_release(
3463 psrch_inf->ntwrk_buf_start);
3464 else
3465 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 psrch_inf->srch_entries_start = response_data;
3467 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003468 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 if(parms->EndofSearch)
3470 psrch_inf->endOfSearch = TRUE;
3471 else
3472 psrch_inf->endOfSearch = FALSE;
3473
3474 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3475 psrch_inf->index_of_last_entry +=
3476 psrch_inf->entries_in_buffer;
3477/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3478
3479 /* BB fixme add unlock here */
3480 }
3481
3482 }
3483
3484 /* BB On error, should we leave previous search buf (and count and
3485 last entry fields) intact or free the previous one? */
3486
3487 /* Note: On -EAGAIN error only caller can retry on handle based calls
3488 since file handle passed in no longer valid */
3489FNext2_err_exit:
3490 if (rc != 0)
3491 cifs_buf_release(pSMB);
3492
3493 return rc;
3494}
3495
3496int
3497CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3498{
3499 int rc = 0;
3500 FINDCLOSE_REQ *pSMB = NULL;
3501 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3502 int bytes_returned;
3503
3504 cFYI(1, ("In CIFSSMBFindClose"));
3505 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3506
3507 /* no sense returning error if session restarted
3508 as file handle has been closed */
3509 if(rc == -EAGAIN)
3510 return 0;
3511 if (rc)
3512 return rc;
3513
3514 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3515 pSMB->FileID = searchHandle;
3516 pSMB->ByteCount = 0;
3517 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3518 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3519 if (rc) {
3520 cERROR(1, ("Send error in FindClose = %d", rc));
3521 }
Steve Frencha4544342005-08-24 13:59:35 -07003522 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 cifs_small_buf_release(pSMB);
3524
3525 /* Since session is dead, search handle closed on server already */
3526 if (rc == -EAGAIN)
3527 rc = 0;
3528
3529 return rc;
3530}
3531
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532int
3533CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3534 const unsigned char *searchName,
3535 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003536 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537{
3538 int rc = 0;
3539 TRANSACTION2_QPI_REQ *pSMB = NULL;
3540 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3541 int name_len, bytes_returned;
3542 __u16 params, byte_count;
3543
3544 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3545 if(tcon == NULL)
3546 return -ENODEV;
3547
3548GetInodeNumberRetry:
3549 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3550 (void **) &pSMBr);
3551 if (rc)
3552 return rc;
3553
3554
3555 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3556 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003557 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003558 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 name_len++; /* trailing null */
3560 name_len *= 2;
3561 } else { /* BB improve the check for buffer overruns BB */
3562 name_len = strnlen(searchName, PATH_MAX);
3563 name_len++; /* trailing null */
3564 strncpy(pSMB->FileName, searchName, name_len);
3565 }
3566
3567 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3568 pSMB->TotalDataCount = 0;
3569 pSMB->MaxParameterCount = cpu_to_le16(2);
3570 /* BB find exact max data count below from sess structure BB */
3571 pSMB->MaxDataCount = cpu_to_le16(4000);
3572 pSMB->MaxSetupCount = 0;
3573 pSMB->Reserved = 0;
3574 pSMB->Flags = 0;
3575 pSMB->Timeout = 0;
3576 pSMB->Reserved2 = 0;
3577 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3578 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3579 pSMB->DataCount = 0;
3580 pSMB->DataOffset = 0;
3581 pSMB->SetupCount = 1;
3582 pSMB->Reserved3 = 0;
3583 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3584 byte_count = params + 1 /* pad */ ;
3585 pSMB->TotalParameterCount = cpu_to_le16(params);
3586 pSMB->ParameterCount = pSMB->TotalParameterCount;
3587 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3588 pSMB->Reserved4 = 0;
3589 pSMB->hdr.smb_buf_length += byte_count;
3590 pSMB->ByteCount = cpu_to_le16(byte_count);
3591
3592 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3593 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3594 if (rc) {
3595 cFYI(1, ("error %d in QueryInternalInfo", rc));
3596 } else {
3597 /* decode response */
3598 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3599 if (rc || (pSMBr->ByteCount < 2))
3600 /* BB also check enough total bytes returned */
3601 /* If rc should we check for EOPNOSUPP and
3602 disable the srvino flag? or in caller? */
3603 rc = -EIO; /* bad smb */
3604 else {
3605 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3606 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3607 struct file_internal_info * pfinfo;
3608 /* BB Do we need a cast or hash here ? */
3609 if(count < 8) {
3610 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3611 rc = -EIO;
3612 goto GetInodeNumOut;
3613 }
3614 pfinfo = (struct file_internal_info *)
3615 (data_offset + (char *) &pSMBr->hdr.Protocol);
3616 *inode_number = pfinfo->UniqueId;
3617 }
3618 }
3619GetInodeNumOut:
3620 cifs_buf_release(pSMB);
3621 if (rc == -EAGAIN)
3622 goto GetInodeNumberRetry;
3623 return rc;
3624}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625
3626int
3627CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3628 const unsigned char *searchName,
3629 unsigned char **targetUNCs,
3630 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003631 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632{
3633/* TRANS2_GET_DFS_REFERRAL */
3634 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3635 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3636 struct dfs_referral_level_3 * referrals = NULL;
3637 int rc = 0;
3638 int bytes_returned;
3639 int name_len;
3640 unsigned int i;
3641 char * temp;
3642 __u16 params, byte_count;
3643 *number_of_UNC_in_array = 0;
3644 *targetUNCs = NULL;
3645
3646 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3647 if (ses == NULL)
3648 return -ENODEV;
3649getDFSRetry:
3650 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3651 (void **) &pSMBr);
3652 if (rc)
3653 return rc;
Steve French1982c342005-08-17 12:38:22 -07003654
3655 /* server pointer checked in called function,
3656 but should never be null here anyway */
3657 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 pSMB->hdr.Tid = ses->ipc_tid;
3659 pSMB->hdr.Uid = ses->Suid;
3660 if (ses->capabilities & CAP_STATUS32) {
3661 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3662 }
3663 if (ses->capabilities & CAP_DFS) {
3664 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3665 }
3666
3667 if (ses->capabilities & CAP_UNICODE) {
3668 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3669 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003670 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003671 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 name_len++; /* trailing null */
3673 name_len *= 2;
3674 } else { /* BB improve the check for buffer overruns BB */
3675 name_len = strnlen(searchName, PATH_MAX);
3676 name_len++; /* trailing null */
3677 strncpy(pSMB->RequestFileName, searchName, name_len);
3678 }
3679
Steve French1a4e15a2006-10-12 21:33:51 +00003680 if(ses->server) {
3681 if(ses->server->secMode &
3682 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3683 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3684 }
3685
3686 pSMB->hdr.Uid = ses->Suid;
3687
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 params = 2 /* level */ + name_len /*includes null */ ;
3689 pSMB->TotalDataCount = 0;
3690 pSMB->DataCount = 0;
3691 pSMB->DataOffset = 0;
3692 pSMB->MaxParameterCount = 0;
3693 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3694 pSMB->MaxSetupCount = 0;
3695 pSMB->Reserved = 0;
3696 pSMB->Flags = 0;
3697 pSMB->Timeout = 0;
3698 pSMB->Reserved2 = 0;
3699 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3700 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3701 pSMB->SetupCount = 1;
3702 pSMB->Reserved3 = 0;
3703 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3704 byte_count = params + 3 /* pad */ ;
3705 pSMB->ParameterCount = cpu_to_le16(params);
3706 pSMB->TotalParameterCount = pSMB->ParameterCount;
3707 pSMB->MaxReferralLevel = cpu_to_le16(3);
3708 pSMB->hdr.smb_buf_length += byte_count;
3709 pSMB->ByteCount = cpu_to_le16(byte_count);
3710
3711 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3712 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3713 if (rc) {
3714 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3715 } else { /* decode response */
3716/* BB Add logic to parse referrals here */
3717 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3718
3719 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3720 rc = -EIO; /* bad smb */
3721 else {
3722 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3723 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3724
3725 cFYI(1,
3726 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3727 pSMBr->ByteCount, data_offset));
3728 referrals =
3729 (struct dfs_referral_level_3 *)
3730 (8 /* sizeof start of data block */ +
3731 data_offset +
3732 (char *) &pSMBr->hdr.Protocol);
3733 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",
3734 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)));
3735 /* BB This field is actually two bytes in from start of
3736 data block so we could do safety check that DataBlock
3737 begins at address of pSMBr->NumberOfReferrals */
3738 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3739
3740 /* BB Fix below so can return more than one referral */
3741 if(*number_of_UNC_in_array > 1)
3742 *number_of_UNC_in_array = 1;
3743
3744 /* get the length of the strings describing refs */
3745 name_len = 0;
3746 for(i=0;i<*number_of_UNC_in_array;i++) {
3747 /* make sure that DfsPathOffset not past end */
3748 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3749 if (offset > data_count) {
3750 /* if invalid referral, stop here and do
3751 not try to copy any more */
3752 *number_of_UNC_in_array = i;
3753 break;
3754 }
3755 temp = ((char *)referrals) + offset;
3756
3757 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3758 name_len += UniStrnlen((wchar_t *)temp,data_count);
3759 } else {
3760 name_len += strnlen(temp,data_count);
3761 }
3762 referrals++;
3763 /* BB add check that referral pointer does not fall off end PDU */
3764
3765 }
3766 /* BB add check for name_len bigger than bcc */
3767 *targetUNCs =
3768 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3769 if(*targetUNCs == NULL) {
3770 rc = -ENOMEM;
3771 goto GetDFSRefExit;
3772 }
3773 /* copy the ref strings */
3774 referrals =
3775 (struct dfs_referral_level_3 *)
3776 (8 /* sizeof data hdr */ +
3777 data_offset +
3778 (char *) &pSMBr->hdr.Protocol);
3779
3780 for(i=0;i<*number_of_UNC_in_array;i++) {
3781 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3782 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3783 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003784 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 } else {
3786 strncpy(*targetUNCs,temp,name_len);
3787 }
3788 /* BB update target_uncs pointers */
3789 referrals++;
3790 }
3791 temp = *targetUNCs;
3792 temp[name_len] = 0;
3793 }
3794
3795 }
3796GetDFSRefExit:
3797 if (pSMB)
3798 cifs_buf_release(pSMB);
3799
3800 if (rc == -EAGAIN)
3801 goto getDFSRetry;
3802
3803 return rc;
3804}
3805
Steve French20962432005-09-21 22:05:57 -07003806/* Query File System Info such as free space to old servers such as Win 9x */
3807int
3808SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3809{
3810/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3811 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3812 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3813 FILE_SYSTEM_ALLOC_INFO *response_data;
3814 int rc = 0;
3815 int bytes_returned = 0;
3816 __u16 params, byte_count;
3817
3818 cFYI(1, ("OldQFSInfo"));
3819oldQFSInfoRetry:
3820 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3821 (void **) &pSMBr);
3822 if (rc)
3823 return rc;
3824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3825 (void **) &pSMBr);
3826 if (rc)
3827 return rc;
3828
3829 params = 2; /* level */
3830 pSMB->TotalDataCount = 0;
3831 pSMB->MaxParameterCount = cpu_to_le16(2);
3832 pSMB->MaxDataCount = cpu_to_le16(1000);
3833 pSMB->MaxSetupCount = 0;
3834 pSMB->Reserved = 0;
3835 pSMB->Flags = 0;
3836 pSMB->Timeout = 0;
3837 pSMB->Reserved2 = 0;
3838 byte_count = params + 1 /* pad */ ;
3839 pSMB->TotalParameterCount = cpu_to_le16(params);
3840 pSMB->ParameterCount = pSMB->TotalParameterCount;
3841 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3842 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3843 pSMB->DataCount = 0;
3844 pSMB->DataOffset = 0;
3845 pSMB->SetupCount = 1;
3846 pSMB->Reserved3 = 0;
3847 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3848 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3849 pSMB->hdr.smb_buf_length += byte_count;
3850 pSMB->ByteCount = cpu_to_le16(byte_count);
3851
3852 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3853 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3854 if (rc) {
3855 cFYI(1, ("Send error in QFSInfo = %d", rc));
3856 } else { /* decode response */
3857 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3858
3859 if (rc || (pSMBr->ByteCount < 18))
3860 rc = -EIO; /* bad smb */
3861 else {
3862 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3863 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3864 pSMBr->ByteCount, data_offset));
3865
3866 response_data =
3867 (FILE_SYSTEM_ALLOC_INFO *)
3868 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3869 FSData->f_bsize =
3870 le16_to_cpu(response_data->BytesPerSector) *
3871 le32_to_cpu(response_data->
3872 SectorsPerAllocationUnit);
3873 FSData->f_blocks =
3874 le32_to_cpu(response_data->TotalAllocationUnits);
3875 FSData->f_bfree = FSData->f_bavail =
3876 le32_to_cpu(response_data->FreeAllocationUnits);
3877 cFYI(1,
3878 ("Blocks: %lld Free: %lld Block size %ld",
3879 (unsigned long long)FSData->f_blocks,
3880 (unsigned long long)FSData->f_bfree,
3881 FSData->f_bsize));
3882 }
3883 }
3884 cifs_buf_release(pSMB);
3885
3886 if (rc == -EAGAIN)
3887 goto oldQFSInfoRetry;
3888
3889 return rc;
3890}
3891
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892int
Steve French737b7582005-04-28 22:41:06 -07003893CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894{
3895/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3896 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3897 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3898 FILE_SYSTEM_INFO *response_data;
3899 int rc = 0;
3900 int bytes_returned = 0;
3901 __u16 params, byte_count;
3902
3903 cFYI(1, ("In QFSInfo"));
3904QFSInfoRetry:
3905 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3906 (void **) &pSMBr);
3907 if (rc)
3908 return rc;
3909
3910 params = 2; /* level */
3911 pSMB->TotalDataCount = 0;
3912 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003913 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 pSMB->MaxSetupCount = 0;
3915 pSMB->Reserved = 0;
3916 pSMB->Flags = 0;
3917 pSMB->Timeout = 0;
3918 pSMB->Reserved2 = 0;
3919 byte_count = params + 1 /* pad */ ;
3920 pSMB->TotalParameterCount = cpu_to_le16(params);
3921 pSMB->ParameterCount = pSMB->TotalParameterCount;
3922 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3923 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3924 pSMB->DataCount = 0;
3925 pSMB->DataOffset = 0;
3926 pSMB->SetupCount = 1;
3927 pSMB->Reserved3 = 0;
3928 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3929 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3930 pSMB->hdr.smb_buf_length += byte_count;
3931 pSMB->ByteCount = cpu_to_le16(byte_count);
3932
3933 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3934 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3935 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003936 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 } else { /* decode response */
3938 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3939
Steve French20962432005-09-21 22:05:57 -07003940 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 rc = -EIO; /* bad smb */
3942 else {
3943 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944
3945 response_data =
3946 (FILE_SYSTEM_INFO
3947 *) (((char *) &pSMBr->hdr.Protocol) +
3948 data_offset);
3949 FSData->f_bsize =
3950 le32_to_cpu(response_data->BytesPerSector) *
3951 le32_to_cpu(response_data->
3952 SectorsPerAllocationUnit);
3953 FSData->f_blocks =
3954 le64_to_cpu(response_data->TotalAllocationUnits);
3955 FSData->f_bfree = FSData->f_bavail =
3956 le64_to_cpu(response_data->FreeAllocationUnits);
3957 cFYI(1,
3958 ("Blocks: %lld Free: %lld Block size %ld",
3959 (unsigned long long)FSData->f_blocks,
3960 (unsigned long long)FSData->f_bfree,
3961 FSData->f_bsize));
3962 }
3963 }
3964 cifs_buf_release(pSMB);
3965
3966 if (rc == -EAGAIN)
3967 goto QFSInfoRetry;
3968
3969 return rc;
3970}
3971
3972int
Steve French737b7582005-04-28 22:41:06 -07003973CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974{
3975/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3976 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3977 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3978 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3979 int rc = 0;
3980 int bytes_returned = 0;
3981 __u16 params, byte_count;
3982
3983 cFYI(1, ("In QFSAttributeInfo"));
3984QFSAttributeRetry:
3985 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3986 (void **) &pSMBr);
3987 if (rc)
3988 return rc;
3989
3990 params = 2; /* level */
3991 pSMB->TotalDataCount = 0;
3992 pSMB->MaxParameterCount = cpu_to_le16(2);
3993 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3994 pSMB->MaxSetupCount = 0;
3995 pSMB->Reserved = 0;
3996 pSMB->Flags = 0;
3997 pSMB->Timeout = 0;
3998 pSMB->Reserved2 = 0;
3999 byte_count = params + 1 /* pad */ ;
4000 pSMB->TotalParameterCount = cpu_to_le16(params);
4001 pSMB->ParameterCount = pSMB->TotalParameterCount;
4002 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4003 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4004 pSMB->DataCount = 0;
4005 pSMB->DataOffset = 0;
4006 pSMB->SetupCount = 1;
4007 pSMB->Reserved3 = 0;
4008 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4009 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4010 pSMB->hdr.smb_buf_length += byte_count;
4011 pSMB->ByteCount = cpu_to_le16(byte_count);
4012
4013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4014 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4015 if (rc) {
4016 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4017 } else { /* decode response */
4018 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4019
4020 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4021 rc = -EIO; /* bad smb */
4022 } else {
4023 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4024 response_data =
4025 (FILE_SYSTEM_ATTRIBUTE_INFO
4026 *) (((char *) &pSMBr->hdr.Protocol) +
4027 data_offset);
4028 memcpy(&tcon->fsAttrInfo, response_data,
4029 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4030 }
4031 }
4032 cifs_buf_release(pSMB);
4033
4034 if (rc == -EAGAIN)
4035 goto QFSAttributeRetry;
4036
4037 return rc;
4038}
4039
4040int
Steve French737b7582005-04-28 22:41:06 -07004041CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042{
4043/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4044 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4045 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4046 FILE_SYSTEM_DEVICE_INFO *response_data;
4047 int rc = 0;
4048 int bytes_returned = 0;
4049 __u16 params, byte_count;
4050
4051 cFYI(1, ("In QFSDeviceInfo"));
4052QFSDeviceRetry:
4053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4054 (void **) &pSMBr);
4055 if (rc)
4056 return rc;
4057
4058 params = 2; /* level */
4059 pSMB->TotalDataCount = 0;
4060 pSMB->MaxParameterCount = cpu_to_le16(2);
4061 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4062 pSMB->MaxSetupCount = 0;
4063 pSMB->Reserved = 0;
4064 pSMB->Flags = 0;
4065 pSMB->Timeout = 0;
4066 pSMB->Reserved2 = 0;
4067 byte_count = params + 1 /* pad */ ;
4068 pSMB->TotalParameterCount = cpu_to_le16(params);
4069 pSMB->ParameterCount = pSMB->TotalParameterCount;
4070 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4071 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4072
4073 pSMB->DataCount = 0;
4074 pSMB->DataOffset = 0;
4075 pSMB->SetupCount = 1;
4076 pSMB->Reserved3 = 0;
4077 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4078 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4079 pSMB->hdr.smb_buf_length += byte_count;
4080 pSMB->ByteCount = cpu_to_le16(byte_count);
4081
4082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4084 if (rc) {
4085 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4086 } else { /* decode response */
4087 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4088
4089 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4090 rc = -EIO; /* bad smb */
4091 else {
4092 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4093 response_data =
Steve French737b7582005-04-28 22:41:06 -07004094 (FILE_SYSTEM_DEVICE_INFO *)
4095 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 data_offset);
4097 memcpy(&tcon->fsDevInfo, response_data,
4098 sizeof (FILE_SYSTEM_DEVICE_INFO));
4099 }
4100 }
4101 cifs_buf_release(pSMB);
4102
4103 if (rc == -EAGAIN)
4104 goto QFSDeviceRetry;
4105
4106 return rc;
4107}
4108
4109int
Steve French737b7582005-04-28 22:41:06 -07004110CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111{
4112/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4113 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4114 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4115 FILE_SYSTEM_UNIX_INFO *response_data;
4116 int rc = 0;
4117 int bytes_returned = 0;
4118 __u16 params, byte_count;
4119
4120 cFYI(1, ("In QFSUnixInfo"));
4121QFSUnixRetry:
4122 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4123 (void **) &pSMBr);
4124 if (rc)
4125 return rc;
4126
4127 params = 2; /* level */
4128 pSMB->TotalDataCount = 0;
4129 pSMB->DataCount = 0;
4130 pSMB->DataOffset = 0;
4131 pSMB->MaxParameterCount = cpu_to_le16(2);
4132 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4133 pSMB->MaxSetupCount = 0;
4134 pSMB->Reserved = 0;
4135 pSMB->Flags = 0;
4136 pSMB->Timeout = 0;
4137 pSMB->Reserved2 = 0;
4138 byte_count = params + 1 /* pad */ ;
4139 pSMB->ParameterCount = cpu_to_le16(params);
4140 pSMB->TotalParameterCount = pSMB->ParameterCount;
4141 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4142 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4143 pSMB->SetupCount = 1;
4144 pSMB->Reserved3 = 0;
4145 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4146 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4147 pSMB->hdr.smb_buf_length += byte_count;
4148 pSMB->ByteCount = cpu_to_le16(byte_count);
4149
4150 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4151 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4152 if (rc) {
4153 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4154 } else { /* decode response */
4155 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4156
4157 if (rc || (pSMBr->ByteCount < 13)) {
4158 rc = -EIO; /* bad smb */
4159 } else {
4160 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4161 response_data =
4162 (FILE_SYSTEM_UNIX_INFO
4163 *) (((char *) &pSMBr->hdr.Protocol) +
4164 data_offset);
4165 memcpy(&tcon->fsUnixInfo, response_data,
4166 sizeof (FILE_SYSTEM_UNIX_INFO));
4167 }
4168 }
4169 cifs_buf_release(pSMB);
4170
4171 if (rc == -EAGAIN)
4172 goto QFSUnixRetry;
4173
4174
4175 return rc;
4176}
4177
Jeremy Allisonac670552005-06-22 17:26:35 -07004178int
Steve French45abc6e2005-06-23 13:42:03 -05004179CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004180{
4181/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4182 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4183 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4184 int rc = 0;
4185 int bytes_returned = 0;
4186 __u16 params, param_offset, offset, byte_count;
4187
4188 cFYI(1, ("In SETFSUnixInfo"));
4189SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004190 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004191 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4192 (void **) &pSMBr);
4193 if (rc)
4194 return rc;
4195
4196 params = 4; /* 2 bytes zero followed by info level. */
4197 pSMB->MaxSetupCount = 0;
4198 pSMB->Reserved = 0;
4199 pSMB->Flags = 0;
4200 pSMB->Timeout = 0;
4201 pSMB->Reserved2 = 0;
4202 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4203 offset = param_offset + params;
4204
4205 pSMB->MaxParameterCount = cpu_to_le16(4);
4206 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4207 pSMB->SetupCount = 1;
4208 pSMB->Reserved3 = 0;
4209 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4210 byte_count = 1 /* pad */ + params + 12;
4211
4212 pSMB->DataCount = cpu_to_le16(12);
4213 pSMB->ParameterCount = cpu_to_le16(params);
4214 pSMB->TotalDataCount = pSMB->DataCount;
4215 pSMB->TotalParameterCount = pSMB->ParameterCount;
4216 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4217 pSMB->DataOffset = cpu_to_le16(offset);
4218
4219 /* Params. */
4220 pSMB->FileNum = 0;
4221 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4222
4223 /* Data. */
4224 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4225 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4226 pSMB->ClientUnixCap = cpu_to_le64(cap);
4227
4228 pSMB->hdr.smb_buf_length += byte_count;
4229 pSMB->ByteCount = cpu_to_le16(byte_count);
4230
4231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4233 if (rc) {
4234 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4235 } else { /* decode response */
4236 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4237 if (rc) {
4238 rc = -EIO; /* bad smb */
4239 }
4240 }
4241 cifs_buf_release(pSMB);
4242
4243 if (rc == -EAGAIN)
4244 goto SETFSUnixRetry;
4245
4246 return rc;
4247}
4248
4249
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250
4251int
4252CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004253 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254{
4255/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4256 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4257 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4258 FILE_SYSTEM_POSIX_INFO *response_data;
4259 int rc = 0;
4260 int bytes_returned = 0;
4261 __u16 params, byte_count;
4262
4263 cFYI(1, ("In QFSPosixInfo"));
4264QFSPosixRetry:
4265 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4266 (void **) &pSMBr);
4267 if (rc)
4268 return rc;
4269
4270 params = 2; /* level */
4271 pSMB->TotalDataCount = 0;
4272 pSMB->DataCount = 0;
4273 pSMB->DataOffset = 0;
4274 pSMB->MaxParameterCount = cpu_to_le16(2);
4275 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4276 pSMB->MaxSetupCount = 0;
4277 pSMB->Reserved = 0;
4278 pSMB->Flags = 0;
4279 pSMB->Timeout = 0;
4280 pSMB->Reserved2 = 0;
4281 byte_count = params + 1 /* pad */ ;
4282 pSMB->ParameterCount = cpu_to_le16(params);
4283 pSMB->TotalParameterCount = pSMB->ParameterCount;
4284 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4285 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4286 pSMB->SetupCount = 1;
4287 pSMB->Reserved3 = 0;
4288 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4289 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4290 pSMB->hdr.smb_buf_length += byte_count;
4291 pSMB->ByteCount = cpu_to_le16(byte_count);
4292
4293 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4294 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4295 if (rc) {
4296 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4297 } else { /* decode response */
4298 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4299
4300 if (rc || (pSMBr->ByteCount < 13)) {
4301 rc = -EIO; /* bad smb */
4302 } else {
4303 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4304 response_data =
4305 (FILE_SYSTEM_POSIX_INFO
4306 *) (((char *) &pSMBr->hdr.Protocol) +
4307 data_offset);
4308 FSData->f_bsize =
4309 le32_to_cpu(response_data->BlockSize);
4310 FSData->f_blocks =
4311 le64_to_cpu(response_data->TotalBlocks);
4312 FSData->f_bfree =
4313 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004314 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 FSData->f_bavail = FSData->f_bfree;
4316 } else {
4317 FSData->f_bavail =
4318 le64_to_cpu(response_data->UserBlocksAvail);
4319 }
Steve French70ca7342005-09-22 16:32:06 -07004320 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 FSData->f_files =
4322 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004323 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 FSData->f_ffree =
4325 le64_to_cpu(response_data->FreeFileNodes);
4326 }
4327 }
4328 cifs_buf_release(pSMB);
4329
4330 if (rc == -EAGAIN)
4331 goto QFSPosixRetry;
4332
4333 return rc;
4334}
4335
4336
4337/* We can not use write of zero bytes trick to
4338 set file size due to need for large file support. Also note that
4339 this SetPathInfo is preferred to SetFileInfo based method in next
4340 routine which is only needed to work around a sharing violation bug
4341 in Samba which this routine can run into */
4342
4343int
4344CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004345 __u64 size, int SetAllocation,
4346 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347{
4348 struct smb_com_transaction2_spi_req *pSMB = NULL;
4349 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4350 struct file_end_of_file_info *parm_data;
4351 int name_len;
4352 int rc = 0;
4353 int bytes_returned = 0;
4354 __u16 params, byte_count, data_count, param_offset, offset;
4355
4356 cFYI(1, ("In SetEOF"));
4357SetEOFRetry:
4358 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4359 (void **) &pSMBr);
4360 if (rc)
4361 return rc;
4362
4363 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4364 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004365 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004366 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 name_len++; /* trailing null */
4368 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004369 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 name_len = strnlen(fileName, PATH_MAX);
4371 name_len++; /* trailing null */
4372 strncpy(pSMB->FileName, fileName, name_len);
4373 }
4374 params = 6 + name_len;
4375 data_count = sizeof (struct file_end_of_file_info);
4376 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004377 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 pSMB->MaxSetupCount = 0;
4379 pSMB->Reserved = 0;
4380 pSMB->Flags = 0;
4381 pSMB->Timeout = 0;
4382 pSMB->Reserved2 = 0;
4383 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4384 InformationLevel) - 4;
4385 offset = param_offset + params;
4386 if(SetAllocation) {
4387 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4388 pSMB->InformationLevel =
4389 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4390 else
4391 pSMB->InformationLevel =
4392 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4393 } else /* Set File Size */ {
4394 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4395 pSMB->InformationLevel =
4396 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4397 else
4398 pSMB->InformationLevel =
4399 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4400 }
4401
4402 parm_data =
4403 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4404 offset);
4405 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4406 pSMB->DataOffset = cpu_to_le16(offset);
4407 pSMB->SetupCount = 1;
4408 pSMB->Reserved3 = 0;
4409 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4410 byte_count = 3 /* pad */ + params + data_count;
4411 pSMB->DataCount = cpu_to_le16(data_count);
4412 pSMB->TotalDataCount = pSMB->DataCount;
4413 pSMB->ParameterCount = cpu_to_le16(params);
4414 pSMB->TotalParameterCount = pSMB->ParameterCount;
4415 pSMB->Reserved4 = 0;
4416 pSMB->hdr.smb_buf_length += byte_count;
4417 parm_data->FileSize = cpu_to_le64(size);
4418 pSMB->ByteCount = cpu_to_le16(byte_count);
4419 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4420 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4421 if (rc) {
4422 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4423 }
4424
4425 cifs_buf_release(pSMB);
4426
4427 if (rc == -EAGAIN)
4428 goto SetEOFRetry;
4429
4430 return rc;
4431}
4432
4433int
4434CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4435 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4436{
4437 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4438 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4439 char *data_offset;
4440 struct file_end_of_file_info *parm_data;
4441 int rc = 0;
4442 int bytes_returned = 0;
4443 __u16 params, param_offset, offset, byte_count, count;
4444
4445 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4446 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004447 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 if (rc)
4450 return rc;
4451
Steve Frenchcd634992005-04-28 22:41:10 -07004452 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4453
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4455 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4456
4457 params = 6;
4458 pSMB->MaxSetupCount = 0;
4459 pSMB->Reserved = 0;
4460 pSMB->Flags = 0;
4461 pSMB->Timeout = 0;
4462 pSMB->Reserved2 = 0;
4463 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4464 offset = param_offset + params;
4465
4466 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4467
4468 count = sizeof(struct file_end_of_file_info);
4469 pSMB->MaxParameterCount = cpu_to_le16(2);
4470 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4471 pSMB->SetupCount = 1;
4472 pSMB->Reserved3 = 0;
4473 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4474 byte_count = 3 /* pad */ + params + count;
4475 pSMB->DataCount = cpu_to_le16(count);
4476 pSMB->ParameterCount = cpu_to_le16(params);
4477 pSMB->TotalDataCount = pSMB->DataCount;
4478 pSMB->TotalParameterCount = pSMB->ParameterCount;
4479 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4480 parm_data =
4481 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4482 offset);
4483 pSMB->DataOffset = cpu_to_le16(offset);
4484 parm_data->FileSize = cpu_to_le64(size);
4485 pSMB->Fid = fid;
4486 if(SetAllocation) {
4487 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4488 pSMB->InformationLevel =
4489 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4490 else
4491 pSMB->InformationLevel =
4492 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4493 } else /* Set File Size */ {
4494 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4495 pSMB->InformationLevel =
4496 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4497 else
4498 pSMB->InformationLevel =
4499 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4500 }
4501 pSMB->Reserved4 = 0;
4502 pSMB->hdr.smb_buf_length += byte_count;
4503 pSMB->ByteCount = cpu_to_le16(byte_count);
4504 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4505 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4506 if (rc) {
4507 cFYI(1,
4508 ("Send error in SetFileInfo (SetFileSize) = %d",
4509 rc));
4510 }
4511
4512 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004513 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514
4515 /* Note: On -EAGAIN error only caller can retry on handle based calls
4516 since file handle passed in no longer valid */
4517
4518 return rc;
4519}
4520
4521/* Some legacy servers such as NT4 require that the file times be set on
4522 an open handle, rather than by pathname - this is awkward due to
4523 potential access conflicts on the open, but it is unavoidable for these
4524 old servers since the only other choice is to go from 100 nanosecond DCE
4525 time and resort to the original setpathinfo level which takes the ancient
4526 DOS time format with 2 second granularity */
4527int
4528CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4529 __u16 fid)
4530{
4531 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4532 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4533 char *data_offset;
4534 int rc = 0;
4535 int bytes_returned = 0;
4536 __u16 params, param_offset, offset, byte_count, count;
4537
4538 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004539 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4540
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 if (rc)
4542 return rc;
4543
Steve Frenchcd634992005-04-28 22:41:10 -07004544 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4545
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 /* At this point there is no need to override the current pid
4547 with the pid of the opener, but that could change if we someday
4548 use an existing handle (rather than opening one on the fly) */
4549 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4550 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4551
4552 params = 6;
4553 pSMB->MaxSetupCount = 0;
4554 pSMB->Reserved = 0;
4555 pSMB->Flags = 0;
4556 pSMB->Timeout = 0;
4557 pSMB->Reserved2 = 0;
4558 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4559 offset = param_offset + params;
4560
4561 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4562
4563 count = sizeof (FILE_BASIC_INFO);
4564 pSMB->MaxParameterCount = cpu_to_le16(2);
4565 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4566 pSMB->SetupCount = 1;
4567 pSMB->Reserved3 = 0;
4568 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4569 byte_count = 3 /* pad */ + params + count;
4570 pSMB->DataCount = cpu_to_le16(count);
4571 pSMB->ParameterCount = cpu_to_le16(params);
4572 pSMB->TotalDataCount = pSMB->DataCount;
4573 pSMB->TotalParameterCount = pSMB->ParameterCount;
4574 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4575 pSMB->DataOffset = cpu_to_le16(offset);
4576 pSMB->Fid = fid;
4577 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4578 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4579 else
4580 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4581 pSMB->Reserved4 = 0;
4582 pSMB->hdr.smb_buf_length += byte_count;
4583 pSMB->ByteCount = cpu_to_le16(byte_count);
4584 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4585 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4586 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4587 if (rc) {
4588 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4589 }
4590
Steve Frenchcd634992005-04-28 22:41:10 -07004591 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592
4593 /* Note: On -EAGAIN error only caller can retry on handle based calls
4594 since file handle passed in no longer valid */
4595
4596 return rc;
4597}
4598
4599
4600int
4601CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4602 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004603 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604{
4605 TRANSACTION2_SPI_REQ *pSMB = NULL;
4606 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4607 int name_len;
4608 int rc = 0;
4609 int bytes_returned = 0;
4610 char *data_offset;
4611 __u16 params, param_offset, offset, byte_count, count;
4612
4613 cFYI(1, ("In SetTimes"));
4614
4615SetTimesRetry:
4616 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4617 (void **) &pSMBr);
4618 if (rc)
4619 return rc;
4620
4621 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4622 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004623 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004624 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 name_len++; /* trailing null */
4626 name_len *= 2;
4627 } else { /* BB improve the check for buffer overruns BB */
4628 name_len = strnlen(fileName, PATH_MAX);
4629 name_len++; /* trailing null */
4630 strncpy(pSMB->FileName, fileName, name_len);
4631 }
4632
4633 params = 6 + name_len;
4634 count = sizeof (FILE_BASIC_INFO);
4635 pSMB->MaxParameterCount = cpu_to_le16(2);
4636 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4637 pSMB->MaxSetupCount = 0;
4638 pSMB->Reserved = 0;
4639 pSMB->Flags = 0;
4640 pSMB->Timeout = 0;
4641 pSMB->Reserved2 = 0;
4642 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4643 InformationLevel) - 4;
4644 offset = param_offset + params;
4645 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4646 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4647 pSMB->DataOffset = cpu_to_le16(offset);
4648 pSMB->SetupCount = 1;
4649 pSMB->Reserved3 = 0;
4650 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4651 byte_count = 3 /* pad */ + params + count;
4652
4653 pSMB->DataCount = cpu_to_le16(count);
4654 pSMB->ParameterCount = cpu_to_le16(params);
4655 pSMB->TotalDataCount = pSMB->DataCount;
4656 pSMB->TotalParameterCount = pSMB->ParameterCount;
4657 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4658 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4659 else
4660 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4661 pSMB->Reserved4 = 0;
4662 pSMB->hdr.smb_buf_length += byte_count;
4663 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4664 pSMB->ByteCount = cpu_to_le16(byte_count);
4665 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4666 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4667 if (rc) {
4668 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4669 }
4670
4671 cifs_buf_release(pSMB);
4672
4673 if (rc == -EAGAIN)
4674 goto SetTimesRetry;
4675
4676 return rc;
4677}
4678
4679/* Can not be used to set time stamps yet (due to old DOS time format) */
4680/* Can be used to set attributes */
4681#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4682 handling it anyway and NT4 was what we thought it would be needed for
4683 Do not delete it until we prove whether needed for Win9x though */
4684int
4685CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4686 __u16 dos_attrs, const struct nls_table *nls_codepage)
4687{
4688 SETATTR_REQ *pSMB = NULL;
4689 SETATTR_RSP *pSMBr = NULL;
4690 int rc = 0;
4691 int bytes_returned;
4692 int name_len;
4693
4694 cFYI(1, ("In SetAttrLegacy"));
4695
4696SetAttrLgcyRetry:
4697 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4698 (void **) &pSMBr);
4699 if (rc)
4700 return rc;
4701
4702 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4703 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004704 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 PATH_MAX, nls_codepage);
4706 name_len++; /* trailing null */
4707 name_len *= 2;
4708 } else { /* BB improve the check for buffer overruns BB */
4709 name_len = strnlen(fileName, PATH_MAX);
4710 name_len++; /* trailing null */
4711 strncpy(pSMB->fileName, fileName, name_len);
4712 }
4713 pSMB->attr = cpu_to_le16(dos_attrs);
4714 pSMB->BufferFormat = 0x04;
4715 pSMB->hdr.smb_buf_length += name_len + 1;
4716 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4717 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4718 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4719 if (rc) {
4720 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4721 }
4722
4723 cifs_buf_release(pSMB);
4724
4725 if (rc == -EAGAIN)
4726 goto SetAttrLgcyRetry;
4727
4728 return rc;
4729}
4730#endif /* temporarily unneeded SetAttr legacy function */
4731
4732int
4733CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004734 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4735 dev_t device, const struct nls_table *nls_codepage,
4736 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737{
4738 TRANSACTION2_SPI_REQ *pSMB = NULL;
4739 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4740 int name_len;
4741 int rc = 0;
4742 int bytes_returned = 0;
4743 FILE_UNIX_BASIC_INFO *data_offset;
4744 __u16 params, param_offset, offset, count, byte_count;
4745
4746 cFYI(1, ("In SetUID/GID/Mode"));
4747setPermsRetry:
4748 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4749 (void **) &pSMBr);
4750 if (rc)
4751 return rc;
4752
4753 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4754 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004755 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004756 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 name_len++; /* trailing null */
4758 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004759 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 name_len = strnlen(fileName, PATH_MAX);
4761 name_len++; /* trailing null */
4762 strncpy(pSMB->FileName, fileName, name_len);
4763 }
4764
4765 params = 6 + name_len;
4766 count = sizeof (FILE_UNIX_BASIC_INFO);
4767 pSMB->MaxParameterCount = cpu_to_le16(2);
4768 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4769 pSMB->MaxSetupCount = 0;
4770 pSMB->Reserved = 0;
4771 pSMB->Flags = 0;
4772 pSMB->Timeout = 0;
4773 pSMB->Reserved2 = 0;
4774 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4775 InformationLevel) - 4;
4776 offset = param_offset + params;
4777 data_offset =
4778 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4779 offset);
4780 memset(data_offset, 0, count);
4781 pSMB->DataOffset = cpu_to_le16(offset);
4782 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4783 pSMB->SetupCount = 1;
4784 pSMB->Reserved3 = 0;
4785 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4786 byte_count = 3 /* pad */ + params + count;
4787 pSMB->ParameterCount = cpu_to_le16(params);
4788 pSMB->DataCount = cpu_to_le16(count);
4789 pSMB->TotalParameterCount = pSMB->ParameterCount;
4790 pSMB->TotalDataCount = pSMB->DataCount;
4791 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4792 pSMB->Reserved4 = 0;
4793 pSMB->hdr.smb_buf_length += byte_count;
4794 data_offset->Uid = cpu_to_le64(uid);
4795 data_offset->Gid = cpu_to_le64(gid);
4796 /* better to leave device as zero when it is */
4797 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4798 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4799 data_offset->Permissions = cpu_to_le64(mode);
4800
4801 if(S_ISREG(mode))
4802 data_offset->Type = cpu_to_le32(UNIX_FILE);
4803 else if(S_ISDIR(mode))
4804 data_offset->Type = cpu_to_le32(UNIX_DIR);
4805 else if(S_ISLNK(mode))
4806 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4807 else if(S_ISCHR(mode))
4808 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4809 else if(S_ISBLK(mode))
4810 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4811 else if(S_ISFIFO(mode))
4812 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4813 else if(S_ISSOCK(mode))
4814 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4815
4816
4817 pSMB->ByteCount = cpu_to_le16(byte_count);
4818 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4819 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4820 if (rc) {
4821 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4822 }
4823
4824 if (pSMB)
4825 cifs_buf_release(pSMB);
4826 if (rc == -EAGAIN)
4827 goto setPermsRetry;
4828 return rc;
4829}
4830
4831int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004832 const int notify_subdirs, const __u16 netfid,
4833 __u32 filter, struct file * pfile, int multishot,
4834 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835{
4836 int rc = 0;
4837 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004838 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004839 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 int bytes_returned;
4841
4842 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4843 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4844 (void **) &pSMBr);
4845 if (rc)
4846 return rc;
4847
4848 pSMB->TotalParameterCount = 0 ;
4849 pSMB->TotalDataCount = 0;
4850 pSMB->MaxParameterCount = cpu_to_le32(2);
4851 /* BB find exact data count max from sess structure BB */
4852 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004853/* BB VERIFY verify which is correct for above BB */
4854 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4855 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4856
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 pSMB->MaxSetupCount = 4;
4858 pSMB->Reserved = 0;
4859 pSMB->ParameterOffset = 0;
4860 pSMB->DataCount = 0;
4861 pSMB->DataOffset = 0;
4862 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4863 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4864 pSMB->ParameterCount = pSMB->TotalParameterCount;
4865 if(notify_subdirs)
4866 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4867 pSMB->Reserved2 = 0;
4868 pSMB->CompletionFilter = cpu_to_le32(filter);
4869 pSMB->Fid = netfid; /* file handle always le */
4870 pSMB->ByteCount = 0;
4871
4872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4873 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4874 if (rc) {
4875 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004876 } else {
4877 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004878 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004879 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004880 sizeof(struct dir_notify_req),
4881 GFP_KERNEL);
4882 if(dnotify_req) {
4883 dnotify_req->Pid = pSMB->hdr.Pid;
4884 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4885 dnotify_req->Mid = pSMB->hdr.Mid;
4886 dnotify_req->Tid = pSMB->hdr.Tid;
4887 dnotify_req->Uid = pSMB->hdr.Uid;
4888 dnotify_req->netfid = netfid;
4889 dnotify_req->pfile = pfile;
4890 dnotify_req->filter = filter;
4891 dnotify_req->multishot = multishot;
4892 spin_lock(&GlobalMid_Lock);
4893 list_add_tail(&dnotify_req->lhead,
4894 &GlobalDnotifyReqList);
4895 spin_unlock(&GlobalMid_Lock);
4896 } else
4897 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 }
4899 cifs_buf_release(pSMB);
4900 return rc;
4901}
4902#ifdef CONFIG_CIFS_XATTR
4903ssize_t
4904CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4905 const unsigned char *searchName,
4906 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004907 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908{
4909 /* BB assumes one setup word */
4910 TRANSACTION2_QPI_REQ *pSMB = NULL;
4911 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4912 int rc = 0;
4913 int bytes_returned;
4914 int name_len;
4915 struct fea * temp_fea;
4916 char * temp_ptr;
4917 __u16 params, byte_count;
4918
4919 cFYI(1, ("In Query All EAs path %s", searchName));
4920QAllEAsRetry:
4921 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4922 (void **) &pSMBr);
4923 if (rc)
4924 return rc;
4925
4926 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4927 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004928 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004929 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 name_len++; /* trailing null */
4931 name_len *= 2;
4932 } else { /* BB improve the check for buffer overruns BB */
4933 name_len = strnlen(searchName, PATH_MAX);
4934 name_len++; /* trailing null */
4935 strncpy(pSMB->FileName, searchName, name_len);
4936 }
4937
4938 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4939 pSMB->TotalDataCount = 0;
4940 pSMB->MaxParameterCount = cpu_to_le16(2);
4941 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4942 pSMB->MaxSetupCount = 0;
4943 pSMB->Reserved = 0;
4944 pSMB->Flags = 0;
4945 pSMB->Timeout = 0;
4946 pSMB->Reserved2 = 0;
4947 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4948 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4949 pSMB->DataCount = 0;
4950 pSMB->DataOffset = 0;
4951 pSMB->SetupCount = 1;
4952 pSMB->Reserved3 = 0;
4953 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4954 byte_count = params + 1 /* pad */ ;
4955 pSMB->TotalParameterCount = cpu_to_le16(params);
4956 pSMB->ParameterCount = pSMB->TotalParameterCount;
4957 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4958 pSMB->Reserved4 = 0;
4959 pSMB->hdr.smb_buf_length += byte_count;
4960 pSMB->ByteCount = cpu_to_le16(byte_count);
4961
4962 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4963 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4964 if (rc) {
4965 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4966 } else { /* decode response */
4967 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4968
4969 /* BB also check enough total bytes returned */
4970 /* BB we need to improve the validity checking
4971 of these trans2 responses */
4972 if (rc || (pSMBr->ByteCount < 4))
4973 rc = -EIO; /* bad smb */
4974 /* else if (pFindData){
4975 memcpy((char *) pFindData,
4976 (char *) &pSMBr->hdr.Protocol +
4977 data_offset, kl);
4978 }*/ else {
4979 /* check that length of list is not more than bcc */
4980 /* check that each entry does not go beyond length
4981 of list */
4982 /* check that each element of each entry does not
4983 go beyond end of list */
4984 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4985 struct fealist * ea_response_data;
4986 rc = 0;
4987 /* validate_trans2_offsets() */
4988 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4989 ea_response_data = (struct fealist *)
4990 (((char *) &pSMBr->hdr.Protocol) +
4991 data_offset);
4992 name_len = le32_to_cpu(ea_response_data->list_len);
4993 cFYI(1,("ea length %d", name_len));
4994 if(name_len <= 8) {
4995 /* returned EA size zeroed at top of function */
4996 cFYI(1,("empty EA list returned from server"));
4997 } else {
4998 /* account for ea list len */
4999 name_len -= 4;
5000 temp_fea = ea_response_data->list;
5001 temp_ptr = (char *)temp_fea;
5002 while(name_len > 0) {
5003 __u16 value_len;
5004 name_len -= 4;
5005 temp_ptr += 4;
5006 rc += temp_fea->name_len;
5007 /* account for prefix user. and trailing null */
5008 rc = rc + 5 + 1;
5009 if(rc<(int)buf_size) {
5010 memcpy(EAData,"user.",5);
5011 EAData+=5;
5012 memcpy(EAData,temp_ptr,temp_fea->name_len);
5013 EAData+=temp_fea->name_len;
5014 /* null terminate name */
5015 *EAData = 0;
5016 EAData = EAData + 1;
5017 } else if(buf_size == 0) {
5018 /* skip copy - calc size only */
5019 } else {
5020 /* stop before overrun buffer */
5021 rc = -ERANGE;
5022 break;
5023 }
5024 name_len -= temp_fea->name_len;
5025 temp_ptr += temp_fea->name_len;
5026 /* account for trailing null */
5027 name_len--;
5028 temp_ptr++;
5029 value_len = le16_to_cpu(temp_fea->value_len);
5030 name_len -= value_len;
5031 temp_ptr += value_len;
5032 /* BB check that temp_ptr is still within smb BB*/
5033 /* no trailing null to account for in value len */
5034 /* go on to next EA */
5035 temp_fea = (struct fea *)temp_ptr;
5036 }
5037 }
5038 }
5039 }
5040 if (pSMB)
5041 cifs_buf_release(pSMB);
5042 if (rc == -EAGAIN)
5043 goto QAllEAsRetry;
5044
5045 return (ssize_t)rc;
5046}
5047
5048ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5049 const unsigned char * searchName,const unsigned char * ea_name,
5050 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005051 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052{
5053 TRANSACTION2_QPI_REQ *pSMB = NULL;
5054 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5055 int rc = 0;
5056 int bytes_returned;
5057 int name_len;
5058 struct fea * temp_fea;
5059 char * temp_ptr;
5060 __u16 params, byte_count;
5061
5062 cFYI(1, ("In Query EA path %s", searchName));
5063QEARetry:
5064 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5065 (void **) &pSMBr);
5066 if (rc)
5067 return rc;
5068
5069 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5070 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005071 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005072 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 name_len++; /* trailing null */
5074 name_len *= 2;
5075 } else { /* BB improve the check for buffer overruns BB */
5076 name_len = strnlen(searchName, PATH_MAX);
5077 name_len++; /* trailing null */
5078 strncpy(pSMB->FileName, searchName, name_len);
5079 }
5080
5081 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5082 pSMB->TotalDataCount = 0;
5083 pSMB->MaxParameterCount = cpu_to_le16(2);
5084 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5085 pSMB->MaxSetupCount = 0;
5086 pSMB->Reserved = 0;
5087 pSMB->Flags = 0;
5088 pSMB->Timeout = 0;
5089 pSMB->Reserved2 = 0;
5090 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5091 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5092 pSMB->DataCount = 0;
5093 pSMB->DataOffset = 0;
5094 pSMB->SetupCount = 1;
5095 pSMB->Reserved3 = 0;
5096 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5097 byte_count = params + 1 /* pad */ ;
5098 pSMB->TotalParameterCount = cpu_to_le16(params);
5099 pSMB->ParameterCount = pSMB->TotalParameterCount;
5100 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5101 pSMB->Reserved4 = 0;
5102 pSMB->hdr.smb_buf_length += byte_count;
5103 pSMB->ByteCount = cpu_to_le16(byte_count);
5104
5105 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5106 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5107 if (rc) {
5108 cFYI(1, ("Send error in Query EA = %d", rc));
5109 } else { /* decode response */
5110 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5111
5112 /* BB also check enough total bytes returned */
5113 /* BB we need to improve the validity checking
5114 of these trans2 responses */
5115 if (rc || (pSMBr->ByteCount < 4))
5116 rc = -EIO; /* bad smb */
5117 /* else if (pFindData){
5118 memcpy((char *) pFindData,
5119 (char *) &pSMBr->hdr.Protocol +
5120 data_offset, kl);
5121 }*/ else {
5122 /* check that length of list is not more than bcc */
5123 /* check that each entry does not go beyond length
5124 of list */
5125 /* check that each element of each entry does not
5126 go beyond end of list */
5127 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5128 struct fealist * ea_response_data;
5129 rc = -ENODATA;
5130 /* validate_trans2_offsets() */
5131 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5132 ea_response_data = (struct fealist *)
5133 (((char *) &pSMBr->hdr.Protocol) +
5134 data_offset);
5135 name_len = le32_to_cpu(ea_response_data->list_len);
5136 cFYI(1,("ea length %d", name_len));
5137 if(name_len <= 8) {
5138 /* returned EA size zeroed at top of function */
5139 cFYI(1,("empty EA list returned from server"));
5140 } else {
5141 /* account for ea list len */
5142 name_len -= 4;
5143 temp_fea = ea_response_data->list;
5144 temp_ptr = (char *)temp_fea;
5145 /* loop through checking if we have a matching
5146 name and then return the associated value */
5147 while(name_len > 0) {
5148 __u16 value_len;
5149 name_len -= 4;
5150 temp_ptr += 4;
5151 value_len = le16_to_cpu(temp_fea->value_len);
5152 /* BB validate that value_len falls within SMB,
5153 even though maximum for name_len is 255 */
5154 if(memcmp(temp_fea->name,ea_name,
5155 temp_fea->name_len) == 0) {
5156 /* found a match */
5157 rc = value_len;
5158 /* account for prefix user. and trailing null */
5159 if(rc<=(int)buf_size) {
5160 memcpy(ea_value,
5161 temp_fea->name+temp_fea->name_len+1,
5162 rc);
5163 /* ea values, unlike ea names,
5164 are not null terminated */
5165 } else if(buf_size == 0) {
5166 /* skip copy - calc size only */
5167 } else {
5168 /* stop before overrun buffer */
5169 rc = -ERANGE;
5170 }
5171 break;
5172 }
5173 name_len -= temp_fea->name_len;
5174 temp_ptr += temp_fea->name_len;
5175 /* account for trailing null */
5176 name_len--;
5177 temp_ptr++;
5178 name_len -= value_len;
5179 temp_ptr += value_len;
5180 /* no trailing null to account for in value len */
5181 /* go on to next EA */
5182 temp_fea = (struct fea *)temp_ptr;
5183 }
5184 }
5185 }
5186 }
5187 if (pSMB)
5188 cifs_buf_release(pSMB);
5189 if (rc == -EAGAIN)
5190 goto QEARetry;
5191
5192 return (ssize_t)rc;
5193}
5194
5195int
5196CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5197 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005198 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5199 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200{
5201 struct smb_com_transaction2_spi_req *pSMB = NULL;
5202 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5203 struct fealist *parm_data;
5204 int name_len;
5205 int rc = 0;
5206 int bytes_returned = 0;
5207 __u16 params, param_offset, byte_count, offset, count;
5208
5209 cFYI(1, ("In SetEA"));
5210SetEARetry:
5211 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5212 (void **) &pSMBr);
5213 if (rc)
5214 return rc;
5215
5216 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5217 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005218 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005219 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 name_len++; /* trailing null */
5221 name_len *= 2;
5222 } else { /* BB improve the check for buffer overruns BB */
5223 name_len = strnlen(fileName, PATH_MAX);
5224 name_len++; /* trailing null */
5225 strncpy(pSMB->FileName, fileName, name_len);
5226 }
5227
5228 params = 6 + name_len;
5229
5230 /* done calculating parms using name_len of file name,
5231 now use name_len to calculate length of ea name
5232 we are going to create in the inode xattrs */
5233 if(ea_name == NULL)
5234 name_len = 0;
5235 else
5236 name_len = strnlen(ea_name,255);
5237
5238 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5239 pSMB->MaxParameterCount = cpu_to_le16(2);
5240 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5241 pSMB->MaxSetupCount = 0;
5242 pSMB->Reserved = 0;
5243 pSMB->Flags = 0;
5244 pSMB->Timeout = 0;
5245 pSMB->Reserved2 = 0;
5246 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5247 InformationLevel) - 4;
5248 offset = param_offset + params;
5249 pSMB->InformationLevel =
5250 cpu_to_le16(SMB_SET_FILE_EA);
5251
5252 parm_data =
5253 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5254 offset);
5255 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5256 pSMB->DataOffset = cpu_to_le16(offset);
5257 pSMB->SetupCount = 1;
5258 pSMB->Reserved3 = 0;
5259 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5260 byte_count = 3 /* pad */ + params + count;
5261 pSMB->DataCount = cpu_to_le16(count);
5262 parm_data->list_len = cpu_to_le32(count);
5263 parm_data->list[0].EA_flags = 0;
5264 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005265 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 /* EA names are always ASCII */
5267 if(ea_name)
5268 strncpy(parm_data->list[0].name,ea_name,name_len);
5269 parm_data->list[0].name[name_len] = 0;
5270 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5271 /* caller ensures that ea_value_len is less than 64K but
5272 we need to ensure that it fits within the smb */
5273
5274 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5275 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5276 if(ea_value_len)
5277 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5278
5279 pSMB->TotalDataCount = pSMB->DataCount;
5280 pSMB->ParameterCount = cpu_to_le16(params);
5281 pSMB->TotalParameterCount = pSMB->ParameterCount;
5282 pSMB->Reserved4 = 0;
5283 pSMB->hdr.smb_buf_length += byte_count;
5284 pSMB->ByteCount = cpu_to_le16(byte_count);
5285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5287 if (rc) {
5288 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5289 }
5290
5291 cifs_buf_release(pSMB);
5292
5293 if (rc == -EAGAIN)
5294 goto SetEARetry;
5295
5296 return rc;
5297}
5298
5299#endif