blob: 48fc0c2ab0e5fb022e8b714cf561a55a521b1737 [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 French8af18972007-02-14 04:42:51 +0000161 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
162 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000164 /* tell server which Unix caps we support */
165 if (tcon->ses->capabilities & CAP_UNIX)
166 reset_cifs_unix_caps(0 /* no xid */,
167 tcon,
168 NULL /* we do not know sb */,
169 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700170 /* BB FIXME add code to check if wsize needs
171 update due to negotiated smb buffer size
172 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 if(rc == 0)
174 atomic_inc(&tconInfoReconnectCount);
175
176 cFYI(1, ("reconnect tcon rc = %d", rc));
177 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700178 it is safer (and faster) to reopen files
179 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700182 know whether we can continue or not without
183 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 switch(smb_command) {
185 case SMB_COM_READ_ANDX:
186 case SMB_COM_WRITE_ANDX:
187 case SMB_COM_CLOSE:
188 case SMB_COM_FIND_CLOSE2:
189 case SMB_COM_LOCKING_ANDX: {
190 unload_nls(nls_codepage);
191 return -EAGAIN;
192 }
193 }
194 } else {
195 up(&tcon->ses->sesSem);
196 }
197 unload_nls(nls_codepage);
198
199 } else {
200 return -EIO;
201 }
202 }
203 if(rc)
204 return rc;
205
206 *request_buf = cifs_small_buf_get();
207 if (*request_buf == NULL) {
208 /* BB should we add a retry in here if not a writepage? */
209 return -ENOMEM;
210 }
211
212 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
213
Steve Frencha4544342005-08-24 13:59:35 -0700214 if(tcon != NULL)
215 cifs_stats_inc(&tcon->num_smbs_sent);
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000218}
219
Steve French12b3b8f2006-02-09 21:12:47 +0000220int
Steve French5815449d2006-02-14 01:36:20 +0000221small_smb_init_no_tc(const int smb_command, const int wct,
222 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000223{
224 int rc;
225 struct smb_hdr * buffer;
226
Steve French5815449d2006-02-14 01:36:20 +0000227 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000228 if(rc)
229 return rc;
230
Steve French04fdabe2006-02-10 05:52:50 +0000231 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000232 buffer->Mid = GetNextMid(ses->server);
233 if (ses->capabilities & CAP_UNICODE)
234 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000235 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000236 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
237
238 /* uid, tid can stay at zero as set in header assemble */
239
240 /* BB add support for turning on the signing when
241 this function is used after 1st of session setup requests */
242
243 return rc;
244}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246/* If the return code is zero, this function must fill in request_buf pointer */
247static int
248smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
249 void **request_buf /* returned */ ,
250 void **response_buf /* returned */ )
251{
252 int rc = 0;
253
254 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
255 check for tcp and smb session status done differently
256 for those three - in the calling routine */
257 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800258 if(tcon->tidStatus == CifsExiting) {
259 /* only tree disconnect, open, and write,
260 (and ulogoff which does not have tcon)
261 are allowed as we start force umount */
262 if((smb_command != SMB_COM_WRITE_ANDX) &&
263 (smb_command != SMB_COM_OPEN_ANDX) &&
264 (smb_command != SMB_COM_TREE_DISCONNECT)) {
265 cFYI(1,("can not send cmd %d while umounting",
266 smb_command));
267 return -ENODEV;
268 }
269 }
270
Steve French31ca3bc2005-04-28 22:41:11 -0700271 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
272 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700274 /* Give Demultiplex thread up to 10 seconds to
275 reconnect, should be greater than cifs socket
276 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
278 wait_event_interruptible_timeout(tcon->ses->server->response_q,
279 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700280 if(tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 /* on "soft" mounts we wait once */
283 if((tcon->retry == FALSE) ||
284 (tcon->ses->status == CifsExiting)) {
285 cFYI(1,("gave up waiting on reconnect in smb_init"));
286 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700287 } /* else "hard" mount - keep retrying
288 until process is killed or server
289 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 } else /* TCP session is reestablished now */
291 break;
292
293 }
294
295 nls_codepage = load_nls_default();
296 /* need to prevent multiple threads trying to
297 simultaneously reconnect the same SMB session */
298 down(&tcon->ses->sesSem);
299 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700300 rc = cifs_setup_session(0, tcon->ses,
301 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
303 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700304 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
305 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000307 /* tell server which Unix caps we support */
308 if (tcon->ses->capabilities & CAP_UNIX)
309 reset_cifs_unix_caps(0 /* no xid */,
310 tcon,
311 NULL /* do not know sb */,
312 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 if(rc == 0)
317 atomic_inc(&tconInfoReconnectCount);
318
319 cFYI(1, ("reconnect tcon rc = %d", rc));
320 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700321 it is safer (and faster) to reopen files
322 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700325 know whether we can continue or not without
326 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 switch(smb_command) {
328 case SMB_COM_READ_ANDX:
329 case SMB_COM_WRITE_ANDX:
330 case SMB_COM_CLOSE:
331 case SMB_COM_FIND_CLOSE2:
332 case SMB_COM_LOCKING_ANDX: {
333 unload_nls(nls_codepage);
334 return -EAGAIN;
335 }
336 }
337 } else {
338 up(&tcon->ses->sesSem);
339 }
340 unload_nls(nls_codepage);
341
342 } else {
343 return -EIO;
344 }
345 }
346 if(rc)
347 return rc;
348
349 *request_buf = cifs_buf_get();
350 if (*request_buf == NULL) {
351 /* BB should we add a retry in here if not a writepage? */
352 return -ENOMEM;
353 }
354 /* Although the original thought was we needed the response buf for */
355 /* potential retries of smb operations it turns out we can determine */
356 /* from the mid flags when the request buffer can be resent without */
357 /* having to use a second distinct buffer for the response */
Steve French39798772006-05-31 22:40:51 +0000358 if(response_buf)
359 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
362 wct /*wct */ );
363
Steve Frencha4544342005-08-24 13:59:35 -0700364 if(tcon != NULL)
365 cifs_stats_inc(&tcon->num_smbs_sent);
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return rc;
368}
369
370static int validate_t2(struct smb_t2_rsp * pSMB)
371{
372 int rc = -EINVAL;
373 int total_size;
374 char * pBCC;
375
376 /* check for plausible wct, bcc and t2 data and parm sizes */
377 /* check for parm and data offset going beyond end of smb */
378 if(pSMB->hdr.WordCount >= 10) {
379 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
380 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
381 /* check that bcc is at least as big as parms + data */
382 /* check that bcc is less than negotiated smb buffer */
383 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
384 if(total_size < 512) {
385 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
386 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700387 pBCC = (pSMB->hdr.WordCount * 2) +
388 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 (char *)pSMB;
390 if((total_size <= (*(u16 *)pBCC)) &&
391 (total_size <
392 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
393 return 0;
394 }
395
396 }
397 }
398 }
399 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
400 sizeof(struct smb_t2_rsp) + 16);
401 return rc;
402}
403int
404CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
405{
406 NEGOTIATE_REQ *pSMB;
407 NEGOTIATE_RSP *pSMBr;
408 int rc = 0;
409 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000410 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 struct TCP_Server_Info * server;
412 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000413 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100414 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 if(ses->server)
417 server = ses->server;
418 else {
419 rc = -EIO;
420 return rc;
421 }
422 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
423 (void **) &pSMB, (void **) &pSMBr);
424 if (rc)
425 return rc;
Steve French750d1152006-06-27 06:28:30 +0000426
427 /* if any of auth flags (ie not sign or seal) are overriden use them */
428 if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
429 secFlags = ses->overrideSecFlg;
430 else /* if override flags set only sign/seal OR them with global auth */
431 secFlags = extended_security | ses->overrideSecFlg;
432
Steve Frenchf40c5622006-06-28 00:13:38 +0000433 cFYI(1,("secFlags 0x%x",secFlags));
434
Steve French1982c342005-08-17 12:38:22 -0700435 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French750d1152006-06-27 06:28:30 +0000437 if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000438 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000439
440 count = 0;
441 for(i=0;i<CIFS_NUM_PROT;i++) {
442 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
443 count += strlen(protocols[i].name) + 1;
444 /* null at end of source and target buffers anyway */
445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 pSMB->hdr.smb_buf_length += count;
447 pSMB->ByteCount = cpu_to_le16(count);
448
449 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000451 if (rc != 0)
452 goto neg_err_exit;
453
Al Viro733f99a2006-10-14 16:48:26 +0100454 dialect = le16_to_cpu(pSMBr->DialectIndex);
455 cFYI(1,("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000456 /* Check wct = 1 error case */
Al Viro733f99a2006-10-14 16:48:26 +0100457 if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000458 /* core returns wct = 1, but we do not ask for core - otherwise
459 small wct just comes when dialect index is -1 indicating we
460 could not negotiate a common dialect */
461 rc = -EOPNOTSUPP;
462 goto neg_err_exit;
463#ifdef CONFIG_CIFS_WEAK_PW_HASH
464 } else if((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100465 && ((dialect == LANMAN_PROT)
466 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000467 __s16 tmp;
Steve French254e55e2006-06-04 05:53:15 +0000468 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
469
Steve French750d1152006-06-27 06:28:30 +0000470 if((secFlags & CIFSSEC_MAY_LANMAN) ||
471 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000472 server->secType = LANMAN;
473 else {
474 cERROR(1, ("mount failed weak security disabled"
475 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000476 rc = -EOPNOTSUPP;
477 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000478 }
479 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
480 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
481 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000482 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000483 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
484 /* even though we do not use raw we might as well set this
485 accurately, in case we ever find a need for it */
486 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
487 server->maxRw = 0xFF00;
488 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
489 } else {
490 server->maxRw = 0;/* we do not need to use raw anyway */
491 server->capabilities = CAP_MPX_MODE;
492 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000494 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000495 /* OS/2 often does not set timezone therefore
496 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000497 * Could deviate slightly from the right zone.
498 * Smallest defined timezone difference is 15 minutes
499 * (i.e. Nepal). Rounding up/down is done to match
500 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000501 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000502 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000503 struct timespec ts, utc;
504 utc = CURRENT_TIME;
505 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
506 le16_to_cpu(rsp->SrvTime.Time));
507 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
508 (int)ts.tv_sec, (int)utc.tv_sec,
509 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000510 val = (int)(utc.tv_sec - ts.tv_sec);
511 seconds = val < 0 ? -val : val;
Steve French947a5062006-10-02 05:55:25 +0000512 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000513 remain = seconds % MIN_TZ_ADJ;
514 if(remain >= (MIN_TZ_ADJ / 2))
515 result += MIN_TZ_ADJ;
516 if(val < 0)
517 result = - result;
518 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000519 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000520 server->timeAdj = (int)tmp;
521 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000522 }
Steve French175ec9e2006-09-30 01:07:38 +0000523 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000524
Steve French39798772006-05-31 22:40:51 +0000525
Steve French254e55e2006-06-04 05:53:15 +0000526 /* BB get server time for time conversions and add
527 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000528
Steve French25ee4a92006-09-30 00:54:23 +0000529 if (rsp->EncryptionKeyLength ==
530 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000531 memcpy(server->cryptKey, rsp->EncryptionKey,
532 CIFS_CRYPTO_KEY_SIZE);
533 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
534 rc = -EIO; /* need cryptkey unless plain text */
535 goto neg_err_exit;
536 }
Steve French39798772006-05-31 22:40:51 +0000537
Steve French254e55e2006-06-04 05:53:15 +0000538 cFYI(1,("LANMAN negotiated"));
539 /* we will not end up setting signing flags - as no signing
540 was in LANMAN and server did not return the flags on */
541 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000542#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000543 } else if(pSMBr->hdr.WordCount == 13) {
544 cERROR(1,("mount failed, cifs module not built "
545 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000546 rc = -EOPNOTSUPP;
547#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000548 goto neg_err_exit;
549 } else if(pSMBr->hdr.WordCount != 17) {
550 /* unknown wct */
551 rc = -EOPNOTSUPP;
552 goto neg_err_exit;
553 }
554 /* else wct == 17 NTLM */
555 server->secMode = pSMBr->SecurityMode;
556 if((server->secMode & SECMODE_USER) == 0)
557 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000558
Steve French254e55e2006-06-04 05:53:15 +0000559 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000560#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000561 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000562#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000563 cERROR(1,("Server requests plain text password"
564 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000565
Steve Frenchf40c5622006-06-28 00:13:38 +0000566 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000567 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000568 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000569 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000570 else if(secFlags & CIFSSEC_MAY_NTLMV2)
571 server->secType = NTLMv2;
572 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000573
Steve French254e55e2006-06-04 05:53:15 +0000574 /* one byte, so no need to convert this or EncryptionKeyLen from
575 little endian */
576 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
577 /* probably no need to store and check maxvcs */
578 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000580 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
581 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
582 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
583 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000584 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
585 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000586 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
587 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
588 CIFS_CRYPTO_KEY_SIZE);
589 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
590 && (pSMBr->EncryptionKeyLength == 0)) {
591 /* decode security blob */
592 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
593 rc = -EIO; /* no crypt key only if plain text pwd */
594 goto neg_err_exit;
595 }
596
597 /* BB might be helpful to save off the domain of server here */
598
599 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
600 (server->capabilities & CAP_EXTENDED_SECURITY)) {
601 count = pSMBr->ByteCount;
602 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000604 else if (count == 16) {
605 server->secType = RawNTLMSSP;
606 if (server->socketUseCount.counter > 1) {
607 if (memcmp(server->server_GUID,
608 pSMBr->u.extended_response.
609 GUID, 16) != 0) {
610 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000612 pSMBr->u.extended_response.GUID,
613 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
Steve French254e55e2006-06-04 05:53:15 +0000615 } else
616 memcpy(server->server_GUID,
617 pSMBr->u.extended_response.GUID, 16);
618 } else {
619 rc = decode_negTokenInit(pSMBr->u.extended_response.
620 SecurityBlob,
621 count - 16,
622 &server->secType);
623 if(rc == 1) {
624 /* BB Need to fill struct for sessetup here */
625 rc = -EOPNOTSUPP;
626 } else {
627 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
Steve French254e55e2006-06-04 05:53:15 +0000630 } else
631 server->capabilities &= ~CAP_EXTENDED_SECURITY;
632
Steve French6344a422006-06-12 04:18:35 +0000633#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000634signing_check:
Steve French6344a422006-06-12 04:18:35 +0000635#endif
Steve French254e55e2006-06-04 05:53:15 +0000636 if(sign_CIFS_PDUs == FALSE) {
637 if(server->secMode & SECMODE_SIGN_REQUIRED)
638 cERROR(1,("Server requires "
639 "/proc/fs/cifs/PacketSigningEnabled to be on"));
640 server->secMode &=
641 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
642 } else if(sign_CIFS_PDUs == 1) {
643 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
644 server->secMode &=
645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
646 } else if(sign_CIFS_PDUs == 2) {
647 if((server->secMode &
648 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
649 cERROR(1,("signing required but server lacks support"));
650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
Steve French39798772006-05-31 22:40:51 +0000652neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700653 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000654
655 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 return rc;
657}
658
659int
660CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
661{
662 struct smb_hdr *smb_buffer;
663 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
664 int rc = 0;
665 int length;
666
667 cFYI(1, ("In tree disconnect"));
668 /*
669 * If last user of the connection and
670 * connection alive - disconnect it
671 * If this is the last connection on the server session disconnect it
672 * (and inside session disconnect we should check if tcp socket needs
673 * to be freed and kernel thread woken up).
674 */
675 if (tcon)
676 down(&tcon->tconSem);
677 else
678 return -EIO;
679
680 atomic_dec(&tcon->useCount);
681 if (atomic_read(&tcon->useCount) > 0) {
682 up(&tcon->tconSem);
683 return -EBUSY;
684 }
685
686 /* No need to return error on this operation if tid invalidated and
687 closed on server already e.g. due to tcp session crashing */
688 if(tcon->tidStatus == CifsNeedReconnect) {
689 up(&tcon->tconSem);
690 return 0;
691 }
692
693 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
694 up(&tcon->tconSem);
695 return -EIO;
696 }
Steve French09d1db52005-04-28 22:41:08 -0700697 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
698 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (rc) {
700 up(&tcon->tconSem);
701 return rc;
702 } else {
703 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
706 &length, 0);
707 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700708 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 if (smb_buffer)
711 cifs_small_buf_release(smb_buffer);
712 up(&tcon->tconSem);
713
714 /* No need to return error on this operation if tid invalidated and
715 closed on server already e.g. due to tcp session crashing */
716 if (rc == -EAGAIN)
717 rc = 0;
718
719 return rc;
720}
721
722int
723CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
724{
725 struct smb_hdr *smb_buffer_response;
726 LOGOFF_ANDX_REQ *pSMB;
727 int rc = 0;
728 int length;
729
730 cFYI(1, ("In SMBLogoff for session disconnect"));
731 if (ses)
732 down(&ses->sesSem);
733 else
734 return -EIO;
735
736 atomic_dec(&ses->inUse);
737 if (atomic_read(&ses->inUse) > 0) {
738 up(&ses->sesSem);
739 return -EBUSY;
740 }
741 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
742 if (rc) {
743 up(&ses->sesSem);
744 return rc;
745 }
746
747 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
748
749 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700750 pSMB->hdr.Mid = GetNextMid(ses->server);
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if(ses->server->secMode &
753 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
754 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
755 }
756
757 pSMB->hdr.Uid = ses->Suid;
758
759 pSMB->AndXCommand = 0xFF;
760 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
761 smb_buffer_response, &length, 0);
762 if (ses->server) {
763 atomic_dec(&ses->server->socketUseCount);
764 if (atomic_read(&ses->server->socketUseCount) == 0) {
765 spin_lock(&GlobalMid_Lock);
766 ses->server->tcpStatus = CifsExiting;
767 spin_unlock(&GlobalMid_Lock);
768 rc = -ESHUTDOWN;
769 }
770 }
Steve Frencha59c6582005-08-17 12:12:19 -0700771 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700772 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774 /* if session dead then we do not need to do ulogoff,
775 since server closed smb session, no sense reporting
776 error */
777 if (rc == -EAGAIN)
778 rc = 0;
779 return rc;
780}
781
782int
Steve French737b7582005-04-28 22:41:06 -0700783CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
784 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
786 DELETE_FILE_REQ *pSMB = NULL;
787 DELETE_FILE_RSP *pSMBr = NULL;
788 int rc = 0;
789 int bytes_returned;
790 int name_len;
791
792DelFileRetry:
793 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
794 (void **) &pSMBr);
795 if (rc)
796 return rc;
797
798 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
799 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500800 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700801 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 name_len++; /* trailing null */
803 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700804 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 name_len = strnlen(fileName, PATH_MAX);
806 name_len++; /* trailing null */
807 strncpy(pSMB->fileName, fileName, name_len);
808 }
809 pSMB->SearchAttributes =
810 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
811 pSMB->BufferFormat = 0x04;
812 pSMB->hdr.smb_buf_length += name_len + 1;
813 pSMB->ByteCount = cpu_to_le16(name_len + 1);
814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700816 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (rc) {
818 cFYI(1, ("Error in RMFile = %d", rc));
819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 cifs_buf_release(pSMB);
822 if (rc == -EAGAIN)
823 goto DelFileRetry;
824
825 return rc;
826}
827
828int
Steve French737b7582005-04-28 22:41:06 -0700829CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
830 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
832 DELETE_DIRECTORY_REQ *pSMB = NULL;
833 DELETE_DIRECTORY_RSP *pSMBr = NULL;
834 int rc = 0;
835 int bytes_returned;
836 int name_len;
837
838 cFYI(1, ("In CIFSSMBRmDir"));
839RmDirRetry:
840 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
841 (void **) &pSMBr);
842 if (rc)
843 return rc;
844
845 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700846 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
847 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 name_len++; /* trailing null */
849 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700850 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 name_len = strnlen(dirName, PATH_MAX);
852 name_len++; /* trailing null */
853 strncpy(pSMB->DirName, dirName, name_len);
854 }
855
856 pSMB->BufferFormat = 0x04;
857 pSMB->hdr.smb_buf_length += name_len + 1;
858 pSMB->ByteCount = cpu_to_le16(name_len + 1);
859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700861 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (rc) {
863 cFYI(1, ("Error in RMDir = %d", rc));
864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 cifs_buf_release(pSMB);
867 if (rc == -EAGAIN)
868 goto RmDirRetry;
869 return rc;
870}
871
872int
873CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700874 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 int rc = 0;
877 CREATE_DIRECTORY_REQ *pSMB = NULL;
878 CREATE_DIRECTORY_RSP *pSMBr = NULL;
879 int bytes_returned;
880 int name_len;
881
882 cFYI(1, ("In CIFSSMBMkDir"));
883MkDirRetry:
884 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
885 (void **) &pSMBr);
886 if (rc)
887 return rc;
888
889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500890 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700891 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 name_len++; /* trailing null */
893 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700894 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 name_len = strnlen(name, PATH_MAX);
896 name_len++; /* trailing null */
897 strncpy(pSMB->DirName, name, name_len);
898 }
899
900 pSMB->BufferFormat = 0x04;
901 pSMB->hdr.smb_buf_length += name_len + 1;
902 pSMB->ByteCount = cpu_to_le16(name_len + 1);
903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700905 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (rc) {
907 cFYI(1, ("Error in Mkdir = %d", rc));
908 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 cifs_buf_release(pSMB);
911 if (rc == -EAGAIN)
912 goto MkDirRetry;
913 return rc;
914}
915
Steve Frencha9d02ad2005-08-24 23:06:05 -0700916static __u16 convert_disposition(int disposition)
917{
918 __u16 ofun = 0;
919
920 switch (disposition) {
921 case FILE_SUPERSEDE:
922 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
923 break;
924 case FILE_OPEN:
925 ofun = SMBOPEN_OAPPEND;
926 break;
927 case FILE_CREATE:
928 ofun = SMBOPEN_OCREATE;
929 break;
930 case FILE_OPEN_IF:
931 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
932 break;
933 case FILE_OVERWRITE:
934 ofun = SMBOPEN_OTRUNC;
935 break;
936 case FILE_OVERWRITE_IF:
937 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
938 break;
939 default:
940 cFYI(1,("unknown disposition %d",disposition));
941 ofun = SMBOPEN_OAPPEND; /* regular open */
942 }
943 return ofun;
944}
945
946int
947SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
948 const char *fileName, const int openDisposition,
949 const int access_flags, const int create_options, __u16 * netfid,
950 int *pOplock, FILE_ALL_INFO * pfile_info,
951 const struct nls_table *nls_codepage, int remap)
952{
953 int rc = -EACCES;
954 OPENX_REQ *pSMB = NULL;
955 OPENX_RSP *pSMBr = NULL;
956 int bytes_returned;
957 int name_len;
958 __u16 count;
959
960OldOpenRetry:
961 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
962 (void **) &pSMBr);
963 if (rc)
964 return rc;
965
966 pSMB->AndXCommand = 0xFF; /* none */
967
968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
969 count = 1; /* account for one byte pad to word boundary */
970 name_len =
971 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
972 fileName, PATH_MAX, nls_codepage, remap);
973 name_len++; /* trailing null */
974 name_len *= 2;
975 } else { /* BB improve check for buffer overruns BB */
976 count = 0; /* no pad */
977 name_len = strnlen(fileName, PATH_MAX);
978 name_len++; /* trailing null */
979 strncpy(pSMB->fileName, fileName, name_len);
980 }
981 if (*pOplock & REQ_OPLOCK)
982 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
983 else if (*pOplock & REQ_BATCHOPLOCK) {
984 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
985 }
986 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
987 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
988 /* 0 = read
989 1 = write
990 2 = rw
991 3 = execute
992 */
993 pSMB->Mode = cpu_to_le16(2);
994 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
995 /* set file as system file if special file such
996 as fifo and server expecting SFU style and
997 no Unix extensions */
998
999 if(create_options & CREATE_OPTION_SPECIAL)
1000 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1001 else
Steve French3e87d802005-09-18 20:49:21 -07001002 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001003
1004 /* if ((omode & S_IWUGO) == 0)
1005 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1006 /* Above line causes problems due to vfs splitting create into two
1007 pieces - need to set mode after file created not while it is
1008 being created */
1009
1010 /* BB FIXME BB */
1011/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
1012 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001013
1014 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001015 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001016 count += name_len;
1017 pSMB->hdr.smb_buf_length += count;
1018
1019 pSMB->ByteCount = cpu_to_le16(count);
1020 /* long_op set to 1 to allow for oplock break timeouts */
1021 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1022 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1023 cifs_stats_inc(&tcon->num_opens);
1024 if (rc) {
1025 cFYI(1, ("Error in Open = %d", rc));
1026 } else {
1027 /* BB verify if wct == 15 */
1028
1029/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1030
1031 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1032 /* Let caller know file was created so we can set the mode. */
1033 /* Do we care about the CreateAction in any other cases? */
1034 /* BB FIXME BB */
1035/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1036 *pOplock |= CIFS_CREATE_ACTION; */
1037 /* BB FIXME END */
1038
1039 if(pfile_info) {
1040 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1041 pfile_info->LastAccessTime = 0; /* BB fixme */
1042 pfile_info->LastWriteTime = 0; /* BB fixme */
1043 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001044 pfile_info->Attributes =
1045 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001046 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001047 pfile_info->AllocationSize =
1048 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1049 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001050 pfile_info->NumberOfLinks = cpu_to_le32(1);
1051 }
1052 }
1053
1054 cifs_buf_release(pSMB);
1055 if (rc == -EAGAIN)
1056 goto OldOpenRetry;
1057 return rc;
1058}
1059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060int
1061CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1062 const char *fileName, const int openDisposition,
1063 const int access_flags, const int create_options, __u16 * netfid,
1064 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001065 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
1067 int rc = -EACCES;
1068 OPEN_REQ *pSMB = NULL;
1069 OPEN_RSP *pSMBr = NULL;
1070 int bytes_returned;
1071 int name_len;
1072 __u16 count;
1073
1074openRetry:
1075 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1076 (void **) &pSMBr);
1077 if (rc)
1078 return rc;
1079
1080 pSMB->AndXCommand = 0xFF; /* none */
1081
1082 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1083 count = 1; /* account for one byte pad to word boundary */
1084 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001085 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001086 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 name_len++; /* trailing null */
1088 name_len *= 2;
1089 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001090 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 count = 0; /* no pad */
1092 name_len = strnlen(fileName, PATH_MAX);
1093 name_len++; /* trailing null */
1094 pSMB->NameLength = cpu_to_le16(name_len);
1095 strncpy(pSMB->fileName, fileName, name_len);
1096 }
1097 if (*pOplock & REQ_OPLOCK)
1098 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1099 else if (*pOplock & REQ_BATCHOPLOCK) {
1100 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1101 }
1102 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1103 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001104 /* set file as system file if special file such
1105 as fifo and server expecting SFU style and
1106 no Unix extensions */
1107 if(create_options & CREATE_OPTION_SPECIAL)
1108 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1109 else
1110 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 /* XP does not handle ATTR_POSIX_SEMANTICS */
1112 /* but it helps speed up case sensitive checks for other
1113 servers such as Samba */
1114 if (tcon->ses->capabilities & CAP_UNIX)
1115 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1116
1117 /* if ((omode & S_IWUGO) == 0)
1118 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1119 /* Above line causes problems due to vfs splitting create into two
1120 pieces - need to set mode after file created not while it is
1121 being created */
1122 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1123 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001124 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001125 /* BB Expirement with various impersonation levels and verify */
1126 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 pSMB->SecurityFlags =
1128 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1129
1130 count += name_len;
1131 pSMB->hdr.smb_buf_length += count;
1132
1133 pSMB->ByteCount = cpu_to_le16(count);
1134 /* long_op set to 1 to allow for oplock break timeouts */
1135 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1136 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001137 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 if (rc) {
1139 cFYI(1, ("Error in Open = %d", rc));
1140 } else {
Steve French09d1db52005-04-28 22:41:08 -07001141 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1143 /* Let caller know file was created so we can set the mode. */
1144 /* Do we care about the CreateAction in any other cases? */
1145 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1146 *pOplock |= CIFS_CREATE_ACTION;
1147 if(pfile_info) {
1148 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1149 36 /* CreationTime to Attributes */);
1150 /* the file_info buf is endian converted by caller */
1151 pfile_info->AllocationSize = pSMBr->AllocationSize;
1152 pfile_info->EndOfFile = pSMBr->EndOfFile;
1153 pfile_info->NumberOfLinks = cpu_to_le32(1);
1154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001156
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 cifs_buf_release(pSMB);
1158 if (rc == -EAGAIN)
1159 goto openRetry;
1160 return rc;
1161}
1162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163int
1164CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001165 const int netfid, const unsigned int count,
1166 const __u64 lseek, unsigned int *nbytes, char **buf,
1167 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168{
1169 int rc = -EACCES;
1170 READ_REQ *pSMB = NULL;
1171 READ_RSP *pSMBr = NULL;
1172 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001173 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001174 int resp_buf_type = 0;
1175 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001178 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1179 wct = 12;
1180 else
1181 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
1183 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001184 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if (rc)
1186 return rc;
1187
1188 /* tcon and ses pointer are checked in smb_init */
1189 if (tcon->ses->server == NULL)
1190 return -ECONNABORTED;
1191
Steve Frenchec637e32005-12-12 20:53:18 -08001192 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 pSMB->Fid = netfid;
1194 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001195 if(wct == 12)
1196 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001197 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1198 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 pSMB->Remaining = 0;
1201 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1202 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001203 if(wct == 12)
1204 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1205 else {
1206 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001207 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001208 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001209 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001210 }
Steve Frenchec637e32005-12-12 20:53:18 -08001211
1212 iov[0].iov_base = (char *)pSMB;
1213 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1214 rc = SendReceive2(xid, tcon->ses, iov,
1215 1 /* num iovecs */,
1216 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001217 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001218 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 if (rc) {
1220 cERROR(1, ("Send error in read = %d", rc));
1221 } else {
1222 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1223 data_length = data_length << 16;
1224 data_length += le16_to_cpu(pSMBr->DataLength);
1225 *nbytes = data_length;
1226
1227 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001228 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 || (data_length > count)) {
1230 cFYI(1,("bad length %d for count %d",data_length,count));
1231 rc = -EIO;
1232 *nbytes = 0;
1233 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001234 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001236/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1237 cERROR(1,("Faulting on read rc = %d",rc));
1238 rc = -EFAULT;
1239 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001241 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
1243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Steve French4b8f9302006-02-26 16:41:18 +00001245/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001246 if(*buf) {
1247 if(resp_buf_type == CIFS_SMALL_BUFFER)
1248 cifs_small_buf_release(iov[0].iov_base);
1249 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1250 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001251 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1252 /* return buffer to caller to free */
1253 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001254 if(resp_buf_type == CIFS_SMALL_BUFFER)
1255 *pbuf_type = CIFS_SMALL_BUFFER;
1256 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1257 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001258 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001259
1260 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 since file handle passed in no longer valid */
1262 return rc;
1263}
1264
Steve Frenchec637e32005-12-12 20:53:18 -08001265
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266int
1267CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1268 const int netfid, const unsigned int count,
1269 const __u64 offset, unsigned int *nbytes, const char *buf,
1270 const char __user * ubuf, const int long_op)
1271{
1272 int rc = -EACCES;
1273 WRITE_REQ *pSMB = NULL;
1274 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001275 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 __u32 bytes_sent;
1277 __u16 byte_count;
1278
1279 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001280 if(tcon->ses == NULL)
1281 return -ECONNABORTED;
1282
1283 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1284 wct = 14;
1285 else
1286 wct = 12;
1287
1288 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 (void **) &pSMBr);
1290 if (rc)
1291 return rc;
1292 /* tcon and ses pointer are checked in smb_init */
1293 if (tcon->ses->server == NULL)
1294 return -ECONNABORTED;
1295
1296 pSMB->AndXCommand = 0xFF; /* none */
1297 pSMB->Fid = netfid;
1298 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001299 if(wct == 14)
1300 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1301 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1302 return -EIO;
1303
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 pSMB->Reserved = 0xFFFFFFFF;
1305 pSMB->WriteMode = 0;
1306 pSMB->Remaining = 0;
1307
1308 /* Can increase buffer size if buffer is big enough in some cases - ie we
1309 can send more if LARGE_WRITE_X capability returned by the server and if
1310 our buffer is big enough or if we convert to iovecs on socket writes
1311 and eliminate the copy to the CIFS buffer */
1312 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1313 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1314 } else {
1315 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1316 & ~0xFF;
1317 }
1318
1319 if (bytes_sent > count)
1320 bytes_sent = count;
1321 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001322 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if(buf)
1324 memcpy(pSMB->Data,buf,bytes_sent);
1325 else if(ubuf) {
1326 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1327 cifs_buf_release(pSMB);
1328 return -EFAULT;
1329 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001330 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 /* No buffer */
1332 cifs_buf_release(pSMB);
1333 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001334 } /* else setting file size with write of zero bytes */
1335 if(wct == 14)
1336 byte_count = bytes_sent + 1; /* pad */
1337 else /* wct == 12 */ {
1338 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1341 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001342 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001343
1344 if(wct == 14)
1345 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001346 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001347 struct smb_com_writex_req * pSMBW =
1348 (struct smb_com_writex_req *)pSMB;
1349 pSMBW->ByteCount = cpu_to_le16(byte_count);
1350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
1352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1353 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001354 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (rc) {
1356 cFYI(1, ("Send error in write = %d", rc));
1357 *nbytes = 0;
1358 } else {
1359 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1360 *nbytes = (*nbytes) << 16;
1361 *nbytes += le16_to_cpu(pSMBr->Count);
1362 }
1363
1364 cifs_buf_release(pSMB);
1365
1366 /* Note: On -EAGAIN error only caller can retry on handle based calls
1367 since file handle passed in no longer valid */
1368
1369 return rc;
1370}
1371
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001372int
1373CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001375 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1376 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377{
1378 int rc = -EACCES;
1379 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001380 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001381 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001382 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Steve Frenchff7feac2005-11-15 16:45:16 -08001384 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1385
Steve French8cc64c62005-10-03 13:49:43 -07001386 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1387 wct = 14;
1388 else
1389 wct = 12;
1390 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 if (rc)
1392 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 /* tcon and ses pointer are checked in smb_init */
1394 if (tcon->ses->server == NULL)
1395 return -ECONNABORTED;
1396
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001397 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 pSMB->Fid = netfid;
1399 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001400 if(wct == 14)
1401 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1402 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1403 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 pSMB->Reserved = 0xFFFFFFFF;
1405 pSMB->WriteMode = 0;
1406 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001407
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 pSMB->DataOffset =
1409 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1410
Steve French3e844692005-10-03 13:37:24 -07001411 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1412 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001413 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001414 if(wct == 14)
1415 pSMB->hdr.smb_buf_length += count+1;
1416 else /* wct == 12 */
1417 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1418 if(wct == 14)
1419 pSMB->ByteCount = cpu_to_le16(count + 1);
1420 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1421 struct smb_com_writex_req * pSMBW =
1422 (struct smb_com_writex_req *)pSMB;
1423 pSMBW->ByteCount = cpu_to_le16(count + 5);
1424 }
Steve French3e844692005-10-03 13:37:24 -07001425 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001426 if(wct == 14)
1427 iov[0].iov_len = smb_hdr_len + 4;
1428 else /* wct == 12 pad bigger by four bytes */
1429 iov[0].iov_len = smb_hdr_len + 8;
1430
Steve French3e844692005-10-03 13:37:24 -07001431
Steve Frenchec637e32005-12-12 20:53:18 -08001432 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001433 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001434 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001436 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001438 } else if(resp_buf_type == 0) {
1439 /* presumably this can not happen, but best to be safe */
1440 rc = -EIO;
1441 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001442 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001443 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001444 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1445 *nbytes = (*nbytes) << 16;
1446 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Steve French4b8f9302006-02-26 16:41:18 +00001449/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001450 if(resp_buf_type == CIFS_SMALL_BUFFER)
1451 cifs_small_buf_release(iov[0].iov_base);
1452 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1453 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
1455 /* Note: On -EAGAIN error only caller can retry on handle based calls
1456 since file handle passed in no longer valid */
1457
1458 return rc;
1459}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001460
1461
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462int
1463CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1464 const __u16 smb_file_id, const __u64 len,
1465 const __u64 offset, const __u32 numUnlock,
1466 const __u32 numLock, const __u8 lockType, const int waitFlag)
1467{
1468 int rc = 0;
1469 LOCK_REQ *pSMB = NULL;
1470 LOCK_RSP *pSMBr = NULL;
1471 int bytes_returned;
1472 int timeout = 0;
1473 __u16 count;
1474
1475 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001476 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1477
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 if (rc)
1479 return rc;
1480
Steve French46810cb2005-04-28 22:41:09 -07001481 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1484 timeout = -1; /* no response expected */
1485 pSMB->Timeout = 0;
1486 } else if (waitFlag == TRUE) {
1487 timeout = 3; /* blocking operation, no timeout */
1488 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1489 } else {
1490 pSMB->Timeout = 0;
1491 }
1492
1493 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1494 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1495 pSMB->LockType = lockType;
1496 pSMB->AndXCommand = 0xFF; /* none */
1497 pSMB->Fid = smb_file_id; /* netfid stays le */
1498
1499 if((numLock != 0) || (numUnlock != 0)) {
1500 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1501 /* BB where to store pid high? */
1502 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1503 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1504 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1505 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1506 count = sizeof(LOCKING_ANDX_RANGE);
1507 } else {
1508 /* oplock break */
1509 count = 0;
1510 }
1511 pSMB->hdr.smb_buf_length += count;
1512 pSMB->ByteCount = cpu_to_le16(count);
1513
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001514 if (waitFlag) {
1515 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1516 (struct smb_hdr *) pSMBr, &bytes_returned);
1517 } else {
1518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001520 }
Steve Frencha4544342005-08-24 13:59:35 -07001521 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 if (rc) {
1523 cFYI(1, ("Send error in Lock = %d", rc));
1524 }
Steve French46810cb2005-04-28 22:41:09 -07001525 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 /* Note: On -EAGAIN error only caller can retry on handle based calls
1528 since file handle passed in no longer valid */
1529 return rc;
1530}
1531
1532int
Steve French08547b02006-02-28 22:39:25 +00001533CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1534 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001535 struct file_lock *pLockData, const __u16 lock_type,
1536 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001537{
1538 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1539 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1540 char *data_offset;
1541 struct cifs_posix_lock *parm_data;
1542 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001543 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001544 int bytes_returned = 0;
1545 __u16 params, param_offset, offset, byte_count, count;
1546
1547 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001548
1549 if(pLockData == NULL)
1550 return EINVAL;
1551
Steve French08547b02006-02-28 22:39:25 +00001552 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1553
1554 if (rc)
1555 return rc;
1556
1557 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1558
1559 params = 6;
1560 pSMB->MaxSetupCount = 0;
1561 pSMB->Reserved = 0;
1562 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001563 pSMB->Reserved2 = 0;
1564 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1565 offset = param_offset + params;
1566
1567 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1568
1569 count = sizeof(struct cifs_posix_lock);
1570 pSMB->MaxParameterCount = cpu_to_le16(2);
1571 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1572 pSMB->SetupCount = 1;
1573 pSMB->Reserved3 = 0;
1574 if(get_flag)
1575 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1576 else
1577 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1578 byte_count = 3 /* pad */ + params + count;
1579 pSMB->DataCount = cpu_to_le16(count);
1580 pSMB->ParameterCount = cpu_to_le16(params);
1581 pSMB->TotalDataCount = pSMB->DataCount;
1582 pSMB->TotalParameterCount = pSMB->ParameterCount;
1583 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1584 parm_data = (struct cifs_posix_lock *)
1585 (((char *) &pSMB->hdr.Protocol) + offset);
1586
1587 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001588 if(waitFlag) {
1589 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001590 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001591 pSMB->Timeout = cpu_to_le32(-1);
1592 } else
1593 pSMB->Timeout = 0;
1594
Steve French08547b02006-02-28 22:39:25 +00001595 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001596 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001597 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001598
1599 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001600 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001601 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1602 pSMB->Reserved4 = 0;
1603 pSMB->hdr.smb_buf_length += byte_count;
1604 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001605 if (waitFlag) {
1606 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1607 (struct smb_hdr *) pSMBr, &bytes_returned);
1608 } else {
1609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001610 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001611 }
1612
Steve French08547b02006-02-28 22:39:25 +00001613 if (rc) {
1614 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001615 } else if (get_flag) {
1616 /* lock structure can be returned on get */
1617 __u16 data_offset;
1618 __u16 data_count;
1619 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001620
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001621 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1622 rc = -EIO; /* bad smb */
1623 goto plk_err_exit;
1624 }
1625 if(pLockData == NULL) {
1626 rc = -EINVAL;
1627 goto plk_err_exit;
1628 }
1629 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1630 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1631 if(data_count < sizeof(struct cifs_posix_lock)) {
1632 rc = -EIO;
1633 goto plk_err_exit;
1634 }
1635 parm_data = (struct cifs_posix_lock *)
1636 ((char *)&pSMBr->hdr.Protocol + data_offset);
1637 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1638 pLockData->fl_type = F_UNLCK;
1639 }
1640
1641plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001642 if (pSMB)
1643 cifs_small_buf_release(pSMB);
1644
1645 /* Note: On -EAGAIN error only caller can retry on handle based calls
1646 since file handle passed in no longer valid */
1647
1648 return rc;
1649}
1650
1651
1652int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1654{
1655 int rc = 0;
1656 CLOSE_REQ *pSMB = NULL;
1657 CLOSE_RSP *pSMBr = NULL;
1658 int bytes_returned;
1659 cFYI(1, ("In CIFSSMBClose"));
1660
1661/* do not retry on dead session on close */
1662 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1663 if(rc == -EAGAIN)
1664 return 0;
1665 if (rc)
1666 return rc;
1667
1668 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1669
1670 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001671 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 pSMB->ByteCount = 0;
1673 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1674 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001675 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 if (rc) {
1677 if(rc!=-EINTR) {
1678 /* EINTR is expected when user ctl-c to kill app */
1679 cERROR(1, ("Send error in Close = %d", rc));
1680 }
1681 }
1682
1683 cifs_small_buf_release(pSMB);
1684
1685 /* Since session is dead, file will be closed on server already */
1686 if(rc == -EAGAIN)
1687 rc = 0;
1688
1689 return rc;
1690}
1691
1692int
1693CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1694 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001695 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696{
1697 int rc = 0;
1698 RENAME_REQ *pSMB = NULL;
1699 RENAME_RSP *pSMBr = NULL;
1700 int bytes_returned;
1701 int name_len, name_len2;
1702 __u16 count;
1703
1704 cFYI(1, ("In CIFSSMBRename"));
1705renameRetry:
1706 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1707 (void **) &pSMBr);
1708 if (rc)
1709 return rc;
1710
1711 pSMB->BufferFormat = 0x04;
1712 pSMB->SearchAttributes =
1713 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1714 ATTR_DIRECTORY);
1715
1716 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1717 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001718 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001719 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 name_len++; /* trailing null */
1721 name_len *= 2;
1722 pSMB->OldFileName[name_len] = 0x04; /* pad */
1723 /* protocol requires ASCII signature byte on Unicode string */
1724 pSMB->OldFileName[name_len + 1] = 0x00;
1725 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001726 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001727 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1729 name_len2 *= 2; /* convert to bytes */
1730 } else { /* BB improve the check for buffer overruns BB */
1731 name_len = strnlen(fromName, PATH_MAX);
1732 name_len++; /* trailing null */
1733 strncpy(pSMB->OldFileName, fromName, name_len);
1734 name_len2 = strnlen(toName, PATH_MAX);
1735 name_len2++; /* trailing null */
1736 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1737 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1738 name_len2++; /* trailing null */
1739 name_len2++; /* signature byte */
1740 }
1741
1742 count = 1 /* 1st signature byte */ + name_len + name_len2;
1743 pSMB->hdr.smb_buf_length += count;
1744 pSMB->ByteCount = cpu_to_le16(count);
1745
1746 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1747 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001748 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 if (rc) {
1750 cFYI(1, ("Send error in rename = %d", rc));
1751 }
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 cifs_buf_release(pSMB);
1754
1755 if (rc == -EAGAIN)
1756 goto renameRetry;
1757
1758 return rc;
1759}
1760
1761int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001762 int netfid, char * target_name,
1763 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764{
1765 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1766 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1767 struct set_file_rename * rename_info;
1768 char *data_offset;
1769 char dummy_string[30];
1770 int rc = 0;
1771 int bytes_returned = 0;
1772 int len_of_str;
1773 __u16 params, param_offset, offset, count, byte_count;
1774
1775 cFYI(1, ("Rename to File by handle"));
1776 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1777 (void **) &pSMBr);
1778 if (rc)
1779 return rc;
1780
1781 params = 6;
1782 pSMB->MaxSetupCount = 0;
1783 pSMB->Reserved = 0;
1784 pSMB->Flags = 0;
1785 pSMB->Timeout = 0;
1786 pSMB->Reserved2 = 0;
1787 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1788 offset = param_offset + params;
1789
1790 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1791 rename_info = (struct set_file_rename *) data_offset;
1792 pSMB->MaxParameterCount = cpu_to_le16(2);
1793 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1794 pSMB->SetupCount = 1;
1795 pSMB->Reserved3 = 0;
1796 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1797 byte_count = 3 /* pad */ + params;
1798 pSMB->ParameterCount = cpu_to_le16(params);
1799 pSMB->TotalParameterCount = pSMB->ParameterCount;
1800 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1801 pSMB->DataOffset = cpu_to_le16(offset);
1802 /* construct random name ".cifs_tmp<inodenum><mid>" */
1803 rename_info->overwrite = cpu_to_le32(1);
1804 rename_info->root_fid = 0;
1805 /* unicode only call */
1806 if(target_name == NULL) {
1807 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001808 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001809 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001811 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001812 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 }
1814 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1815 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1816 byte_count += count;
1817 pSMB->DataCount = cpu_to_le16(count);
1818 pSMB->TotalDataCount = pSMB->DataCount;
1819 pSMB->Fid = netfid;
1820 pSMB->InformationLevel =
1821 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1822 pSMB->Reserved4 = 0;
1823 pSMB->hdr.smb_buf_length += byte_count;
1824 pSMB->ByteCount = cpu_to_le16(byte_count);
1825 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1826 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001827 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if (rc) {
1829 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1830 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001831
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 cifs_buf_release(pSMB);
1833
1834 /* Note: On -EAGAIN error only caller can retry on handle based calls
1835 since file handle passed in no longer valid */
1836
1837 return rc;
1838}
1839
1840int
1841CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1842 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001843 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844{
1845 int rc = 0;
1846 COPY_REQ *pSMB = NULL;
1847 COPY_RSP *pSMBr = NULL;
1848 int bytes_returned;
1849 int name_len, name_len2;
1850 __u16 count;
1851
1852 cFYI(1, ("In CIFSSMBCopy"));
1853copyRetry:
1854 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1855 (void **) &pSMBr);
1856 if (rc)
1857 return rc;
1858
1859 pSMB->BufferFormat = 0x04;
1860 pSMB->Tid2 = target_tid;
1861
1862 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1863
1864 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001865 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001866 fromName, PATH_MAX, nls_codepage,
1867 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 name_len++; /* trailing null */
1869 name_len *= 2;
1870 pSMB->OldFileName[name_len] = 0x04; /* pad */
1871 /* protocol requires ASCII signature byte on Unicode string */
1872 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001873 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001874 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1876 name_len2 *= 2; /* convert to bytes */
1877 } else { /* BB improve the check for buffer overruns BB */
1878 name_len = strnlen(fromName, PATH_MAX);
1879 name_len++; /* trailing null */
1880 strncpy(pSMB->OldFileName, fromName, name_len);
1881 name_len2 = strnlen(toName, PATH_MAX);
1882 name_len2++; /* trailing null */
1883 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1884 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1885 name_len2++; /* trailing null */
1886 name_len2++; /* signature byte */
1887 }
1888
1889 count = 1 /* 1st signature byte */ + name_len + name_len2;
1890 pSMB->hdr.smb_buf_length += count;
1891 pSMB->ByteCount = cpu_to_le16(count);
1892
1893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1895 if (rc) {
1896 cFYI(1, ("Send error in copy = %d with %d files copied",
1897 rc, le16_to_cpu(pSMBr->CopyCount)));
1898 }
1899 if (pSMB)
1900 cifs_buf_release(pSMB);
1901
1902 if (rc == -EAGAIN)
1903 goto copyRetry;
1904
1905 return rc;
1906}
1907
1908int
1909CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1910 const char *fromName, const char *toName,
1911 const struct nls_table *nls_codepage)
1912{
1913 TRANSACTION2_SPI_REQ *pSMB = NULL;
1914 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1915 char *data_offset;
1916 int name_len;
1917 int name_len_target;
1918 int rc = 0;
1919 int bytes_returned = 0;
1920 __u16 params, param_offset, offset, byte_count;
1921
1922 cFYI(1, ("In Symlink Unix style"));
1923createSymLinkRetry:
1924 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1925 (void **) &pSMBr);
1926 if (rc)
1927 return rc;
1928
1929 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1930 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001931 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* find define for this maxpathcomponent */
1933 , nls_codepage);
1934 name_len++; /* trailing null */
1935 name_len *= 2;
1936
1937 } else { /* BB improve the check for buffer overruns BB */
1938 name_len = strnlen(fromName, PATH_MAX);
1939 name_len++; /* trailing null */
1940 strncpy(pSMB->FileName, fromName, name_len);
1941 }
1942 params = 6 + name_len;
1943 pSMB->MaxSetupCount = 0;
1944 pSMB->Reserved = 0;
1945 pSMB->Flags = 0;
1946 pSMB->Timeout = 0;
1947 pSMB->Reserved2 = 0;
1948 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1949 InformationLevel) - 4;
1950 offset = param_offset + params;
1951
1952 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1954 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001955 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 /* find define for this maxpathcomponent */
1957 , nls_codepage);
1958 name_len_target++; /* trailing null */
1959 name_len_target *= 2;
1960 } else { /* BB improve the check for buffer overruns BB */
1961 name_len_target = strnlen(toName, PATH_MAX);
1962 name_len_target++; /* trailing null */
1963 strncpy(data_offset, toName, name_len_target);
1964 }
1965
1966 pSMB->MaxParameterCount = cpu_to_le16(2);
1967 /* BB find exact max on data count below from sess */
1968 pSMB->MaxDataCount = cpu_to_le16(1000);
1969 pSMB->SetupCount = 1;
1970 pSMB->Reserved3 = 0;
1971 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1972 byte_count = 3 /* pad */ + params + name_len_target;
1973 pSMB->DataCount = cpu_to_le16(name_len_target);
1974 pSMB->ParameterCount = cpu_to_le16(params);
1975 pSMB->TotalDataCount = pSMB->DataCount;
1976 pSMB->TotalParameterCount = pSMB->ParameterCount;
1977 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1978 pSMB->DataOffset = cpu_to_le16(offset);
1979 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1980 pSMB->Reserved4 = 0;
1981 pSMB->hdr.smb_buf_length += byte_count;
1982 pSMB->ByteCount = cpu_to_le16(byte_count);
1983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001985 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 if (rc) {
1987 cFYI(1,
1988 ("Send error in SetPathInfo (create symlink) = %d",
1989 rc));
1990 }
1991
1992 if (pSMB)
1993 cifs_buf_release(pSMB);
1994
1995 if (rc == -EAGAIN)
1996 goto createSymLinkRetry;
1997
1998 return rc;
1999}
2000
2001int
2002CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2003 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002004 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005{
2006 TRANSACTION2_SPI_REQ *pSMB = NULL;
2007 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2008 char *data_offset;
2009 int name_len;
2010 int name_len_target;
2011 int rc = 0;
2012 int bytes_returned = 0;
2013 __u16 params, param_offset, offset, byte_count;
2014
2015 cFYI(1, ("In Create Hard link Unix style"));
2016createHardLinkRetry:
2017 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2018 (void **) &pSMBr);
2019 if (rc)
2020 return rc;
2021
2022 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002023 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002024 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 name_len++; /* trailing null */
2026 name_len *= 2;
2027
2028 } else { /* BB improve the check for buffer overruns BB */
2029 name_len = strnlen(toName, PATH_MAX);
2030 name_len++; /* trailing null */
2031 strncpy(pSMB->FileName, toName, name_len);
2032 }
2033 params = 6 + name_len;
2034 pSMB->MaxSetupCount = 0;
2035 pSMB->Reserved = 0;
2036 pSMB->Flags = 0;
2037 pSMB->Timeout = 0;
2038 pSMB->Reserved2 = 0;
2039 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2040 InformationLevel) - 4;
2041 offset = param_offset + params;
2042
2043 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2045 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002046 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002047 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 name_len_target++; /* trailing null */
2049 name_len_target *= 2;
2050 } else { /* BB improve the check for buffer overruns BB */
2051 name_len_target = strnlen(fromName, PATH_MAX);
2052 name_len_target++; /* trailing null */
2053 strncpy(data_offset, fromName, name_len_target);
2054 }
2055
2056 pSMB->MaxParameterCount = cpu_to_le16(2);
2057 /* BB find exact max on data count below from sess*/
2058 pSMB->MaxDataCount = cpu_to_le16(1000);
2059 pSMB->SetupCount = 1;
2060 pSMB->Reserved3 = 0;
2061 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2062 byte_count = 3 /* pad */ + params + name_len_target;
2063 pSMB->ParameterCount = cpu_to_le16(params);
2064 pSMB->TotalParameterCount = pSMB->ParameterCount;
2065 pSMB->DataCount = cpu_to_le16(name_len_target);
2066 pSMB->TotalDataCount = pSMB->DataCount;
2067 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2068 pSMB->DataOffset = cpu_to_le16(offset);
2069 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2070 pSMB->Reserved4 = 0;
2071 pSMB->hdr.smb_buf_length += byte_count;
2072 pSMB->ByteCount = cpu_to_le16(byte_count);
2073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002075 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 if (rc) {
2077 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2078 }
2079
2080 cifs_buf_release(pSMB);
2081 if (rc == -EAGAIN)
2082 goto createHardLinkRetry;
2083
2084 return rc;
2085}
2086
2087int
2088CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2089 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002090 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091{
2092 int rc = 0;
2093 NT_RENAME_REQ *pSMB = NULL;
2094 RENAME_RSP *pSMBr = NULL;
2095 int bytes_returned;
2096 int name_len, name_len2;
2097 __u16 count;
2098
2099 cFYI(1, ("In CIFSCreateHardLink"));
2100winCreateHardLinkRetry:
2101
2102 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2103 (void **) &pSMBr);
2104 if (rc)
2105 return rc;
2106
2107 pSMB->SearchAttributes =
2108 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2109 ATTR_DIRECTORY);
2110 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2111 pSMB->ClusterCount = 0;
2112
2113 pSMB->BufferFormat = 0x04;
2114
2115 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2116 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002117 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002118 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 name_len++; /* trailing null */
2120 name_len *= 2;
2121 pSMB->OldFileName[name_len] = 0; /* pad */
2122 pSMB->OldFileName[name_len + 1] = 0x04;
2123 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002124 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002125 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2127 name_len2 *= 2; /* convert to bytes */
2128 } else { /* BB improve the check for buffer overruns BB */
2129 name_len = strnlen(fromName, PATH_MAX);
2130 name_len++; /* trailing null */
2131 strncpy(pSMB->OldFileName, fromName, name_len);
2132 name_len2 = strnlen(toName, PATH_MAX);
2133 name_len2++; /* trailing null */
2134 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2135 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2136 name_len2++; /* trailing null */
2137 name_len2++; /* signature byte */
2138 }
2139
2140 count = 1 /* string type byte */ + name_len + name_len2;
2141 pSMB->hdr.smb_buf_length += count;
2142 pSMB->ByteCount = cpu_to_le16(count);
2143
2144 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2145 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002146 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 if (rc) {
2148 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2149 }
2150 cifs_buf_release(pSMB);
2151 if (rc == -EAGAIN)
2152 goto winCreateHardLinkRetry;
2153
2154 return rc;
2155}
2156
2157int
2158CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2159 const unsigned char *searchName,
2160 char *symlinkinfo, const int buflen,
2161 const struct nls_table *nls_codepage)
2162{
2163/* SMB_QUERY_FILE_UNIX_LINK */
2164 TRANSACTION2_QPI_REQ *pSMB = NULL;
2165 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2166 int rc = 0;
2167 int bytes_returned;
2168 int name_len;
2169 __u16 params, byte_count;
2170
2171 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2172
2173querySymLinkRetry:
2174 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2175 (void **) &pSMBr);
2176 if (rc)
2177 return rc;
2178
2179 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2180 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002181 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 /* find define for this maxpathcomponent */
2183 , nls_codepage);
2184 name_len++; /* trailing null */
2185 name_len *= 2;
2186 } else { /* BB improve the check for buffer overruns BB */
2187 name_len = strnlen(searchName, PATH_MAX);
2188 name_len++; /* trailing null */
2189 strncpy(pSMB->FileName, searchName, name_len);
2190 }
2191
2192 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2193 pSMB->TotalDataCount = 0;
2194 pSMB->MaxParameterCount = cpu_to_le16(2);
2195 /* BB find exact max data count below from sess structure BB */
2196 pSMB->MaxDataCount = cpu_to_le16(4000);
2197 pSMB->MaxSetupCount = 0;
2198 pSMB->Reserved = 0;
2199 pSMB->Flags = 0;
2200 pSMB->Timeout = 0;
2201 pSMB->Reserved2 = 0;
2202 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2203 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2204 pSMB->DataCount = 0;
2205 pSMB->DataOffset = 0;
2206 pSMB->SetupCount = 1;
2207 pSMB->Reserved3 = 0;
2208 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2209 byte_count = params + 1 /* pad */ ;
2210 pSMB->TotalParameterCount = cpu_to_le16(params);
2211 pSMB->ParameterCount = pSMB->TotalParameterCount;
2212 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2213 pSMB->Reserved4 = 0;
2214 pSMB->hdr.smb_buf_length += byte_count;
2215 pSMB->ByteCount = cpu_to_le16(byte_count);
2216
2217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2219 if (rc) {
2220 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2221 } else {
2222 /* decode response */
2223
2224 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2225 if (rc || (pSMBr->ByteCount < 2))
2226 /* BB also check enough total bytes returned */
2227 rc = -EIO; /* bad smb */
2228 else {
2229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2230 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2231
2232 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2233 name_len = UniStrnlen((wchar_t *) ((char *)
2234 &pSMBr->hdr.Protocol +data_offset),
2235 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002236 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002238 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 data_offset),
2240 name_len, nls_codepage);
2241 } else {
2242 strncpy(symlinkinfo,
2243 (char *) &pSMBr->hdr.Protocol +
2244 data_offset,
2245 min_t(const int, buflen, count));
2246 }
2247 symlinkinfo[buflen] = 0;
2248 /* just in case so calling code does not go off the end of buffer */
2249 }
2250 }
2251 cifs_buf_release(pSMB);
2252 if (rc == -EAGAIN)
2253 goto querySymLinkRetry;
2254 return rc;
2255}
2256
Steve French0a4b92c2006-01-12 15:44:21 -08002257/* Initialize NT TRANSACT SMB into small smb request buffer.
2258 This assumes that all NT TRANSACTS that we init here have
2259 total parm and data under about 400 bytes (to fit in small cifs
2260 buffer size), which is the case so far, it easily fits. NB:
2261 Setup words themselves and ByteCount
2262 MaxSetupCount (size of returned setup area) and
2263 MaxParameterCount (returned parms size) must be set by caller */
2264static int
2265smb_init_ntransact(const __u16 sub_command, const int setup_count,
2266 const int parm_len, struct cifsTconInfo *tcon,
2267 void ** ret_buf)
2268{
2269 int rc;
2270 __u32 temp_offset;
2271 struct smb_com_ntransact_req * pSMB;
2272
2273 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2274 (void **)&pSMB);
2275 if (rc)
2276 return rc;
2277 *ret_buf = (void *)pSMB;
2278 pSMB->Reserved = 0;
2279 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2280 pSMB->TotalDataCount = 0;
2281 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2282 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2283 pSMB->ParameterCount = pSMB->TotalParameterCount;
2284 pSMB->DataCount = pSMB->TotalDataCount;
2285 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2286 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2287 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2288 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2289 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2290 pSMB->SubCommand = cpu_to_le16(sub_command);
2291 return 0;
2292}
2293
2294static int
2295validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2296 int * pdatalen, int * pparmlen)
2297{
2298 char * end_of_smb;
2299 __u32 data_count, data_offset, parm_count, parm_offset;
2300 struct smb_com_ntransact_rsp * pSMBr;
2301
2302 if(buf == NULL)
2303 return -EINVAL;
2304
2305 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2306
2307 /* ByteCount was converted from little endian in SendReceive */
2308 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2309 (char *)&pSMBr->ByteCount;
2310
2311
2312 data_offset = le32_to_cpu(pSMBr->DataOffset);
2313 data_count = le32_to_cpu(pSMBr->DataCount);
2314 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2315 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2316
2317 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2318 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2319
2320 /* should we also check that parm and data areas do not overlap? */
2321 if(*ppparm > end_of_smb) {
2322 cFYI(1,("parms start after end of smb"));
2323 return -EINVAL;
2324 } else if(parm_count + *ppparm > end_of_smb) {
2325 cFYI(1,("parm end after end of smb"));
2326 return -EINVAL;
2327 } else if(*ppdata > end_of_smb) {
2328 cFYI(1,("data starts after end of smb"));
2329 return -EINVAL;
2330 } else if(data_count + *ppdata > end_of_smb) {
2331 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2332 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2333 return -EINVAL;
2334 } else if(parm_count + data_count > pSMBr->ByteCount) {
2335 cFYI(1,("parm count and data count larger than SMB"));
2336 return -EINVAL;
2337 }
2338 return 0;
2339}
2340
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341int
2342CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2343 const unsigned char *searchName,
2344 char *symlinkinfo, const int buflen,__u16 fid,
2345 const struct nls_table *nls_codepage)
2346{
2347 int rc = 0;
2348 int bytes_returned;
2349 int name_len;
2350 struct smb_com_transaction_ioctl_req * pSMB;
2351 struct smb_com_transaction_ioctl_rsp * pSMBr;
2352
2353 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2354 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2355 (void **) &pSMBr);
2356 if (rc)
2357 return rc;
2358
2359 pSMB->TotalParameterCount = 0 ;
2360 pSMB->TotalDataCount = 0;
2361 pSMB->MaxParameterCount = cpu_to_le32(2);
2362 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002363 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2364 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 pSMB->MaxSetupCount = 4;
2366 pSMB->Reserved = 0;
2367 pSMB->ParameterOffset = 0;
2368 pSMB->DataCount = 0;
2369 pSMB->DataOffset = 0;
2370 pSMB->SetupCount = 4;
2371 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2372 pSMB->ParameterCount = pSMB->TotalParameterCount;
2373 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2374 pSMB->IsFsctl = 1; /* FSCTL */
2375 pSMB->IsRootFlag = 0;
2376 pSMB->Fid = fid; /* file handle always le */
2377 pSMB->ByteCount = 0;
2378
2379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2380 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2381 if (rc) {
2382 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2383 } else { /* decode response */
2384 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2385 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2386 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2387 /* BB also check enough total bytes returned */
2388 rc = -EIO; /* bad smb */
2389 else {
2390 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002391 char * end_of_smb = 2 /* sizeof byte count */ +
2392 pSMBr->ByteCount +
2393 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
2395 struct reparse_data * reparse_buf = (struct reparse_data *)
2396 ((char *)&pSMBr->hdr.Protocol + data_offset);
2397 if((char*)reparse_buf >= end_of_smb) {
2398 rc = -EIO;
2399 goto qreparse_out;
2400 }
2401 if((reparse_buf->LinkNamesBuf +
2402 reparse_buf->TargetNameOffset +
2403 reparse_buf->TargetNameLen) >
2404 end_of_smb) {
2405 cFYI(1,("reparse buf extended beyond SMB"));
2406 rc = -EIO;
2407 goto qreparse_out;
2408 }
2409
2410 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2411 name_len = UniStrnlen((wchar_t *)
2412 (reparse_buf->LinkNamesBuf +
2413 reparse_buf->TargetNameOffset),
2414 min(buflen/2, reparse_buf->TargetNameLen / 2));
2415 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002416 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 reparse_buf->TargetNameOffset),
2418 name_len, nls_codepage);
2419 } else { /* ASCII names */
2420 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2421 reparse_buf->TargetNameOffset,
2422 min_t(const int, buflen, reparse_buf->TargetNameLen));
2423 }
2424 } else {
2425 rc = -EIO;
2426 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2427 }
2428 symlinkinfo[buflen] = 0; /* just in case so the caller
2429 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002430 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 }
2432 }
2433qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002434 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
2436 /* Note: On -EAGAIN error only caller can retry on handle based calls
2437 since file handle passed in no longer valid */
2438
2439 return rc;
2440}
2441
2442#ifdef CONFIG_CIFS_POSIX
2443
2444/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2445static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2446{
2447 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002448 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2449 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2450 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2452
2453 return;
2454}
2455
2456/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002457static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2458 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459{
2460 int size = 0;
2461 int i;
2462 __u16 count;
2463 struct cifs_posix_ace * pACE;
2464 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2465 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2466
2467 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2468 return -EOPNOTSUPP;
2469
2470 if(acl_type & ACL_TYPE_ACCESS) {
2471 count = le16_to_cpu(cifs_acl->access_entry_count);
2472 pACE = &cifs_acl->ace_array[0];
2473 size = sizeof(struct cifs_posix_acl);
2474 size += sizeof(struct cifs_posix_ace) * count;
2475 /* check if we would go beyond end of SMB */
2476 if(size_of_data_area < size) {
2477 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2478 return -EINVAL;
2479 }
2480 } else if(acl_type & ACL_TYPE_DEFAULT) {
2481 count = le16_to_cpu(cifs_acl->access_entry_count);
2482 size = sizeof(struct cifs_posix_acl);
2483 size += sizeof(struct cifs_posix_ace) * count;
2484/* skip past access ACEs to get to default ACEs */
2485 pACE = &cifs_acl->ace_array[count];
2486 count = le16_to_cpu(cifs_acl->default_entry_count);
2487 size += sizeof(struct cifs_posix_ace) * count;
2488 /* check if we would go beyond end of SMB */
2489 if(size_of_data_area < size)
2490 return -EINVAL;
2491 } else {
2492 /* illegal type */
2493 return -EINVAL;
2494 }
2495
2496 size = posix_acl_xattr_size(count);
2497 if((buflen == 0) || (local_acl == NULL)) {
2498 /* used to query ACL EA size */
2499 } else if(size > buflen) {
2500 return -ERANGE;
2501 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002502 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 for(i = 0;i < count ;i++) {
2504 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2505 pACE ++;
2506 }
2507 }
2508 return size;
2509}
2510
2511static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2512 const posix_acl_xattr_entry * local_ace)
2513{
2514 __u16 rc = 0; /* 0 = ACL converted ok */
2515
Steve Frenchff7feac2005-11-15 16:45:16 -08002516 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2517 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002519 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 /* Probably no need to le convert -1 on any arch but can not hurt */
2521 cifs_ace->cifs_uid = cpu_to_le64(-1);
2522 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002523 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2525 return rc;
2526}
2527
2528/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2529static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2530 const int acl_type)
2531{
2532 __u16 rc = 0;
2533 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2534 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2535 int count;
2536 int i;
2537
2538 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2539 return 0;
2540
2541 count = posix_acl_xattr_count((size_t)buflen);
2542 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002543 count, buflen, le32_to_cpu(local_acl->a_version)));
2544 if(le32_to_cpu(local_acl->a_version) != 2) {
2545 cFYI(1,("unknown POSIX ACL version %d",
2546 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 return 0;
2548 }
2549 cifs_acl->version = cpu_to_le16(1);
2550 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002551 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002553 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 else {
2555 cFYI(1,("unknown ACL type %d",acl_type));
2556 return 0;
2557 }
2558 for(i=0;i<count;i++) {
2559 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2560 &local_acl->a_entries[i]);
2561 if(rc != 0) {
2562 /* ACE not converted */
2563 break;
2564 }
2565 }
2566 if(rc == 0) {
2567 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2568 rc += sizeof(struct cifs_posix_acl);
2569 /* BB add check to make sure ACL does not overflow SMB */
2570 }
2571 return rc;
2572}
2573
2574int
2575CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2576 const unsigned char *searchName,
2577 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002578 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579{
2580/* SMB_QUERY_POSIX_ACL */
2581 TRANSACTION2_QPI_REQ *pSMB = NULL;
2582 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2583 int rc = 0;
2584 int bytes_returned;
2585 int name_len;
2586 __u16 params, byte_count;
2587
2588 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2589
2590queryAclRetry:
2591 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2592 (void **) &pSMBr);
2593 if (rc)
2594 return rc;
2595
2596 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2597 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002598 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002599 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 name_len++; /* trailing null */
2601 name_len *= 2;
2602 pSMB->FileName[name_len] = 0;
2603 pSMB->FileName[name_len+1] = 0;
2604 } else { /* BB improve the check for buffer overruns BB */
2605 name_len = strnlen(searchName, PATH_MAX);
2606 name_len++; /* trailing null */
2607 strncpy(pSMB->FileName, searchName, name_len);
2608 }
2609
2610 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2611 pSMB->TotalDataCount = 0;
2612 pSMB->MaxParameterCount = cpu_to_le16(2);
2613 /* BB find exact max data count below from sess structure BB */
2614 pSMB->MaxDataCount = cpu_to_le16(4000);
2615 pSMB->MaxSetupCount = 0;
2616 pSMB->Reserved = 0;
2617 pSMB->Flags = 0;
2618 pSMB->Timeout = 0;
2619 pSMB->Reserved2 = 0;
2620 pSMB->ParameterOffset = cpu_to_le16(
2621 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2622 pSMB->DataCount = 0;
2623 pSMB->DataOffset = 0;
2624 pSMB->SetupCount = 1;
2625 pSMB->Reserved3 = 0;
2626 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2627 byte_count = params + 1 /* pad */ ;
2628 pSMB->TotalParameterCount = cpu_to_le16(params);
2629 pSMB->ParameterCount = pSMB->TotalParameterCount;
2630 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2631 pSMB->Reserved4 = 0;
2632 pSMB->hdr.smb_buf_length += byte_count;
2633 pSMB->ByteCount = cpu_to_le16(byte_count);
2634
2635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002637 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 if (rc) {
2639 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2640 } else {
2641 /* decode response */
2642
2643 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2644 if (rc || (pSMBr->ByteCount < 2))
2645 /* BB also check enough total bytes returned */
2646 rc = -EIO; /* bad smb */
2647 else {
2648 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2649 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2650 rc = cifs_copy_posix_acl(acl_inf,
2651 (char *)&pSMBr->hdr.Protocol+data_offset,
2652 buflen,acl_type,count);
2653 }
2654 }
2655 cifs_buf_release(pSMB);
2656 if (rc == -EAGAIN)
2657 goto queryAclRetry;
2658 return rc;
2659}
2660
2661int
2662CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2663 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002664 const char *local_acl, const int buflen,
2665 const int acl_type,
2666 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667{
2668 struct smb_com_transaction2_spi_req *pSMB = NULL;
2669 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2670 char *parm_data;
2671 int name_len;
2672 int rc = 0;
2673 int bytes_returned = 0;
2674 __u16 params, byte_count, data_count, param_offset, offset;
2675
2676 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2677setAclRetry:
2678 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2679 (void **) &pSMBr);
2680 if (rc)
2681 return rc;
2682 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2683 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002684 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002685 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 name_len++; /* trailing null */
2687 name_len *= 2;
2688 } else { /* BB improve the check for buffer overruns BB */
2689 name_len = strnlen(fileName, PATH_MAX);
2690 name_len++; /* trailing null */
2691 strncpy(pSMB->FileName, fileName, name_len);
2692 }
2693 params = 6 + name_len;
2694 pSMB->MaxParameterCount = cpu_to_le16(2);
2695 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2696 pSMB->MaxSetupCount = 0;
2697 pSMB->Reserved = 0;
2698 pSMB->Flags = 0;
2699 pSMB->Timeout = 0;
2700 pSMB->Reserved2 = 0;
2701 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2702 InformationLevel) - 4;
2703 offset = param_offset + params;
2704 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2705 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2706
2707 /* convert to on the wire format for POSIX ACL */
2708 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2709
2710 if(data_count == 0) {
2711 rc = -EOPNOTSUPP;
2712 goto setACLerrorExit;
2713 }
2714 pSMB->DataOffset = cpu_to_le16(offset);
2715 pSMB->SetupCount = 1;
2716 pSMB->Reserved3 = 0;
2717 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2718 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2719 byte_count = 3 /* pad */ + params + data_count;
2720 pSMB->DataCount = cpu_to_le16(data_count);
2721 pSMB->TotalDataCount = pSMB->DataCount;
2722 pSMB->ParameterCount = cpu_to_le16(params);
2723 pSMB->TotalParameterCount = pSMB->ParameterCount;
2724 pSMB->Reserved4 = 0;
2725 pSMB->hdr.smb_buf_length += byte_count;
2726 pSMB->ByteCount = cpu_to_le16(byte_count);
2727 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2728 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2729 if (rc) {
2730 cFYI(1, ("Set POSIX ACL returned %d", rc));
2731 }
2732
2733setACLerrorExit:
2734 cifs_buf_release(pSMB);
2735 if (rc == -EAGAIN)
2736 goto setAclRetry;
2737 return rc;
2738}
2739
Steve Frenchf654bac2005-04-28 22:41:04 -07002740/* BB fix tabs in this function FIXME BB */
2741int
2742CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2743 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2744{
2745 int rc = 0;
2746 struct smb_t2_qfi_req *pSMB = NULL;
2747 struct smb_t2_qfi_rsp *pSMBr = NULL;
2748 int bytes_returned;
2749 __u16 params, byte_count;
2750
2751 cFYI(1,("In GetExtAttr"));
2752 if(tcon == NULL)
2753 return -ENODEV;
2754
2755GetExtAttrRetry:
2756 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2757 (void **) &pSMBr);
2758 if (rc)
2759 return rc;
2760
Steve Frenchc67593a2005-04-28 22:41:04 -07002761 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002762 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002763 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002764 /* BB find exact max data count below from sess structure BB */
2765 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2766 pSMB->t2.MaxSetupCount = 0;
2767 pSMB->t2.Reserved = 0;
2768 pSMB->t2.Flags = 0;
2769 pSMB->t2.Timeout = 0;
2770 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002771 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2772 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002773 pSMB->t2.DataCount = 0;
2774 pSMB->t2.DataOffset = 0;
2775 pSMB->t2.SetupCount = 1;
2776 pSMB->t2.Reserved3 = 0;
2777 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002778 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002779 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2780 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2781 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002782 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002783 pSMB->Fid = netfid;
2784 pSMB->hdr.smb_buf_length += byte_count;
2785 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2786
2787 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2788 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2789 if (rc) {
2790 cFYI(1, ("error %d in GetExtAttr", rc));
2791 } else {
2792 /* decode response */
2793 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2794 if (rc || (pSMBr->ByteCount < 2))
2795 /* BB also check enough total bytes returned */
2796 /* If rc should we check for EOPNOSUPP and
2797 disable the srvino flag? or in caller? */
2798 rc = -EIO; /* bad smb */
2799 else {
2800 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2801 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2802 struct file_chattr_info * pfinfo;
2803 /* BB Do we need a cast or hash here ? */
2804 if(count != 16) {
2805 cFYI(1, ("Illegal size ret in GetExtAttr"));
2806 rc = -EIO;
2807 goto GetExtAttrOut;
2808 }
2809 pfinfo = (struct file_chattr_info *)
2810 (data_offset + (char *) &pSMBr->hdr.Protocol);
2811 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2812 *pMask = le64_to_cpu(pfinfo->mask);
2813 }
2814 }
2815GetExtAttrOut:
2816 cifs_buf_release(pSMB);
2817 if (rc == -EAGAIN)
2818 goto GetExtAttrRetry;
2819 return rc;
2820}
2821
2822
2823#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824
Steve Frencheeac8042006-01-13 21:34:58 -08002825
2826/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002827static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00002828 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002829/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002830static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00002831 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002832
Steve French0a4b92c2006-01-12 15:44:21 -08002833/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002834static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002835{
Steve French0a4b92c2006-01-12 15:44:21 -08002836 return 0;
2837}
2838
2839/* Get Security Descriptor (by handle) from remote server for a file or dir */
2840int
2841CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2842 /* BB fix up return info */ char *acl_inf, const int buflen,
2843 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2844{
2845 int rc = 0;
2846 int buf_type = 0;
2847 QUERY_SEC_DESC_REQ * pSMB;
2848 struct kvec iov[1];
2849
2850 cFYI(1, ("GetCifsACL"));
2851
2852 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2853 8 /* parm len */, tcon, (void **) &pSMB);
2854 if (rc)
2855 return rc;
2856
2857 pSMB->MaxParameterCount = cpu_to_le32(4);
2858 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2859 pSMB->MaxSetupCount = 0;
2860 pSMB->Fid = fid; /* file handle always le */
2861 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2862 CIFS_ACL_DACL);
2863 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2864 pSMB->hdr.smb_buf_length += 11;
2865 iov[0].iov_base = (char *)pSMB;
2866 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2867
2868 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2869 cifs_stats_inc(&tcon->num_acl_get);
2870 if (rc) {
2871 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2872 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002873 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002874 __le32 * parm;
2875 int parm_len;
2876 int data_len;
2877 int acl_len;
2878 struct smb_com_ntransact_rsp * pSMBr;
2879
2880/* validate_nttransact */
2881 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2882 (char **)&psec_desc,
2883 &parm_len, &data_len);
2884
2885 if(rc)
2886 goto qsec_out;
2887 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2888
2889 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2890
2891 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2892 rc = -EIO; /* bad smb */
2893 goto qsec_out;
2894 }
2895
2896/* BB check that data area is minimum length and as big as acl_len */
2897
2898 acl_len = le32_to_cpu(*(__le32 *)parm);
2899 /* BB check if(acl_len > bufsize) */
2900
2901 parse_sec_desc(psec_desc, acl_len);
2902 }
2903qsec_out:
2904 if(buf_type == CIFS_SMALL_BUFFER)
2905 cifs_small_buf_release(iov[0].iov_base);
2906 else if(buf_type == CIFS_LARGE_BUFFER)
2907 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002908/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002909 return rc;
2910}
2911
Steve French6b8edfe2005-08-23 20:26:03 -07002912/* Legacy Query Path Information call for lookup to old servers such
2913 as Win9x/WinME */
2914int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2915 const unsigned char *searchName,
2916 FILE_ALL_INFO * pFinfo,
2917 const struct nls_table *nls_codepage, int remap)
2918{
2919 QUERY_INFORMATION_REQ * pSMB;
2920 QUERY_INFORMATION_RSP * pSMBr;
2921 int rc = 0;
2922 int bytes_returned;
2923 int name_len;
2924
2925 cFYI(1, ("In SMBQPath path %s", searchName));
2926QInfRetry:
2927 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2928 (void **) &pSMBr);
2929 if (rc)
2930 return rc;
2931
2932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2933 name_len =
2934 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2935 PATH_MAX, nls_codepage, remap);
2936 name_len++; /* trailing null */
2937 name_len *= 2;
2938 } else {
2939 name_len = strnlen(searchName, PATH_MAX);
2940 name_len++; /* trailing null */
2941 strncpy(pSMB->FileName, searchName, name_len);
2942 }
2943 pSMB->BufferFormat = 0x04;
2944 name_len++; /* account for buffer type byte */
2945 pSMB->hdr.smb_buf_length += (__u16) name_len;
2946 pSMB->ByteCount = cpu_to_le16(name_len);
2947
2948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2950 if (rc) {
2951 cFYI(1, ("Send error in QueryInfo = %d", rc));
2952 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00002953 struct timespec ts;
2954 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2955 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07002956 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00002957 ts.tv_nsec = 0;
2958 ts.tv_sec = time;
2959 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01002960 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00002961 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2962 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07002963 pFinfo->AllocationSize =
2964 cpu_to_le64(le32_to_cpu(pSMBr->size));
2965 pFinfo->EndOfFile = pFinfo->AllocationSize;
2966 pFinfo->Attributes =
2967 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002968 } else
2969 rc = -EIO; /* bad buffer passed in */
2970
2971 cifs_buf_release(pSMB);
2972
2973 if (rc == -EAGAIN)
2974 goto QInfRetry;
2975
2976 return rc;
2977}
2978
2979
2980
2981
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982int
2983CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2984 const unsigned char *searchName,
2985 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00002986 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07002987 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988{
2989/* level 263 SMB_QUERY_FILE_ALL_INFO */
2990 TRANSACTION2_QPI_REQ *pSMB = NULL;
2991 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2992 int rc = 0;
2993 int bytes_returned;
2994 int name_len;
2995 __u16 params, byte_count;
2996
2997/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2998QPathInfoRetry:
2999 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3000 (void **) &pSMBr);
3001 if (rc)
3002 return rc;
3003
3004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3005 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003006 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003007 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 name_len++; /* trailing null */
3009 name_len *= 2;
3010 } else { /* BB improve the check for buffer overruns BB */
3011 name_len = strnlen(searchName, PATH_MAX);
3012 name_len++; /* trailing null */
3013 strncpy(pSMB->FileName, searchName, name_len);
3014 }
3015
3016 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3017 pSMB->TotalDataCount = 0;
3018 pSMB->MaxParameterCount = cpu_to_le16(2);
3019 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3020 pSMB->MaxSetupCount = 0;
3021 pSMB->Reserved = 0;
3022 pSMB->Flags = 0;
3023 pSMB->Timeout = 0;
3024 pSMB->Reserved2 = 0;
3025 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3026 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3027 pSMB->DataCount = 0;
3028 pSMB->DataOffset = 0;
3029 pSMB->SetupCount = 1;
3030 pSMB->Reserved3 = 0;
3031 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3032 byte_count = params + 1 /* pad */ ;
3033 pSMB->TotalParameterCount = cpu_to_le16(params);
3034 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003035 if(legacy)
3036 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3037 else
3038 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 pSMB->Reserved4 = 0;
3040 pSMB->hdr.smb_buf_length += byte_count;
3041 pSMB->ByteCount = cpu_to_le16(byte_count);
3042
3043 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3045 if (rc) {
3046 cFYI(1, ("Send error in QPathInfo = %d", rc));
3047 } else { /* decode response */
3048 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3049
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003050 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3051 rc = -EIO;
3052 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 rc = -EIO; /* bad smb */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003054 else if(legacy && (pSMBr->ByteCount < 24))
3055 rc = -EIO; /* 24 or 26 expected but we do not read last field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 else if (pFindData){
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003057 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003059 if(legacy) /* we do not read the last field, EAsize, fortunately
3060 since it varies by subdialect and on Set vs. Get, is
3061 two bytes or 4 bytes depending but we don't care here */
3062 size = sizeof(FILE_INFO_STANDARD);
3063 else
3064 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 memcpy((char *) pFindData,
3066 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003067 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 } else
3069 rc = -ENOMEM;
3070 }
3071 cifs_buf_release(pSMB);
3072 if (rc == -EAGAIN)
3073 goto QPathInfoRetry;
3074
3075 return rc;
3076}
3077
3078int
3079CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3080 const unsigned char *searchName,
3081 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003082 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083{
3084/* SMB_QUERY_FILE_UNIX_BASIC */
3085 TRANSACTION2_QPI_REQ *pSMB = NULL;
3086 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3087 int rc = 0;
3088 int bytes_returned = 0;
3089 int name_len;
3090 __u16 params, byte_count;
3091
3092 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3093UnixQPathInfoRetry:
3094 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3095 (void **) &pSMBr);
3096 if (rc)
3097 return rc;
3098
3099 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3100 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003101 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003102 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 name_len++; /* trailing null */
3104 name_len *= 2;
3105 } else { /* BB improve the check for buffer overruns BB */
3106 name_len = strnlen(searchName, PATH_MAX);
3107 name_len++; /* trailing null */
3108 strncpy(pSMB->FileName, searchName, name_len);
3109 }
3110
3111 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3112 pSMB->TotalDataCount = 0;
3113 pSMB->MaxParameterCount = cpu_to_le16(2);
3114 /* BB find exact max SMB PDU from sess structure BB */
3115 pSMB->MaxDataCount = cpu_to_le16(4000);
3116 pSMB->MaxSetupCount = 0;
3117 pSMB->Reserved = 0;
3118 pSMB->Flags = 0;
3119 pSMB->Timeout = 0;
3120 pSMB->Reserved2 = 0;
3121 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3122 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3123 pSMB->DataCount = 0;
3124 pSMB->DataOffset = 0;
3125 pSMB->SetupCount = 1;
3126 pSMB->Reserved3 = 0;
3127 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3128 byte_count = params + 1 /* pad */ ;
3129 pSMB->TotalParameterCount = cpu_to_le16(params);
3130 pSMB->ParameterCount = pSMB->TotalParameterCount;
3131 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3132 pSMB->Reserved4 = 0;
3133 pSMB->hdr.smb_buf_length += byte_count;
3134 pSMB->ByteCount = cpu_to_le16(byte_count);
3135
3136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3138 if (rc) {
3139 cFYI(1, ("Send error in QPathInfo = %d", rc));
3140 } else { /* decode response */
3141 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3142
3143 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3144 rc = -EIO; /* bad smb */
3145 } else {
3146 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3147 memcpy((char *) pFindData,
3148 (char *) &pSMBr->hdr.Protocol +
3149 data_offset,
3150 sizeof (FILE_UNIX_BASIC_INFO));
3151 }
3152 }
3153 cifs_buf_release(pSMB);
3154 if (rc == -EAGAIN)
3155 goto UnixQPathInfoRetry;
3156
3157 return rc;
3158}
3159
3160#if 0 /* function unused at present */
3161int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3162 const char *searchName, FILE_ALL_INFO * findData,
3163 const struct nls_table *nls_codepage)
3164{
3165/* level 257 SMB_ */
3166 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3167 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3168 int rc = 0;
3169 int bytes_returned;
3170 int name_len;
3171 __u16 params, byte_count;
3172
3173 cFYI(1, ("In FindUnique"));
3174findUniqueRetry:
3175 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3176 (void **) &pSMBr);
3177 if (rc)
3178 return rc;
3179
3180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3181 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003182 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 /* find define for this maxpathcomponent */
3184 , nls_codepage);
3185 name_len++; /* trailing null */
3186 name_len *= 2;
3187 } else { /* BB improve the check for buffer overruns BB */
3188 name_len = strnlen(searchName, PATH_MAX);
3189 name_len++; /* trailing null */
3190 strncpy(pSMB->FileName, searchName, name_len);
3191 }
3192
3193 params = 12 + name_len /* includes null */ ;
3194 pSMB->TotalDataCount = 0; /* no EAs */
3195 pSMB->MaxParameterCount = cpu_to_le16(2);
3196 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3197 pSMB->MaxSetupCount = 0;
3198 pSMB->Reserved = 0;
3199 pSMB->Flags = 0;
3200 pSMB->Timeout = 0;
3201 pSMB->Reserved2 = 0;
3202 pSMB->ParameterOffset = cpu_to_le16(
3203 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3204 pSMB->DataCount = 0;
3205 pSMB->DataOffset = 0;
3206 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3207 pSMB->Reserved3 = 0;
3208 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3209 byte_count = params + 1 /* pad */ ;
3210 pSMB->TotalParameterCount = cpu_to_le16(params);
3211 pSMB->ParameterCount = pSMB->TotalParameterCount;
3212 pSMB->SearchAttributes =
3213 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3214 ATTR_DIRECTORY);
3215 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3216 pSMB->SearchFlags = cpu_to_le16(1);
3217 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3218 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3219 pSMB->hdr.smb_buf_length += byte_count;
3220 pSMB->ByteCount = cpu_to_le16(byte_count);
3221
3222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3224
3225 if (rc) {
3226 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3227 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003228 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 /* BB fill in */
3230 }
3231
3232 cifs_buf_release(pSMB);
3233 if (rc == -EAGAIN)
3234 goto findUniqueRetry;
3235
3236 return rc;
3237}
3238#endif /* end unused (temporarily) function */
3239
3240/* xid, tcon, searchName and codepage are input parms, rest are returned */
3241int
3242CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3243 const char *searchName,
3244 const struct nls_table *nls_codepage,
3245 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003246 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247{
3248/* level 257 SMB_ */
3249 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3250 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3251 T2_FFIRST_RSP_PARMS * parms;
3252 int rc = 0;
3253 int bytes_returned = 0;
3254 int name_len;
3255 __u16 params, byte_count;
3256
Steve French737b7582005-04-28 22:41:06 -07003257 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
3259findFirstRetry:
3260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3261 (void **) &pSMBr);
3262 if (rc)
3263 return rc;
3264
3265 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3266 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003267 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003268 PATH_MAX, nls_codepage, remap);
3269 /* We can not add the asterik earlier in case
3270 it got remapped to 0xF03A as if it were part of the
3271 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003273 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003274 pSMB->FileName[name_len+1] = 0;
3275 pSMB->FileName[name_len+2] = '*';
3276 pSMB->FileName[name_len+3] = 0;
3277 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3279 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003280 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 } else { /* BB add check for overrun of SMB buf BB */
3282 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283/* BB fix here and in unicode clause above ie
3284 if(name_len > buffersize-header)
3285 free buffer exit; BB */
3286 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003287 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003288 pSMB->FileName[name_len+1] = '*';
3289 pSMB->FileName[name_len+2] = 0;
3290 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 }
3292
3293 params = 12 + name_len /* includes null */ ;
3294 pSMB->TotalDataCount = 0; /* no EAs */
3295 pSMB->MaxParameterCount = cpu_to_le16(10);
3296 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3297 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3298 pSMB->MaxSetupCount = 0;
3299 pSMB->Reserved = 0;
3300 pSMB->Flags = 0;
3301 pSMB->Timeout = 0;
3302 pSMB->Reserved2 = 0;
3303 byte_count = params + 1 /* pad */ ;
3304 pSMB->TotalParameterCount = cpu_to_le16(params);
3305 pSMB->ParameterCount = pSMB->TotalParameterCount;
3306 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003307 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3308 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 pSMB->DataCount = 0;
3310 pSMB->DataOffset = 0;
3311 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3312 pSMB->Reserved3 = 0;
3313 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3314 pSMB->SearchAttributes =
3315 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3316 ATTR_DIRECTORY);
3317 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3318 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3319 CIFS_SEARCH_RETURN_RESUME);
3320 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3321
3322 /* BB what should we set StorageType to? Does it matter? BB */
3323 pSMB->SearchStorageType = 0;
3324 pSMB->hdr.smb_buf_length += byte_count;
3325 pSMB->ByteCount = cpu_to_le16(byte_count);
3326
3327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003329 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330
Steve French88274812006-03-09 22:21:45 +00003331 if (rc) {/* BB add logic to retry regular search if Unix search
3332 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 /* BB Add code to handle unsupported level rc */
3334 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003335
Steve French88274812006-03-09 22:21:45 +00003336 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337
3338 /* BB eventually could optimize out free and realloc of buf */
3339 /* for this case */
3340 if (rc == -EAGAIN)
3341 goto findFirstRetry;
3342 } else { /* decode response */
3343 /* BB remember to free buffer if error BB */
3344 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3345 if(rc == 0) {
3346 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3347 psrch_inf->unicode = TRUE;
3348 else
3349 psrch_inf->unicode = FALSE;
3350
3351 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003352 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 psrch_inf->srch_entries_start =
3354 (char *) &pSMBr->hdr.Protocol +
3355 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3357 le16_to_cpu(pSMBr->t2.ParameterOffset));
3358
3359 if(parms->EndofSearch)
3360 psrch_inf->endOfSearch = TRUE;
3361 else
3362 psrch_inf->endOfSearch = FALSE;
3363
3364 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003365 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 *pnetfid = parms->SearchHandle;
3368 } else {
3369 cifs_buf_release(pSMB);
3370 }
3371 }
3372
3373 return rc;
3374}
3375
3376int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3377 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3378{
3379 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3380 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3381 T2_FNEXT_RSP_PARMS * parms;
3382 char *response_data;
3383 int rc = 0;
3384 int bytes_returned, name_len;
3385 __u16 params, byte_count;
3386
3387 cFYI(1, ("In FindNext"));
3388
3389 if(psrch_inf->endOfSearch == TRUE)
3390 return -ENOENT;
3391
3392 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3393 (void **) &pSMBr);
3394 if (rc)
3395 return rc;
3396
3397 params = 14; /* includes 2 bytes of null string, converted to LE below */
3398 byte_count = 0;
3399 pSMB->TotalDataCount = 0; /* no EAs */
3400 pSMB->MaxParameterCount = cpu_to_le16(8);
3401 pSMB->MaxDataCount =
3402 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3403 pSMB->MaxSetupCount = 0;
3404 pSMB->Reserved = 0;
3405 pSMB->Flags = 0;
3406 pSMB->Timeout = 0;
3407 pSMB->Reserved2 = 0;
3408 pSMB->ParameterOffset = cpu_to_le16(
3409 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3410 pSMB->DataCount = 0;
3411 pSMB->DataOffset = 0;
3412 pSMB->SetupCount = 1;
3413 pSMB->Reserved3 = 0;
3414 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3415 pSMB->SearchHandle = searchHandle; /* always kept as le */
3416 pSMB->SearchCount =
3417 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3418 /* test for Unix extensions */
3419/* if (tcon->ses->capabilities & CAP_UNIX) {
3420 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3421 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3422 } else {
3423 pSMB->InformationLevel =
3424 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3425 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3426 } */
3427 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3428 pSMB->ResumeKey = psrch_inf->resume_key;
3429 pSMB->SearchFlags =
3430 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3431
3432 name_len = psrch_inf->resume_name_len;
3433 params += name_len;
3434 if(name_len < PATH_MAX) {
3435 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3436 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003437 /* 14 byte parm len above enough for 2 byte null terminator */
3438 pSMB->ResumeFileName[name_len] = 0;
3439 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 } else {
3441 rc = -EINVAL;
3442 goto FNext2_err_exit;
3443 }
3444 byte_count = params + 1 /* pad */ ;
3445 pSMB->TotalParameterCount = cpu_to_le16(params);
3446 pSMB->ParameterCount = pSMB->TotalParameterCount;
3447 pSMB->hdr.smb_buf_length += byte_count;
3448 pSMB->ByteCount = cpu_to_le16(byte_count);
3449
3450 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3451 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003452 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 if (rc) {
3454 if (rc == -EBADF) {
3455 psrch_inf->endOfSearch = TRUE;
3456 rc = 0; /* search probably was closed at end of search above */
3457 } else
3458 cFYI(1, ("FindNext returned = %d", rc));
3459 } else { /* decode response */
3460 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3461
3462 if(rc == 0) {
3463 /* BB fixme add lock for file (srch_info) struct here */
3464 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3465 psrch_inf->unicode = TRUE;
3466 else
3467 psrch_inf->unicode = FALSE;
3468 response_data = (char *) &pSMBr->hdr.Protocol +
3469 le16_to_cpu(pSMBr->t2.ParameterOffset);
3470 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3471 response_data = (char *)&pSMBr->hdr.Protocol +
3472 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003473 if(psrch_inf->smallBuf)
3474 cifs_small_buf_release(
3475 psrch_inf->ntwrk_buf_start);
3476 else
3477 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 psrch_inf->srch_entries_start = response_data;
3479 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003480 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 if(parms->EndofSearch)
3482 psrch_inf->endOfSearch = TRUE;
3483 else
3484 psrch_inf->endOfSearch = FALSE;
3485
3486 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3487 psrch_inf->index_of_last_entry +=
3488 psrch_inf->entries_in_buffer;
3489/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3490
3491 /* BB fixme add unlock here */
3492 }
3493
3494 }
3495
3496 /* BB On error, should we leave previous search buf (and count and
3497 last entry fields) intact or free the previous one? */
3498
3499 /* Note: On -EAGAIN error only caller can retry on handle based calls
3500 since file handle passed in no longer valid */
3501FNext2_err_exit:
3502 if (rc != 0)
3503 cifs_buf_release(pSMB);
3504
3505 return rc;
3506}
3507
3508int
3509CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3510{
3511 int rc = 0;
3512 FINDCLOSE_REQ *pSMB = NULL;
3513 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3514 int bytes_returned;
3515
3516 cFYI(1, ("In CIFSSMBFindClose"));
3517 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3518
3519 /* no sense returning error if session restarted
3520 as file handle has been closed */
3521 if(rc == -EAGAIN)
3522 return 0;
3523 if (rc)
3524 return rc;
3525
3526 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3527 pSMB->FileID = searchHandle;
3528 pSMB->ByteCount = 0;
3529 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3530 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3531 if (rc) {
3532 cERROR(1, ("Send error in FindClose = %d", rc));
3533 }
Steve Frencha4544342005-08-24 13:59:35 -07003534 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 cifs_small_buf_release(pSMB);
3536
3537 /* Since session is dead, search handle closed on server already */
3538 if (rc == -EAGAIN)
3539 rc = 0;
3540
3541 return rc;
3542}
3543
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544int
3545CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3546 const unsigned char *searchName,
3547 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003548 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549{
3550 int rc = 0;
3551 TRANSACTION2_QPI_REQ *pSMB = NULL;
3552 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3553 int name_len, bytes_returned;
3554 __u16 params, byte_count;
3555
3556 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3557 if(tcon == NULL)
3558 return -ENODEV;
3559
3560GetInodeNumberRetry:
3561 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3562 (void **) &pSMBr);
3563 if (rc)
3564 return rc;
3565
3566
3567 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3568 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003569 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003570 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 name_len++; /* trailing null */
3572 name_len *= 2;
3573 } else { /* BB improve the check for buffer overruns BB */
3574 name_len = strnlen(searchName, PATH_MAX);
3575 name_len++; /* trailing null */
3576 strncpy(pSMB->FileName, searchName, name_len);
3577 }
3578
3579 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3580 pSMB->TotalDataCount = 0;
3581 pSMB->MaxParameterCount = cpu_to_le16(2);
3582 /* BB find exact max data count below from sess structure BB */
3583 pSMB->MaxDataCount = cpu_to_le16(4000);
3584 pSMB->MaxSetupCount = 0;
3585 pSMB->Reserved = 0;
3586 pSMB->Flags = 0;
3587 pSMB->Timeout = 0;
3588 pSMB->Reserved2 = 0;
3589 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3590 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3591 pSMB->DataCount = 0;
3592 pSMB->DataOffset = 0;
3593 pSMB->SetupCount = 1;
3594 pSMB->Reserved3 = 0;
3595 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3596 byte_count = params + 1 /* pad */ ;
3597 pSMB->TotalParameterCount = cpu_to_le16(params);
3598 pSMB->ParameterCount = pSMB->TotalParameterCount;
3599 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3600 pSMB->Reserved4 = 0;
3601 pSMB->hdr.smb_buf_length += byte_count;
3602 pSMB->ByteCount = cpu_to_le16(byte_count);
3603
3604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3606 if (rc) {
3607 cFYI(1, ("error %d in QueryInternalInfo", rc));
3608 } else {
3609 /* decode response */
3610 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3611 if (rc || (pSMBr->ByteCount < 2))
3612 /* BB also check enough total bytes returned */
3613 /* If rc should we check for EOPNOSUPP and
3614 disable the srvino flag? or in caller? */
3615 rc = -EIO; /* bad smb */
3616 else {
3617 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3618 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3619 struct file_internal_info * pfinfo;
3620 /* BB Do we need a cast or hash here ? */
3621 if(count < 8) {
3622 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3623 rc = -EIO;
3624 goto GetInodeNumOut;
3625 }
3626 pfinfo = (struct file_internal_info *)
3627 (data_offset + (char *) &pSMBr->hdr.Protocol);
3628 *inode_number = pfinfo->UniqueId;
3629 }
3630 }
3631GetInodeNumOut:
3632 cifs_buf_release(pSMB);
3633 if (rc == -EAGAIN)
3634 goto GetInodeNumberRetry;
3635 return rc;
3636}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637
3638int
3639CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3640 const unsigned char *searchName,
3641 unsigned char **targetUNCs,
3642 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003643 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644{
3645/* TRANS2_GET_DFS_REFERRAL */
3646 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3647 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3648 struct dfs_referral_level_3 * referrals = NULL;
3649 int rc = 0;
3650 int bytes_returned;
3651 int name_len;
3652 unsigned int i;
3653 char * temp;
3654 __u16 params, byte_count;
3655 *number_of_UNC_in_array = 0;
3656 *targetUNCs = NULL;
3657
3658 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3659 if (ses == NULL)
3660 return -ENODEV;
3661getDFSRetry:
3662 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3663 (void **) &pSMBr);
3664 if (rc)
3665 return rc;
Steve French1982c342005-08-17 12:38:22 -07003666
3667 /* server pointer checked in called function,
3668 but should never be null here anyway */
3669 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 pSMB->hdr.Tid = ses->ipc_tid;
3671 pSMB->hdr.Uid = ses->Suid;
3672 if (ses->capabilities & CAP_STATUS32) {
3673 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3674 }
3675 if (ses->capabilities & CAP_DFS) {
3676 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3677 }
3678
3679 if (ses->capabilities & CAP_UNICODE) {
3680 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3681 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003682 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003683 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 name_len++; /* trailing null */
3685 name_len *= 2;
3686 } else { /* BB improve the check for buffer overruns BB */
3687 name_len = strnlen(searchName, PATH_MAX);
3688 name_len++; /* trailing null */
3689 strncpy(pSMB->RequestFileName, searchName, name_len);
3690 }
3691
Steve French1a4e15a2006-10-12 21:33:51 +00003692 if(ses->server) {
3693 if(ses->server->secMode &
3694 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3695 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3696 }
3697
3698 pSMB->hdr.Uid = ses->Suid;
3699
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 params = 2 /* level */ + name_len /*includes null */ ;
3701 pSMB->TotalDataCount = 0;
3702 pSMB->DataCount = 0;
3703 pSMB->DataOffset = 0;
3704 pSMB->MaxParameterCount = 0;
3705 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3706 pSMB->MaxSetupCount = 0;
3707 pSMB->Reserved = 0;
3708 pSMB->Flags = 0;
3709 pSMB->Timeout = 0;
3710 pSMB->Reserved2 = 0;
3711 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3712 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3713 pSMB->SetupCount = 1;
3714 pSMB->Reserved3 = 0;
3715 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3716 byte_count = params + 3 /* pad */ ;
3717 pSMB->ParameterCount = cpu_to_le16(params);
3718 pSMB->TotalParameterCount = pSMB->ParameterCount;
3719 pSMB->MaxReferralLevel = cpu_to_le16(3);
3720 pSMB->hdr.smb_buf_length += byte_count;
3721 pSMB->ByteCount = cpu_to_le16(byte_count);
3722
3723 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3724 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3725 if (rc) {
3726 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3727 } else { /* decode response */
3728/* BB Add logic to parse referrals here */
3729 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3730
3731 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3732 rc = -EIO; /* bad smb */
3733 else {
3734 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3735 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3736
3737 cFYI(1,
3738 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3739 pSMBr->ByteCount, data_offset));
3740 referrals =
3741 (struct dfs_referral_level_3 *)
3742 (8 /* sizeof start of data block */ +
3743 data_offset +
3744 (char *) &pSMBr->hdr.Protocol);
3745 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",
3746 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)));
3747 /* BB This field is actually two bytes in from start of
3748 data block so we could do safety check that DataBlock
3749 begins at address of pSMBr->NumberOfReferrals */
3750 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3751
3752 /* BB Fix below so can return more than one referral */
3753 if(*number_of_UNC_in_array > 1)
3754 *number_of_UNC_in_array = 1;
3755
3756 /* get the length of the strings describing refs */
3757 name_len = 0;
3758 for(i=0;i<*number_of_UNC_in_array;i++) {
3759 /* make sure that DfsPathOffset not past end */
3760 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3761 if (offset > data_count) {
3762 /* if invalid referral, stop here and do
3763 not try to copy any more */
3764 *number_of_UNC_in_array = i;
3765 break;
3766 }
3767 temp = ((char *)referrals) + offset;
3768
3769 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3770 name_len += UniStrnlen((wchar_t *)temp,data_count);
3771 } else {
3772 name_len += strnlen(temp,data_count);
3773 }
3774 referrals++;
3775 /* BB add check that referral pointer does not fall off end PDU */
3776
3777 }
3778 /* BB add check for name_len bigger than bcc */
3779 *targetUNCs =
3780 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3781 if(*targetUNCs == NULL) {
3782 rc = -ENOMEM;
3783 goto GetDFSRefExit;
3784 }
3785 /* copy the ref strings */
3786 referrals =
3787 (struct dfs_referral_level_3 *)
3788 (8 /* sizeof data hdr */ +
3789 data_offset +
3790 (char *) &pSMBr->hdr.Protocol);
3791
3792 for(i=0;i<*number_of_UNC_in_array;i++) {
3793 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3794 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3795 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003796 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 } else {
3798 strncpy(*targetUNCs,temp,name_len);
3799 }
3800 /* BB update target_uncs pointers */
3801 referrals++;
3802 }
3803 temp = *targetUNCs;
3804 temp[name_len] = 0;
3805 }
3806
3807 }
3808GetDFSRefExit:
3809 if (pSMB)
3810 cifs_buf_release(pSMB);
3811
3812 if (rc == -EAGAIN)
3813 goto getDFSRetry;
3814
3815 return rc;
3816}
3817
Steve French20962432005-09-21 22:05:57 -07003818/* Query File System Info such as free space to old servers such as Win 9x */
3819int
3820SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3821{
3822/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3823 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3824 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3825 FILE_SYSTEM_ALLOC_INFO *response_data;
3826 int rc = 0;
3827 int bytes_returned = 0;
3828 __u16 params, byte_count;
3829
3830 cFYI(1, ("OldQFSInfo"));
3831oldQFSInfoRetry:
3832 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3833 (void **) &pSMBr);
3834 if (rc)
3835 return rc;
3836 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3837 (void **) &pSMBr);
3838 if (rc)
3839 return rc;
3840
3841 params = 2; /* level */
3842 pSMB->TotalDataCount = 0;
3843 pSMB->MaxParameterCount = cpu_to_le16(2);
3844 pSMB->MaxDataCount = cpu_to_le16(1000);
3845 pSMB->MaxSetupCount = 0;
3846 pSMB->Reserved = 0;
3847 pSMB->Flags = 0;
3848 pSMB->Timeout = 0;
3849 pSMB->Reserved2 = 0;
3850 byte_count = params + 1 /* pad */ ;
3851 pSMB->TotalParameterCount = cpu_to_le16(params);
3852 pSMB->ParameterCount = pSMB->TotalParameterCount;
3853 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3854 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3855 pSMB->DataCount = 0;
3856 pSMB->DataOffset = 0;
3857 pSMB->SetupCount = 1;
3858 pSMB->Reserved3 = 0;
3859 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3860 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3861 pSMB->hdr.smb_buf_length += byte_count;
3862 pSMB->ByteCount = cpu_to_le16(byte_count);
3863
3864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3866 if (rc) {
3867 cFYI(1, ("Send error in QFSInfo = %d", rc));
3868 } else { /* decode response */
3869 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3870
3871 if (rc || (pSMBr->ByteCount < 18))
3872 rc = -EIO; /* bad smb */
3873 else {
3874 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3875 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3876 pSMBr->ByteCount, data_offset));
3877
3878 response_data =
3879 (FILE_SYSTEM_ALLOC_INFO *)
3880 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3881 FSData->f_bsize =
3882 le16_to_cpu(response_data->BytesPerSector) *
3883 le32_to_cpu(response_data->
3884 SectorsPerAllocationUnit);
3885 FSData->f_blocks =
3886 le32_to_cpu(response_data->TotalAllocationUnits);
3887 FSData->f_bfree = FSData->f_bavail =
3888 le32_to_cpu(response_data->FreeAllocationUnits);
3889 cFYI(1,
3890 ("Blocks: %lld Free: %lld Block size %ld",
3891 (unsigned long long)FSData->f_blocks,
3892 (unsigned long long)FSData->f_bfree,
3893 FSData->f_bsize));
3894 }
3895 }
3896 cifs_buf_release(pSMB);
3897
3898 if (rc == -EAGAIN)
3899 goto oldQFSInfoRetry;
3900
3901 return rc;
3902}
3903
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904int
Steve French737b7582005-04-28 22:41:06 -07003905CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906{
3907/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3908 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3909 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3910 FILE_SYSTEM_INFO *response_data;
3911 int rc = 0;
3912 int bytes_returned = 0;
3913 __u16 params, byte_count;
3914
3915 cFYI(1, ("In QFSInfo"));
3916QFSInfoRetry:
3917 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3918 (void **) &pSMBr);
3919 if (rc)
3920 return rc;
3921
3922 params = 2; /* level */
3923 pSMB->TotalDataCount = 0;
3924 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003925 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 pSMB->MaxSetupCount = 0;
3927 pSMB->Reserved = 0;
3928 pSMB->Flags = 0;
3929 pSMB->Timeout = 0;
3930 pSMB->Reserved2 = 0;
3931 byte_count = params + 1 /* pad */ ;
3932 pSMB->TotalParameterCount = cpu_to_le16(params);
3933 pSMB->ParameterCount = pSMB->TotalParameterCount;
3934 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3935 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3936 pSMB->DataCount = 0;
3937 pSMB->DataOffset = 0;
3938 pSMB->SetupCount = 1;
3939 pSMB->Reserved3 = 0;
3940 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3941 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3942 pSMB->hdr.smb_buf_length += byte_count;
3943 pSMB->ByteCount = cpu_to_le16(byte_count);
3944
3945 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3946 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3947 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003948 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 } else { /* decode response */
3950 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3951
Steve French20962432005-09-21 22:05:57 -07003952 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 rc = -EIO; /* bad smb */
3954 else {
3955 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956
3957 response_data =
3958 (FILE_SYSTEM_INFO
3959 *) (((char *) &pSMBr->hdr.Protocol) +
3960 data_offset);
3961 FSData->f_bsize =
3962 le32_to_cpu(response_data->BytesPerSector) *
3963 le32_to_cpu(response_data->
3964 SectorsPerAllocationUnit);
3965 FSData->f_blocks =
3966 le64_to_cpu(response_data->TotalAllocationUnits);
3967 FSData->f_bfree = FSData->f_bavail =
3968 le64_to_cpu(response_data->FreeAllocationUnits);
3969 cFYI(1,
3970 ("Blocks: %lld Free: %lld Block size %ld",
3971 (unsigned long long)FSData->f_blocks,
3972 (unsigned long long)FSData->f_bfree,
3973 FSData->f_bsize));
3974 }
3975 }
3976 cifs_buf_release(pSMB);
3977
3978 if (rc == -EAGAIN)
3979 goto QFSInfoRetry;
3980
3981 return rc;
3982}
3983
3984int
Steve French737b7582005-04-28 22:41:06 -07003985CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986{
3987/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3988 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3989 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3990 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3991 int rc = 0;
3992 int bytes_returned = 0;
3993 __u16 params, byte_count;
3994
3995 cFYI(1, ("In QFSAttributeInfo"));
3996QFSAttributeRetry:
3997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3998 (void **) &pSMBr);
3999 if (rc)
4000 return rc;
4001
4002 params = 2; /* level */
4003 pSMB->TotalDataCount = 0;
4004 pSMB->MaxParameterCount = cpu_to_le16(2);
4005 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4006 pSMB->MaxSetupCount = 0;
4007 pSMB->Reserved = 0;
4008 pSMB->Flags = 0;
4009 pSMB->Timeout = 0;
4010 pSMB->Reserved2 = 0;
4011 byte_count = params + 1 /* pad */ ;
4012 pSMB->TotalParameterCount = cpu_to_le16(params);
4013 pSMB->ParameterCount = pSMB->TotalParameterCount;
4014 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4015 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4016 pSMB->DataCount = 0;
4017 pSMB->DataOffset = 0;
4018 pSMB->SetupCount = 1;
4019 pSMB->Reserved3 = 0;
4020 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4021 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4022 pSMB->hdr.smb_buf_length += byte_count;
4023 pSMB->ByteCount = cpu_to_le16(byte_count);
4024
4025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4027 if (rc) {
4028 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4029 } else { /* decode response */
4030 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4031
4032 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4033 rc = -EIO; /* bad smb */
4034 } else {
4035 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4036 response_data =
4037 (FILE_SYSTEM_ATTRIBUTE_INFO
4038 *) (((char *) &pSMBr->hdr.Protocol) +
4039 data_offset);
4040 memcpy(&tcon->fsAttrInfo, response_data,
4041 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4042 }
4043 }
4044 cifs_buf_release(pSMB);
4045
4046 if (rc == -EAGAIN)
4047 goto QFSAttributeRetry;
4048
4049 return rc;
4050}
4051
4052int
Steve French737b7582005-04-28 22:41:06 -07004053CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054{
4055/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4056 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4057 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4058 FILE_SYSTEM_DEVICE_INFO *response_data;
4059 int rc = 0;
4060 int bytes_returned = 0;
4061 __u16 params, byte_count;
4062
4063 cFYI(1, ("In QFSDeviceInfo"));
4064QFSDeviceRetry:
4065 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4066 (void **) &pSMBr);
4067 if (rc)
4068 return rc;
4069
4070 params = 2; /* level */
4071 pSMB->TotalDataCount = 0;
4072 pSMB->MaxParameterCount = cpu_to_le16(2);
4073 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4074 pSMB->MaxSetupCount = 0;
4075 pSMB->Reserved = 0;
4076 pSMB->Flags = 0;
4077 pSMB->Timeout = 0;
4078 pSMB->Reserved2 = 0;
4079 byte_count = params + 1 /* pad */ ;
4080 pSMB->TotalParameterCount = cpu_to_le16(params);
4081 pSMB->ParameterCount = pSMB->TotalParameterCount;
4082 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4083 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4084
4085 pSMB->DataCount = 0;
4086 pSMB->DataOffset = 0;
4087 pSMB->SetupCount = 1;
4088 pSMB->Reserved3 = 0;
4089 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4090 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4091 pSMB->hdr.smb_buf_length += byte_count;
4092 pSMB->ByteCount = cpu_to_le16(byte_count);
4093
4094 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4095 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4096 if (rc) {
4097 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4098 } else { /* decode response */
4099 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4100
4101 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4102 rc = -EIO; /* bad smb */
4103 else {
4104 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4105 response_data =
Steve French737b7582005-04-28 22:41:06 -07004106 (FILE_SYSTEM_DEVICE_INFO *)
4107 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 data_offset);
4109 memcpy(&tcon->fsDevInfo, response_data,
4110 sizeof (FILE_SYSTEM_DEVICE_INFO));
4111 }
4112 }
4113 cifs_buf_release(pSMB);
4114
4115 if (rc == -EAGAIN)
4116 goto QFSDeviceRetry;
4117
4118 return rc;
4119}
4120
4121int
Steve French737b7582005-04-28 22:41:06 -07004122CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123{
4124/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4125 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4126 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4127 FILE_SYSTEM_UNIX_INFO *response_data;
4128 int rc = 0;
4129 int bytes_returned = 0;
4130 __u16 params, byte_count;
4131
4132 cFYI(1, ("In QFSUnixInfo"));
4133QFSUnixRetry:
4134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4135 (void **) &pSMBr);
4136 if (rc)
4137 return rc;
4138
4139 params = 2; /* level */
4140 pSMB->TotalDataCount = 0;
4141 pSMB->DataCount = 0;
4142 pSMB->DataOffset = 0;
4143 pSMB->MaxParameterCount = cpu_to_le16(2);
4144 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4145 pSMB->MaxSetupCount = 0;
4146 pSMB->Reserved = 0;
4147 pSMB->Flags = 0;
4148 pSMB->Timeout = 0;
4149 pSMB->Reserved2 = 0;
4150 byte_count = params + 1 /* pad */ ;
4151 pSMB->ParameterCount = cpu_to_le16(params);
4152 pSMB->TotalParameterCount = pSMB->ParameterCount;
4153 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4154 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4155 pSMB->SetupCount = 1;
4156 pSMB->Reserved3 = 0;
4157 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4158 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4159 pSMB->hdr.smb_buf_length += byte_count;
4160 pSMB->ByteCount = cpu_to_le16(byte_count);
4161
4162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4164 if (rc) {
4165 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4166 } else { /* decode response */
4167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4168
4169 if (rc || (pSMBr->ByteCount < 13)) {
4170 rc = -EIO; /* bad smb */
4171 } else {
4172 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4173 response_data =
4174 (FILE_SYSTEM_UNIX_INFO
4175 *) (((char *) &pSMBr->hdr.Protocol) +
4176 data_offset);
4177 memcpy(&tcon->fsUnixInfo, response_data,
4178 sizeof (FILE_SYSTEM_UNIX_INFO));
4179 }
4180 }
4181 cifs_buf_release(pSMB);
4182
4183 if (rc == -EAGAIN)
4184 goto QFSUnixRetry;
4185
4186
4187 return rc;
4188}
4189
Jeremy Allisonac670552005-06-22 17:26:35 -07004190int
Steve French45abc6e2005-06-23 13:42:03 -05004191CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004192{
4193/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4194 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4195 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4196 int rc = 0;
4197 int bytes_returned = 0;
4198 __u16 params, param_offset, offset, byte_count;
4199
4200 cFYI(1, ("In SETFSUnixInfo"));
4201SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004202 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004203 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4204 (void **) &pSMBr);
4205 if (rc)
4206 return rc;
4207
4208 params = 4; /* 2 bytes zero followed by info level. */
4209 pSMB->MaxSetupCount = 0;
4210 pSMB->Reserved = 0;
4211 pSMB->Flags = 0;
4212 pSMB->Timeout = 0;
4213 pSMB->Reserved2 = 0;
4214 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4215 offset = param_offset + params;
4216
4217 pSMB->MaxParameterCount = cpu_to_le16(4);
4218 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4219 pSMB->SetupCount = 1;
4220 pSMB->Reserved3 = 0;
4221 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4222 byte_count = 1 /* pad */ + params + 12;
4223
4224 pSMB->DataCount = cpu_to_le16(12);
4225 pSMB->ParameterCount = cpu_to_le16(params);
4226 pSMB->TotalDataCount = pSMB->DataCount;
4227 pSMB->TotalParameterCount = pSMB->ParameterCount;
4228 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4229 pSMB->DataOffset = cpu_to_le16(offset);
4230
4231 /* Params. */
4232 pSMB->FileNum = 0;
4233 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4234
4235 /* Data. */
4236 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4237 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4238 pSMB->ClientUnixCap = cpu_to_le64(cap);
4239
4240 pSMB->hdr.smb_buf_length += byte_count;
4241 pSMB->ByteCount = cpu_to_le16(byte_count);
4242
4243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4245 if (rc) {
4246 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4247 } else { /* decode response */
4248 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4249 if (rc) {
4250 rc = -EIO; /* bad smb */
4251 }
4252 }
4253 cifs_buf_release(pSMB);
4254
4255 if (rc == -EAGAIN)
4256 goto SETFSUnixRetry;
4257
4258 return rc;
4259}
4260
4261
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262
4263int
4264CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004265 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266{
4267/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4268 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4269 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4270 FILE_SYSTEM_POSIX_INFO *response_data;
4271 int rc = 0;
4272 int bytes_returned = 0;
4273 __u16 params, byte_count;
4274
4275 cFYI(1, ("In QFSPosixInfo"));
4276QFSPosixRetry:
4277 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4278 (void **) &pSMBr);
4279 if (rc)
4280 return rc;
4281
4282 params = 2; /* level */
4283 pSMB->TotalDataCount = 0;
4284 pSMB->DataCount = 0;
4285 pSMB->DataOffset = 0;
4286 pSMB->MaxParameterCount = cpu_to_le16(2);
4287 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4288 pSMB->MaxSetupCount = 0;
4289 pSMB->Reserved = 0;
4290 pSMB->Flags = 0;
4291 pSMB->Timeout = 0;
4292 pSMB->Reserved2 = 0;
4293 byte_count = params + 1 /* pad */ ;
4294 pSMB->ParameterCount = cpu_to_le16(params);
4295 pSMB->TotalParameterCount = pSMB->ParameterCount;
4296 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4297 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4298 pSMB->SetupCount = 1;
4299 pSMB->Reserved3 = 0;
4300 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4301 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4302 pSMB->hdr.smb_buf_length += byte_count;
4303 pSMB->ByteCount = cpu_to_le16(byte_count);
4304
4305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4307 if (rc) {
4308 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4309 } else { /* decode response */
4310 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4311
4312 if (rc || (pSMBr->ByteCount < 13)) {
4313 rc = -EIO; /* bad smb */
4314 } else {
4315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4316 response_data =
4317 (FILE_SYSTEM_POSIX_INFO
4318 *) (((char *) &pSMBr->hdr.Protocol) +
4319 data_offset);
4320 FSData->f_bsize =
4321 le32_to_cpu(response_data->BlockSize);
4322 FSData->f_blocks =
4323 le64_to_cpu(response_data->TotalBlocks);
4324 FSData->f_bfree =
4325 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004326 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 FSData->f_bavail = FSData->f_bfree;
4328 } else {
4329 FSData->f_bavail =
4330 le64_to_cpu(response_data->UserBlocksAvail);
4331 }
Steve French70ca7342005-09-22 16:32:06 -07004332 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 FSData->f_files =
4334 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004335 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 FSData->f_ffree =
4337 le64_to_cpu(response_data->FreeFileNodes);
4338 }
4339 }
4340 cifs_buf_release(pSMB);
4341
4342 if (rc == -EAGAIN)
4343 goto QFSPosixRetry;
4344
4345 return rc;
4346}
4347
4348
4349/* We can not use write of zero bytes trick to
4350 set file size due to need for large file support. Also note that
4351 this SetPathInfo is preferred to SetFileInfo based method in next
4352 routine which is only needed to work around a sharing violation bug
4353 in Samba which this routine can run into */
4354
4355int
4356CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004357 __u64 size, int SetAllocation,
4358 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359{
4360 struct smb_com_transaction2_spi_req *pSMB = NULL;
4361 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4362 struct file_end_of_file_info *parm_data;
4363 int name_len;
4364 int rc = 0;
4365 int bytes_returned = 0;
4366 __u16 params, byte_count, data_count, param_offset, offset;
4367
4368 cFYI(1, ("In SetEOF"));
4369SetEOFRetry:
4370 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4371 (void **) &pSMBr);
4372 if (rc)
4373 return rc;
4374
4375 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4376 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004377 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004378 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 name_len++; /* trailing null */
4380 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004381 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 name_len = strnlen(fileName, PATH_MAX);
4383 name_len++; /* trailing null */
4384 strncpy(pSMB->FileName, fileName, name_len);
4385 }
4386 params = 6 + name_len;
4387 data_count = sizeof (struct file_end_of_file_info);
4388 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004389 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 pSMB->MaxSetupCount = 0;
4391 pSMB->Reserved = 0;
4392 pSMB->Flags = 0;
4393 pSMB->Timeout = 0;
4394 pSMB->Reserved2 = 0;
4395 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4396 InformationLevel) - 4;
4397 offset = param_offset + params;
4398 if(SetAllocation) {
4399 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4400 pSMB->InformationLevel =
4401 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4402 else
4403 pSMB->InformationLevel =
4404 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4405 } else /* Set File Size */ {
4406 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4407 pSMB->InformationLevel =
4408 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4409 else
4410 pSMB->InformationLevel =
4411 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4412 }
4413
4414 parm_data =
4415 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4416 offset);
4417 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4418 pSMB->DataOffset = cpu_to_le16(offset);
4419 pSMB->SetupCount = 1;
4420 pSMB->Reserved3 = 0;
4421 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4422 byte_count = 3 /* pad */ + params + data_count;
4423 pSMB->DataCount = cpu_to_le16(data_count);
4424 pSMB->TotalDataCount = pSMB->DataCount;
4425 pSMB->ParameterCount = cpu_to_le16(params);
4426 pSMB->TotalParameterCount = pSMB->ParameterCount;
4427 pSMB->Reserved4 = 0;
4428 pSMB->hdr.smb_buf_length += byte_count;
4429 parm_data->FileSize = cpu_to_le64(size);
4430 pSMB->ByteCount = cpu_to_le16(byte_count);
4431 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4432 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4433 if (rc) {
4434 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4435 }
4436
4437 cifs_buf_release(pSMB);
4438
4439 if (rc == -EAGAIN)
4440 goto SetEOFRetry;
4441
4442 return rc;
4443}
4444
4445int
4446CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4447 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4448{
4449 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4450 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4451 char *data_offset;
4452 struct file_end_of_file_info *parm_data;
4453 int rc = 0;
4454 int bytes_returned = 0;
4455 __u16 params, param_offset, offset, byte_count, count;
4456
4457 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4458 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004459 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 if (rc)
4462 return rc;
4463
Steve Frenchcd634992005-04-28 22:41:10 -07004464 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4465
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4467 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4468
4469 params = 6;
4470 pSMB->MaxSetupCount = 0;
4471 pSMB->Reserved = 0;
4472 pSMB->Flags = 0;
4473 pSMB->Timeout = 0;
4474 pSMB->Reserved2 = 0;
4475 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4476 offset = param_offset + params;
4477
4478 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4479
4480 count = sizeof(struct file_end_of_file_info);
4481 pSMB->MaxParameterCount = cpu_to_le16(2);
4482 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4483 pSMB->SetupCount = 1;
4484 pSMB->Reserved3 = 0;
4485 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4486 byte_count = 3 /* pad */ + params + count;
4487 pSMB->DataCount = cpu_to_le16(count);
4488 pSMB->ParameterCount = cpu_to_le16(params);
4489 pSMB->TotalDataCount = pSMB->DataCount;
4490 pSMB->TotalParameterCount = pSMB->ParameterCount;
4491 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4492 parm_data =
4493 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4494 offset);
4495 pSMB->DataOffset = cpu_to_le16(offset);
4496 parm_data->FileSize = cpu_to_le64(size);
4497 pSMB->Fid = fid;
4498 if(SetAllocation) {
4499 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4500 pSMB->InformationLevel =
4501 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4502 else
4503 pSMB->InformationLevel =
4504 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4505 } else /* Set File Size */ {
4506 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4507 pSMB->InformationLevel =
4508 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4509 else
4510 pSMB->InformationLevel =
4511 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4512 }
4513 pSMB->Reserved4 = 0;
4514 pSMB->hdr.smb_buf_length += byte_count;
4515 pSMB->ByteCount = cpu_to_le16(byte_count);
4516 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4517 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4518 if (rc) {
4519 cFYI(1,
4520 ("Send error in SetFileInfo (SetFileSize) = %d",
4521 rc));
4522 }
4523
4524 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004525 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526
4527 /* Note: On -EAGAIN error only caller can retry on handle based calls
4528 since file handle passed in no longer valid */
4529
4530 return rc;
4531}
4532
4533/* Some legacy servers such as NT4 require that the file times be set on
4534 an open handle, rather than by pathname - this is awkward due to
4535 potential access conflicts on the open, but it is unavoidable for these
4536 old servers since the only other choice is to go from 100 nanosecond DCE
4537 time and resort to the original setpathinfo level which takes the ancient
4538 DOS time format with 2 second granularity */
4539int
4540CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4541 __u16 fid)
4542{
4543 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4544 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4545 char *data_offset;
4546 int rc = 0;
4547 int bytes_returned = 0;
4548 __u16 params, param_offset, offset, byte_count, count;
4549
4550 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004551 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4552
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 if (rc)
4554 return rc;
4555
Steve Frenchcd634992005-04-28 22:41:10 -07004556 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4557
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 /* At this point there is no need to override the current pid
4559 with the pid of the opener, but that could change if we someday
4560 use an existing handle (rather than opening one on the fly) */
4561 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4562 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4563
4564 params = 6;
4565 pSMB->MaxSetupCount = 0;
4566 pSMB->Reserved = 0;
4567 pSMB->Flags = 0;
4568 pSMB->Timeout = 0;
4569 pSMB->Reserved2 = 0;
4570 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4571 offset = param_offset + params;
4572
4573 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4574
4575 count = sizeof (FILE_BASIC_INFO);
4576 pSMB->MaxParameterCount = cpu_to_le16(2);
4577 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4578 pSMB->SetupCount = 1;
4579 pSMB->Reserved3 = 0;
4580 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4581 byte_count = 3 /* pad */ + params + count;
4582 pSMB->DataCount = cpu_to_le16(count);
4583 pSMB->ParameterCount = cpu_to_le16(params);
4584 pSMB->TotalDataCount = pSMB->DataCount;
4585 pSMB->TotalParameterCount = pSMB->ParameterCount;
4586 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4587 pSMB->DataOffset = cpu_to_le16(offset);
4588 pSMB->Fid = fid;
4589 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4590 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4591 else
4592 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4593 pSMB->Reserved4 = 0;
4594 pSMB->hdr.smb_buf_length += byte_count;
4595 pSMB->ByteCount = cpu_to_le16(byte_count);
4596 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4597 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4598 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4599 if (rc) {
4600 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4601 }
4602
Steve Frenchcd634992005-04-28 22:41:10 -07004603 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604
4605 /* Note: On -EAGAIN error only caller can retry on handle based calls
4606 since file handle passed in no longer valid */
4607
4608 return rc;
4609}
4610
4611
4612int
4613CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4614 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004615 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616{
4617 TRANSACTION2_SPI_REQ *pSMB = NULL;
4618 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4619 int name_len;
4620 int rc = 0;
4621 int bytes_returned = 0;
4622 char *data_offset;
4623 __u16 params, param_offset, offset, byte_count, count;
4624
4625 cFYI(1, ("In SetTimes"));
4626
4627SetTimesRetry:
4628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4629 (void **) &pSMBr);
4630 if (rc)
4631 return rc;
4632
4633 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4634 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004635 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004636 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 name_len++; /* trailing null */
4638 name_len *= 2;
4639 } else { /* BB improve the check for buffer overruns BB */
4640 name_len = strnlen(fileName, PATH_MAX);
4641 name_len++; /* trailing null */
4642 strncpy(pSMB->FileName, fileName, name_len);
4643 }
4644
4645 params = 6 + name_len;
4646 count = sizeof (FILE_BASIC_INFO);
4647 pSMB->MaxParameterCount = cpu_to_le16(2);
4648 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4649 pSMB->MaxSetupCount = 0;
4650 pSMB->Reserved = 0;
4651 pSMB->Flags = 0;
4652 pSMB->Timeout = 0;
4653 pSMB->Reserved2 = 0;
4654 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4655 InformationLevel) - 4;
4656 offset = param_offset + params;
4657 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4658 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4659 pSMB->DataOffset = cpu_to_le16(offset);
4660 pSMB->SetupCount = 1;
4661 pSMB->Reserved3 = 0;
4662 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4663 byte_count = 3 /* pad */ + params + count;
4664
4665 pSMB->DataCount = cpu_to_le16(count);
4666 pSMB->ParameterCount = cpu_to_le16(params);
4667 pSMB->TotalDataCount = pSMB->DataCount;
4668 pSMB->TotalParameterCount = pSMB->ParameterCount;
4669 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4670 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4671 else
4672 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4673 pSMB->Reserved4 = 0;
4674 pSMB->hdr.smb_buf_length += byte_count;
4675 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4676 pSMB->ByteCount = cpu_to_le16(byte_count);
4677 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4678 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4679 if (rc) {
4680 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4681 }
4682
4683 cifs_buf_release(pSMB);
4684
4685 if (rc == -EAGAIN)
4686 goto SetTimesRetry;
4687
4688 return rc;
4689}
4690
4691/* Can not be used to set time stamps yet (due to old DOS time format) */
4692/* Can be used to set attributes */
4693#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4694 handling it anyway and NT4 was what we thought it would be needed for
4695 Do not delete it until we prove whether needed for Win9x though */
4696int
4697CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4698 __u16 dos_attrs, const struct nls_table *nls_codepage)
4699{
4700 SETATTR_REQ *pSMB = NULL;
4701 SETATTR_RSP *pSMBr = NULL;
4702 int rc = 0;
4703 int bytes_returned;
4704 int name_len;
4705
4706 cFYI(1, ("In SetAttrLegacy"));
4707
4708SetAttrLgcyRetry:
4709 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4710 (void **) &pSMBr);
4711 if (rc)
4712 return rc;
4713
4714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4715 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004716 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 PATH_MAX, nls_codepage);
4718 name_len++; /* trailing null */
4719 name_len *= 2;
4720 } else { /* BB improve the check for buffer overruns BB */
4721 name_len = strnlen(fileName, PATH_MAX);
4722 name_len++; /* trailing null */
4723 strncpy(pSMB->fileName, fileName, name_len);
4724 }
4725 pSMB->attr = cpu_to_le16(dos_attrs);
4726 pSMB->BufferFormat = 0x04;
4727 pSMB->hdr.smb_buf_length += name_len + 1;
4728 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4731 if (rc) {
4732 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4733 }
4734
4735 cifs_buf_release(pSMB);
4736
4737 if (rc == -EAGAIN)
4738 goto SetAttrLgcyRetry;
4739
4740 return rc;
4741}
4742#endif /* temporarily unneeded SetAttr legacy function */
4743
4744int
4745CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004746 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4747 dev_t device, const struct nls_table *nls_codepage,
4748 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749{
4750 TRANSACTION2_SPI_REQ *pSMB = NULL;
4751 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4752 int name_len;
4753 int rc = 0;
4754 int bytes_returned = 0;
4755 FILE_UNIX_BASIC_INFO *data_offset;
4756 __u16 params, param_offset, offset, count, byte_count;
4757
4758 cFYI(1, ("In SetUID/GID/Mode"));
4759setPermsRetry:
4760 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4761 (void **) &pSMBr);
4762 if (rc)
4763 return rc;
4764
4765 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4766 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004767 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004768 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 name_len++; /* trailing null */
4770 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004771 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 name_len = strnlen(fileName, PATH_MAX);
4773 name_len++; /* trailing null */
4774 strncpy(pSMB->FileName, fileName, name_len);
4775 }
4776
4777 params = 6 + name_len;
4778 count = sizeof (FILE_UNIX_BASIC_INFO);
4779 pSMB->MaxParameterCount = cpu_to_le16(2);
4780 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4781 pSMB->MaxSetupCount = 0;
4782 pSMB->Reserved = 0;
4783 pSMB->Flags = 0;
4784 pSMB->Timeout = 0;
4785 pSMB->Reserved2 = 0;
4786 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4787 InformationLevel) - 4;
4788 offset = param_offset + params;
4789 data_offset =
4790 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4791 offset);
4792 memset(data_offset, 0, count);
4793 pSMB->DataOffset = cpu_to_le16(offset);
4794 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4795 pSMB->SetupCount = 1;
4796 pSMB->Reserved3 = 0;
4797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4798 byte_count = 3 /* pad */ + params + count;
4799 pSMB->ParameterCount = cpu_to_le16(params);
4800 pSMB->DataCount = cpu_to_le16(count);
4801 pSMB->TotalParameterCount = pSMB->ParameterCount;
4802 pSMB->TotalDataCount = pSMB->DataCount;
4803 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4804 pSMB->Reserved4 = 0;
4805 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00004806 /* Samba server ignores set of file size to zero due to bugs in some
4807 older clients, but we should be precise - we use SetFileSize to
4808 set file size and do not want to truncate file size to zero
4809 accidently as happened on one Samba server beta by putting
4810 zero instead of -1 here */
4811 data_offset->EndOfFile = NO_CHANGE_64;
4812 data_offset->NumOfBytes = NO_CHANGE_64;
4813 data_offset->LastStatusChange = NO_CHANGE_64;
4814 data_offset->LastAccessTime = NO_CHANGE_64;
4815 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 data_offset->Uid = cpu_to_le64(uid);
4817 data_offset->Gid = cpu_to_le64(gid);
4818 /* better to leave device as zero when it is */
4819 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4820 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4821 data_offset->Permissions = cpu_to_le64(mode);
4822
4823 if(S_ISREG(mode))
4824 data_offset->Type = cpu_to_le32(UNIX_FILE);
4825 else if(S_ISDIR(mode))
4826 data_offset->Type = cpu_to_le32(UNIX_DIR);
4827 else if(S_ISLNK(mode))
4828 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4829 else if(S_ISCHR(mode))
4830 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4831 else if(S_ISBLK(mode))
4832 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4833 else if(S_ISFIFO(mode))
4834 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4835 else if(S_ISSOCK(mode))
4836 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4837
4838
4839 pSMB->ByteCount = cpu_to_le16(byte_count);
4840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4842 if (rc) {
4843 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4844 }
4845
4846 if (pSMB)
4847 cifs_buf_release(pSMB);
4848 if (rc == -EAGAIN)
4849 goto setPermsRetry;
4850 return rc;
4851}
4852
4853int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004854 const int notify_subdirs, const __u16 netfid,
4855 __u32 filter, struct file * pfile, int multishot,
4856 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857{
4858 int rc = 0;
4859 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004860 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004861 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 int bytes_returned;
4863
4864 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4865 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4866 (void **) &pSMBr);
4867 if (rc)
4868 return rc;
4869
4870 pSMB->TotalParameterCount = 0 ;
4871 pSMB->TotalDataCount = 0;
4872 pSMB->MaxParameterCount = cpu_to_le32(2);
4873 /* BB find exact data count max from sess structure BB */
4874 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004875/* BB VERIFY verify which is correct for above BB */
4876 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4877 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4878
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 pSMB->MaxSetupCount = 4;
4880 pSMB->Reserved = 0;
4881 pSMB->ParameterOffset = 0;
4882 pSMB->DataCount = 0;
4883 pSMB->DataOffset = 0;
4884 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4885 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4886 pSMB->ParameterCount = pSMB->TotalParameterCount;
4887 if(notify_subdirs)
4888 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4889 pSMB->Reserved2 = 0;
4890 pSMB->CompletionFilter = cpu_to_le32(filter);
4891 pSMB->Fid = netfid; /* file handle always le */
4892 pSMB->ByteCount = 0;
4893
4894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4895 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4896 if (rc) {
4897 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004898 } else {
4899 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004900 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08004901 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004902 sizeof(struct dir_notify_req),
4903 GFP_KERNEL);
4904 if(dnotify_req) {
4905 dnotify_req->Pid = pSMB->hdr.Pid;
4906 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4907 dnotify_req->Mid = pSMB->hdr.Mid;
4908 dnotify_req->Tid = pSMB->hdr.Tid;
4909 dnotify_req->Uid = pSMB->hdr.Uid;
4910 dnotify_req->netfid = netfid;
4911 dnotify_req->pfile = pfile;
4912 dnotify_req->filter = filter;
4913 dnotify_req->multishot = multishot;
4914 spin_lock(&GlobalMid_Lock);
4915 list_add_tail(&dnotify_req->lhead,
4916 &GlobalDnotifyReqList);
4917 spin_unlock(&GlobalMid_Lock);
4918 } else
4919 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 }
4921 cifs_buf_release(pSMB);
4922 return rc;
4923}
4924#ifdef CONFIG_CIFS_XATTR
4925ssize_t
4926CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4927 const unsigned char *searchName,
4928 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004929 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930{
4931 /* BB assumes one setup word */
4932 TRANSACTION2_QPI_REQ *pSMB = NULL;
4933 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4934 int rc = 0;
4935 int bytes_returned;
4936 int name_len;
4937 struct fea * temp_fea;
4938 char * temp_ptr;
4939 __u16 params, byte_count;
4940
4941 cFYI(1, ("In Query All EAs path %s", searchName));
4942QAllEAsRetry:
4943 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4944 (void **) &pSMBr);
4945 if (rc)
4946 return rc;
4947
4948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4949 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004950 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004951 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 name_len++; /* trailing null */
4953 name_len *= 2;
4954 } else { /* BB improve the check for buffer overruns BB */
4955 name_len = strnlen(searchName, PATH_MAX);
4956 name_len++; /* trailing null */
4957 strncpy(pSMB->FileName, searchName, name_len);
4958 }
4959
4960 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4961 pSMB->TotalDataCount = 0;
4962 pSMB->MaxParameterCount = cpu_to_le16(2);
4963 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4964 pSMB->MaxSetupCount = 0;
4965 pSMB->Reserved = 0;
4966 pSMB->Flags = 0;
4967 pSMB->Timeout = 0;
4968 pSMB->Reserved2 = 0;
4969 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4970 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4971 pSMB->DataCount = 0;
4972 pSMB->DataOffset = 0;
4973 pSMB->SetupCount = 1;
4974 pSMB->Reserved3 = 0;
4975 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4976 byte_count = params + 1 /* pad */ ;
4977 pSMB->TotalParameterCount = cpu_to_le16(params);
4978 pSMB->ParameterCount = pSMB->TotalParameterCount;
4979 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4980 pSMB->Reserved4 = 0;
4981 pSMB->hdr.smb_buf_length += byte_count;
4982 pSMB->ByteCount = cpu_to_le16(byte_count);
4983
4984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4986 if (rc) {
4987 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4988 } else { /* decode response */
4989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4990
4991 /* BB also check enough total bytes returned */
4992 /* BB we need to improve the validity checking
4993 of these trans2 responses */
4994 if (rc || (pSMBr->ByteCount < 4))
4995 rc = -EIO; /* bad smb */
4996 /* else if (pFindData){
4997 memcpy((char *) pFindData,
4998 (char *) &pSMBr->hdr.Protocol +
4999 data_offset, kl);
5000 }*/ else {
5001 /* check that length of list is not more than bcc */
5002 /* check that each entry does not go beyond length
5003 of list */
5004 /* check that each element of each entry does not
5005 go beyond end of list */
5006 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5007 struct fealist * ea_response_data;
5008 rc = 0;
5009 /* validate_trans2_offsets() */
5010 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5011 ea_response_data = (struct fealist *)
5012 (((char *) &pSMBr->hdr.Protocol) +
5013 data_offset);
5014 name_len = le32_to_cpu(ea_response_data->list_len);
5015 cFYI(1,("ea length %d", name_len));
5016 if(name_len <= 8) {
5017 /* returned EA size zeroed at top of function */
5018 cFYI(1,("empty EA list returned from server"));
5019 } else {
5020 /* account for ea list len */
5021 name_len -= 4;
5022 temp_fea = ea_response_data->list;
5023 temp_ptr = (char *)temp_fea;
5024 while(name_len > 0) {
5025 __u16 value_len;
5026 name_len -= 4;
5027 temp_ptr += 4;
5028 rc += temp_fea->name_len;
5029 /* account for prefix user. and trailing null */
5030 rc = rc + 5 + 1;
5031 if(rc<(int)buf_size) {
5032 memcpy(EAData,"user.",5);
5033 EAData+=5;
5034 memcpy(EAData,temp_ptr,temp_fea->name_len);
5035 EAData+=temp_fea->name_len;
5036 /* null terminate name */
5037 *EAData = 0;
5038 EAData = EAData + 1;
5039 } else if(buf_size == 0) {
5040 /* skip copy - calc size only */
5041 } else {
5042 /* stop before overrun buffer */
5043 rc = -ERANGE;
5044 break;
5045 }
5046 name_len -= temp_fea->name_len;
5047 temp_ptr += temp_fea->name_len;
5048 /* account for trailing null */
5049 name_len--;
5050 temp_ptr++;
5051 value_len = le16_to_cpu(temp_fea->value_len);
5052 name_len -= value_len;
5053 temp_ptr += value_len;
5054 /* BB check that temp_ptr is still within smb BB*/
5055 /* no trailing null to account for in value len */
5056 /* go on to next EA */
5057 temp_fea = (struct fea *)temp_ptr;
5058 }
5059 }
5060 }
5061 }
5062 if (pSMB)
5063 cifs_buf_release(pSMB);
5064 if (rc == -EAGAIN)
5065 goto QAllEAsRetry;
5066
5067 return (ssize_t)rc;
5068}
5069
5070ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5071 const unsigned char * searchName,const unsigned char * ea_name,
5072 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005073 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074{
5075 TRANSACTION2_QPI_REQ *pSMB = NULL;
5076 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5077 int rc = 0;
5078 int bytes_returned;
5079 int name_len;
5080 struct fea * temp_fea;
5081 char * temp_ptr;
5082 __u16 params, byte_count;
5083
5084 cFYI(1, ("In Query EA path %s", searchName));
5085QEARetry:
5086 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5087 (void **) &pSMBr);
5088 if (rc)
5089 return rc;
5090
5091 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5092 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005093 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005094 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 name_len++; /* trailing null */
5096 name_len *= 2;
5097 } else { /* BB improve the check for buffer overruns BB */
5098 name_len = strnlen(searchName, PATH_MAX);
5099 name_len++; /* trailing null */
5100 strncpy(pSMB->FileName, searchName, name_len);
5101 }
5102
5103 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5104 pSMB->TotalDataCount = 0;
5105 pSMB->MaxParameterCount = cpu_to_le16(2);
5106 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5107 pSMB->MaxSetupCount = 0;
5108 pSMB->Reserved = 0;
5109 pSMB->Flags = 0;
5110 pSMB->Timeout = 0;
5111 pSMB->Reserved2 = 0;
5112 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5113 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5114 pSMB->DataCount = 0;
5115 pSMB->DataOffset = 0;
5116 pSMB->SetupCount = 1;
5117 pSMB->Reserved3 = 0;
5118 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5119 byte_count = params + 1 /* pad */ ;
5120 pSMB->TotalParameterCount = cpu_to_le16(params);
5121 pSMB->ParameterCount = pSMB->TotalParameterCount;
5122 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5123 pSMB->Reserved4 = 0;
5124 pSMB->hdr.smb_buf_length += byte_count;
5125 pSMB->ByteCount = cpu_to_le16(byte_count);
5126
5127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5129 if (rc) {
5130 cFYI(1, ("Send error in Query EA = %d", rc));
5131 } else { /* decode response */
5132 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5133
5134 /* BB also check enough total bytes returned */
5135 /* BB we need to improve the validity checking
5136 of these trans2 responses */
5137 if (rc || (pSMBr->ByteCount < 4))
5138 rc = -EIO; /* bad smb */
5139 /* else if (pFindData){
5140 memcpy((char *) pFindData,
5141 (char *) &pSMBr->hdr.Protocol +
5142 data_offset, kl);
5143 }*/ else {
5144 /* check that length of list is not more than bcc */
5145 /* check that each entry does not go beyond length
5146 of list */
5147 /* check that each element of each entry does not
5148 go beyond end of list */
5149 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5150 struct fealist * ea_response_data;
5151 rc = -ENODATA;
5152 /* validate_trans2_offsets() */
5153 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5154 ea_response_data = (struct fealist *)
5155 (((char *) &pSMBr->hdr.Protocol) +
5156 data_offset);
5157 name_len = le32_to_cpu(ea_response_data->list_len);
5158 cFYI(1,("ea length %d", name_len));
5159 if(name_len <= 8) {
5160 /* returned EA size zeroed at top of function */
5161 cFYI(1,("empty EA list returned from server"));
5162 } else {
5163 /* account for ea list len */
5164 name_len -= 4;
5165 temp_fea = ea_response_data->list;
5166 temp_ptr = (char *)temp_fea;
5167 /* loop through checking if we have a matching
5168 name and then return the associated value */
5169 while(name_len > 0) {
5170 __u16 value_len;
5171 name_len -= 4;
5172 temp_ptr += 4;
5173 value_len = le16_to_cpu(temp_fea->value_len);
5174 /* BB validate that value_len falls within SMB,
5175 even though maximum for name_len is 255 */
5176 if(memcmp(temp_fea->name,ea_name,
5177 temp_fea->name_len) == 0) {
5178 /* found a match */
5179 rc = value_len;
5180 /* account for prefix user. and trailing null */
5181 if(rc<=(int)buf_size) {
5182 memcpy(ea_value,
5183 temp_fea->name+temp_fea->name_len+1,
5184 rc);
5185 /* ea values, unlike ea names,
5186 are not null terminated */
5187 } else if(buf_size == 0) {
5188 /* skip copy - calc size only */
5189 } else {
5190 /* stop before overrun buffer */
5191 rc = -ERANGE;
5192 }
5193 break;
5194 }
5195 name_len -= temp_fea->name_len;
5196 temp_ptr += temp_fea->name_len;
5197 /* account for trailing null */
5198 name_len--;
5199 temp_ptr++;
5200 name_len -= value_len;
5201 temp_ptr += value_len;
5202 /* no trailing null to account for in value len */
5203 /* go on to next EA */
5204 temp_fea = (struct fea *)temp_ptr;
5205 }
5206 }
5207 }
5208 }
5209 if (pSMB)
5210 cifs_buf_release(pSMB);
5211 if (rc == -EAGAIN)
5212 goto QEARetry;
5213
5214 return (ssize_t)rc;
5215}
5216
5217int
5218CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5219 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005220 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5221 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222{
5223 struct smb_com_transaction2_spi_req *pSMB = NULL;
5224 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5225 struct fealist *parm_data;
5226 int name_len;
5227 int rc = 0;
5228 int bytes_returned = 0;
5229 __u16 params, param_offset, byte_count, offset, count;
5230
5231 cFYI(1, ("In SetEA"));
5232SetEARetry:
5233 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5234 (void **) &pSMBr);
5235 if (rc)
5236 return rc;
5237
5238 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5239 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005240 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005241 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 name_len++; /* trailing null */
5243 name_len *= 2;
5244 } else { /* BB improve the check for buffer overruns BB */
5245 name_len = strnlen(fileName, PATH_MAX);
5246 name_len++; /* trailing null */
5247 strncpy(pSMB->FileName, fileName, name_len);
5248 }
5249
5250 params = 6 + name_len;
5251
5252 /* done calculating parms using name_len of file name,
5253 now use name_len to calculate length of ea name
5254 we are going to create in the inode xattrs */
5255 if(ea_name == NULL)
5256 name_len = 0;
5257 else
5258 name_len = strnlen(ea_name,255);
5259
5260 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5261 pSMB->MaxParameterCount = cpu_to_le16(2);
5262 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5263 pSMB->MaxSetupCount = 0;
5264 pSMB->Reserved = 0;
5265 pSMB->Flags = 0;
5266 pSMB->Timeout = 0;
5267 pSMB->Reserved2 = 0;
5268 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5269 InformationLevel) - 4;
5270 offset = param_offset + params;
5271 pSMB->InformationLevel =
5272 cpu_to_le16(SMB_SET_FILE_EA);
5273
5274 parm_data =
5275 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5276 offset);
5277 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5278 pSMB->DataOffset = cpu_to_le16(offset);
5279 pSMB->SetupCount = 1;
5280 pSMB->Reserved3 = 0;
5281 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5282 byte_count = 3 /* pad */ + params + count;
5283 pSMB->DataCount = cpu_to_le16(count);
5284 parm_data->list_len = cpu_to_le32(count);
5285 parm_data->list[0].EA_flags = 0;
5286 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005287 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 /* EA names are always ASCII */
5289 if(ea_name)
5290 strncpy(parm_data->list[0].name,ea_name,name_len);
5291 parm_data->list[0].name[name_len] = 0;
5292 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5293 /* caller ensures that ea_value_len is less than 64K but
5294 we need to ensure that it fits within the smb */
5295
5296 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5297 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5298 if(ea_value_len)
5299 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5300
5301 pSMB->TotalDataCount = pSMB->DataCount;
5302 pSMB->ParameterCount = cpu_to_le16(params);
5303 pSMB->TotalParameterCount = pSMB->ParameterCount;
5304 pSMB->Reserved4 = 0;
5305 pSMB->hdr.smb_buf_length += byte_count;
5306 pSMB->ByteCount = cpu_to_le16(byte_count);
5307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5309 if (rc) {
5310 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5311 }
5312
5313 cifs_buf_release(pSMB);
5314
5315 if (rc == -EAGAIN)
5316 goto SetEARetry;
5317
5318 return rc;
5319}
5320
5321#endif