blob: 4a2458e787847967d8f046173be9c21e0daf24ef [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French2dd29d32007-04-23 22:07:35 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
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 */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
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)))
Steve French762e5ab2007-06-28 18:41:42 +0000429 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000430 else /* if override flags set only sign/seal OR them with global auth */
431 secFlags = extended_security | ses->overrideSecFlg;
432
Steve French762e5ab2007-06-28 18:41:42 +0000433 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000434
Steve French1982c342005-08-17 12:38:22 -0700435 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000436 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
437 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 French762e5ab2007-06-28 18:41:42 +0000636 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
637 /* MUST_SIGN already includes the MAY_SIGN FLAG
638 so if this is zero it means that signing is disabled */
639 cFYI(1, ("Signing disabled"));
Steve French254e55e2006-06-04 05:53:15 +0000640 if(server->secMode & SECMODE_SIGN_REQUIRED)
Steve French762e5ab2007-06-28 18:41:42 +0000641 cERROR(1, ("Server requires "
642 "/proc/fs/cifs/PacketSigningEnabled "
643 "to be on"));
Steve French254e55e2006-06-04 05:53:15 +0000644 server->secMode &=
645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
647 /* signing required */
648 cFYI(1, ("Must sign - segFlags 0x%x", secFlags));
649 if ((server->secMode &
650 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
651 cERROR(1,
652 ("signing required but server lacks support"));
653 } else
654 server->secMode |= SECMODE_SIGN_REQUIRED;
655 } else {
656 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French254e55e2006-06-04 05:53:15 +0000657 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
658 server->secMode &=
659 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
Steve French762e5ab2007-06-28 18:41:42 +0000661
Steve French39798772006-05-31 22:40:51 +0000662neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700663 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000664
665 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return rc;
667}
668
669int
670CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
671{
672 struct smb_hdr *smb_buffer;
673 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
674 int rc = 0;
675 int length;
676
677 cFYI(1, ("In tree disconnect"));
678 /*
679 * If last user of the connection and
680 * connection alive - disconnect it
681 * If this is the last connection on the server session disconnect it
682 * (and inside session disconnect we should check if tcp socket needs
683 * to be freed and kernel thread woken up).
684 */
685 if (tcon)
686 down(&tcon->tconSem);
687 else
688 return -EIO;
689
690 atomic_dec(&tcon->useCount);
691 if (atomic_read(&tcon->useCount) > 0) {
692 up(&tcon->tconSem);
693 return -EBUSY;
694 }
695
696 /* No need to return error on this operation if tid invalidated and
697 closed on server already e.g. due to tcp session crashing */
698 if(tcon->tidStatus == CifsNeedReconnect) {
699 up(&tcon->tconSem);
700 return 0;
701 }
702
703 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
704 up(&tcon->tconSem);
705 return -EIO;
706 }
Steve French09d1db52005-04-28 22:41:08 -0700707 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
708 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 if (rc) {
710 up(&tcon->tconSem);
711 return rc;
712 } else {
713 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
716 &length, 0);
717 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700718 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 if (smb_buffer)
721 cifs_small_buf_release(smb_buffer);
722 up(&tcon->tconSem);
723
724 /* No need to return error on this operation if tid invalidated and
725 closed on server already e.g. due to tcp session crashing */
726 if (rc == -EAGAIN)
727 rc = 0;
728
729 return rc;
730}
731
732int
733CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
734{
735 struct smb_hdr *smb_buffer_response;
736 LOGOFF_ANDX_REQ *pSMB;
737 int rc = 0;
738 int length;
739
740 cFYI(1, ("In SMBLogoff for session disconnect"));
741 if (ses)
742 down(&ses->sesSem);
743 else
744 return -EIO;
745
746 atomic_dec(&ses->inUse);
747 if (atomic_read(&ses->inUse) > 0) {
748 up(&ses->sesSem);
749 return -EBUSY;
750 }
751 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
752 if (rc) {
753 up(&ses->sesSem);
754 return rc;
755 }
756
757 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
758
759 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700760 pSMB->hdr.Mid = GetNextMid(ses->server);
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if(ses->server->secMode &
763 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
764 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
765 }
766
767 pSMB->hdr.Uid = ses->Suid;
768
769 pSMB->AndXCommand = 0xFF;
770 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
771 smb_buffer_response, &length, 0);
772 if (ses->server) {
773 atomic_dec(&ses->server->socketUseCount);
774 if (atomic_read(&ses->server->socketUseCount) == 0) {
775 spin_lock(&GlobalMid_Lock);
776 ses->server->tcpStatus = CifsExiting;
777 spin_unlock(&GlobalMid_Lock);
778 rc = -ESHUTDOWN;
779 }
780 }
Steve Frencha59c6582005-08-17 12:12:19 -0700781 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700782 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 /* if session dead then we do not need to do ulogoff,
785 since server closed smb session, no sense reporting
786 error */
787 if (rc == -EAGAIN)
788 rc = 0;
789 return rc;
790}
791
792int
Steve French737b7582005-04-28 22:41:06 -0700793CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
794 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
796 DELETE_FILE_REQ *pSMB = NULL;
797 DELETE_FILE_RSP *pSMBr = NULL;
798 int rc = 0;
799 int bytes_returned;
800 int name_len;
801
802DelFileRetry:
803 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
804 (void **) &pSMBr);
805 if (rc)
806 return rc;
807
808 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
809 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500810 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700811 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 name_len++; /* trailing null */
813 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700814 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 name_len = strnlen(fileName, PATH_MAX);
816 name_len++; /* trailing null */
817 strncpy(pSMB->fileName, fileName, name_len);
818 }
819 pSMB->SearchAttributes =
820 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
821 pSMB->BufferFormat = 0x04;
822 pSMB->hdr.smb_buf_length += name_len + 1;
823 pSMB->ByteCount = cpu_to_le16(name_len + 1);
824 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
825 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700826 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (rc) {
828 cFYI(1, ("Error in RMFile = %d", rc));
829 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 cifs_buf_release(pSMB);
832 if (rc == -EAGAIN)
833 goto DelFileRetry;
834
835 return rc;
836}
837
838int
Steve French737b7582005-04-28 22:41:06 -0700839CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
840 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
842 DELETE_DIRECTORY_REQ *pSMB = NULL;
843 DELETE_DIRECTORY_RSP *pSMBr = NULL;
844 int rc = 0;
845 int bytes_returned;
846 int name_len;
847
848 cFYI(1, ("In CIFSSMBRmDir"));
849RmDirRetry:
850 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
851 (void **) &pSMBr);
852 if (rc)
853 return rc;
854
855 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700856 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
857 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 name_len++; /* trailing null */
859 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700860 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 name_len = strnlen(dirName, PATH_MAX);
862 name_len++; /* trailing null */
863 strncpy(pSMB->DirName, dirName, name_len);
864 }
865
866 pSMB->BufferFormat = 0x04;
867 pSMB->hdr.smb_buf_length += name_len + 1;
868 pSMB->ByteCount = cpu_to_le16(name_len + 1);
869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700871 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (rc) {
873 cFYI(1, ("Error in RMDir = %d", rc));
874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
876 cifs_buf_release(pSMB);
877 if (rc == -EAGAIN)
878 goto RmDirRetry;
879 return rc;
880}
881
882int
883CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700884 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
886 int rc = 0;
887 CREATE_DIRECTORY_REQ *pSMB = NULL;
888 CREATE_DIRECTORY_RSP *pSMBr = NULL;
889 int bytes_returned;
890 int name_len;
891
892 cFYI(1, ("In CIFSSMBMkDir"));
893MkDirRetry:
894 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
895 (void **) &pSMBr);
896 if (rc)
897 return rc;
898
899 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500900 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700901 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 name_len++; /* trailing null */
903 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700904 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 name_len = strnlen(name, PATH_MAX);
906 name_len++; /* trailing null */
907 strncpy(pSMB->DirName, name, name_len);
908 }
909
910 pSMB->BufferFormat = 0x04;
911 pSMB->hdr.smb_buf_length += name_len + 1;
912 pSMB->ByteCount = cpu_to_le16(name_len + 1);
913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700915 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 if (rc) {
917 cFYI(1, ("Error in Mkdir = %d", rc));
918 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 cifs_buf_release(pSMB);
921 if (rc == -EAGAIN)
922 goto MkDirRetry;
923 return rc;
924}
925
Steve French2dd29d32007-04-23 22:07:35 +0000926int
927CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
928 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
929 __u32 *pOplock, const char *name,
930 const struct nls_table *nls_codepage, int remap)
931{
932 TRANSACTION2_SPI_REQ *pSMB = NULL;
933 TRANSACTION2_SPI_RSP *pSMBr = NULL;
934 int name_len;
935 int rc = 0;
936 int bytes_returned = 0;
937 char *data_offset;
938 __u16 params, param_offset, offset, byte_count, count;
939 OPEN_PSX_REQ * pdata;
940 OPEN_PSX_RSP * psx_rsp;
941
942 cFYI(1, ("In POSIX Create"));
943PsxCreat:
944 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
945 (void **) &pSMBr);
946 if (rc)
947 return rc;
948
949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
950 name_len =
951 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
952 PATH_MAX, nls_codepage, remap);
953 name_len++; /* trailing null */
954 name_len *= 2;
955 } else { /* BB improve the check for buffer overruns BB */
956 name_len = strnlen(name, PATH_MAX);
957 name_len++; /* trailing null */
958 strncpy(pSMB->FileName, name, name_len);
959 }
960
961 params = 6 + name_len;
962 count = sizeof(OPEN_PSX_REQ);
963 pSMB->MaxParameterCount = cpu_to_le16(2);
964 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
965 pSMB->MaxSetupCount = 0;
966 pSMB->Reserved = 0;
967 pSMB->Flags = 0;
968 pSMB->Timeout = 0;
969 pSMB->Reserved2 = 0;
970 param_offset = offsetof(struct smb_com_transaction2_spi_req,
971 InformationLevel) - 4;
972 offset = param_offset + params;
973 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
974 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
975 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
976 pdata->Permissions = cpu_to_le64(mode);
977 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
978 pdata->OpenFlags = cpu_to_le32(*pOplock);
979 pSMB->ParameterOffset = cpu_to_le16(param_offset);
980 pSMB->DataOffset = cpu_to_le16(offset);
981 pSMB->SetupCount = 1;
982 pSMB->Reserved3 = 0;
983 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
984 byte_count = 3 /* pad */ + params + count;
985
986 pSMB->DataCount = cpu_to_le16(count);
987 pSMB->ParameterCount = cpu_to_le16(params);
988 pSMB->TotalDataCount = pSMB->DataCount;
989 pSMB->TotalParameterCount = pSMB->ParameterCount;
990 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
991 pSMB->Reserved4 = 0;
992 pSMB->hdr.smb_buf_length += byte_count;
993 pSMB->ByteCount = cpu_to_le16(byte_count);
994 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
995 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
996 if (rc) {
997 cFYI(1, ("Posix create returned %d", rc));
998 goto psx_create_err;
999 }
1000
1001 cFYI(1,("copying inode info"));
1002 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1003
1004 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1005 rc = -EIO; /* bad smb */
1006 goto psx_create_err;
1007 }
1008
1009 /* copy return information to pRetData */
1010 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1011 + le16_to_cpu(pSMBr->t2.DataOffset));
1012
1013 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1014 if(netfid)
1015 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1016 /* Let caller know file was created so we can set the mode. */
1017 /* Do we care about the CreateAction in any other cases? */
1018 if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1019 *pOplock |= CIFS_CREATE_ACTION;
1020 /* check to make sure response data is there */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001021 if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
1022 pRetData->Type = -1; /* unknown */
1023#ifdef CONFIG_CIFS_DEBUG2
1024 cFYI(1,("unknown type"));
1025#endif
1026 } else {
Steve French2dd29d32007-04-23 22:07:35 +00001027 if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1028 + sizeof(FILE_UNIX_BASIC_INFO)) {
1029 cERROR(1,("Open response data too small"));
1030 pRetData->Type = -1;
1031 goto psx_create_err;
1032 }
1033 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001034 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French2dd29d32007-04-23 22:07:35 +00001035 sizeof (FILE_UNIX_BASIC_INFO));
1036 }
1037
1038
1039psx_create_err:
1040 cifs_buf_release(pSMB);
1041
1042 cifs_stats_inc(&tcon->num_mkdirs);
1043
1044 if (rc == -EAGAIN)
1045 goto PsxCreat;
1046
1047 return rc;
1048}
1049
Steve Frencha9d02ad2005-08-24 23:06:05 -07001050static __u16 convert_disposition(int disposition)
1051{
1052 __u16 ofun = 0;
1053
1054 switch (disposition) {
1055 case FILE_SUPERSEDE:
1056 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1057 break;
1058 case FILE_OPEN:
1059 ofun = SMBOPEN_OAPPEND;
1060 break;
1061 case FILE_CREATE:
1062 ofun = SMBOPEN_OCREATE;
1063 break;
1064 case FILE_OPEN_IF:
1065 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1066 break;
1067 case FILE_OVERWRITE:
1068 ofun = SMBOPEN_OTRUNC;
1069 break;
1070 case FILE_OVERWRITE_IF:
1071 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1072 break;
1073 default:
1074 cFYI(1,("unknown disposition %d",disposition));
1075 ofun = SMBOPEN_OAPPEND; /* regular open */
1076 }
1077 return ofun;
1078}
1079
1080int
1081SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1082 const char *fileName, const int openDisposition,
1083 const int access_flags, const int create_options, __u16 * netfid,
1084 int *pOplock, FILE_ALL_INFO * pfile_info,
1085 const struct nls_table *nls_codepage, int remap)
1086{
1087 int rc = -EACCES;
1088 OPENX_REQ *pSMB = NULL;
1089 OPENX_RSP *pSMBr = NULL;
1090 int bytes_returned;
1091 int name_len;
1092 __u16 count;
1093
1094OldOpenRetry:
1095 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1096 (void **) &pSMBr);
1097 if (rc)
1098 return rc;
1099
1100 pSMB->AndXCommand = 0xFF; /* none */
1101
1102 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1103 count = 1; /* account for one byte pad to word boundary */
1104 name_len =
1105 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1106 fileName, PATH_MAX, nls_codepage, remap);
1107 name_len++; /* trailing null */
1108 name_len *= 2;
1109 } else { /* BB improve check for buffer overruns BB */
1110 count = 0; /* no pad */
1111 name_len = strnlen(fileName, PATH_MAX);
1112 name_len++; /* trailing null */
1113 strncpy(pSMB->fileName, fileName, name_len);
1114 }
1115 if (*pOplock & REQ_OPLOCK)
1116 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1117 else if (*pOplock & REQ_BATCHOPLOCK) {
1118 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1119 }
1120 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1121 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1122 /* 0 = read
1123 1 = write
1124 2 = rw
1125 3 = execute
1126 */
1127 pSMB->Mode = cpu_to_le16(2);
1128 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1129 /* set file as system file if special file such
1130 as fifo and server expecting SFU style and
1131 no Unix extensions */
1132
1133 if(create_options & CREATE_OPTION_SPECIAL)
1134 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1135 else
Steve French3e87d802005-09-18 20:49:21 -07001136 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001137
1138 /* if ((omode & S_IWUGO) == 0)
1139 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1140 /* Above line causes problems due to vfs splitting create into two
1141 pieces - need to set mode after file created not while it is
1142 being created */
1143
1144 /* BB FIXME BB */
1145/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
1146 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001147
1148 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001149 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001150 count += name_len;
1151 pSMB->hdr.smb_buf_length += count;
1152
1153 pSMB->ByteCount = cpu_to_le16(count);
1154 /* long_op set to 1 to allow for oplock break timeouts */
1155 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1156 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1157 cifs_stats_inc(&tcon->num_opens);
1158 if (rc) {
1159 cFYI(1, ("Error in Open = %d", rc));
1160 } else {
1161 /* BB verify if wct == 15 */
1162
1163/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1164
1165 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1166 /* Let caller know file was created so we can set the mode. */
1167 /* Do we care about the CreateAction in any other cases? */
1168 /* BB FIXME BB */
1169/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1170 *pOplock |= CIFS_CREATE_ACTION; */
1171 /* BB FIXME END */
1172
1173 if(pfile_info) {
1174 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1175 pfile_info->LastAccessTime = 0; /* BB fixme */
1176 pfile_info->LastWriteTime = 0; /* BB fixme */
1177 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001178 pfile_info->Attributes =
1179 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001181 pfile_info->AllocationSize =
1182 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1183 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001184 pfile_info->NumberOfLinks = cpu_to_le32(1);
1185 }
1186 }
1187
1188 cifs_buf_release(pSMB);
1189 if (rc == -EAGAIN)
1190 goto OldOpenRetry;
1191 return rc;
1192}
1193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194int
1195CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1196 const char *fileName, const int openDisposition,
1197 const int access_flags, const int create_options, __u16 * netfid,
1198 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001199 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
1201 int rc = -EACCES;
1202 OPEN_REQ *pSMB = NULL;
1203 OPEN_RSP *pSMBr = NULL;
1204 int bytes_returned;
1205 int name_len;
1206 __u16 count;
1207
1208openRetry:
1209 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1210 (void **) &pSMBr);
1211 if (rc)
1212 return rc;
1213
1214 pSMB->AndXCommand = 0xFF; /* none */
1215
1216 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1217 count = 1; /* account for one byte pad to word boundary */
1218 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001219 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001220 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 name_len++; /* trailing null */
1222 name_len *= 2;
1223 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001224 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 count = 0; /* no pad */
1226 name_len = strnlen(fileName, PATH_MAX);
1227 name_len++; /* trailing null */
1228 pSMB->NameLength = cpu_to_le16(name_len);
1229 strncpy(pSMB->fileName, fileName, name_len);
1230 }
1231 if (*pOplock & REQ_OPLOCK)
1232 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1233 else if (*pOplock & REQ_BATCHOPLOCK) {
1234 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1235 }
1236 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1237 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001238 /* set file as system file if special file such
1239 as fifo and server expecting SFU style and
1240 no Unix extensions */
1241 if(create_options & CREATE_OPTION_SPECIAL)
1242 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1243 else
1244 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 /* XP does not handle ATTR_POSIX_SEMANTICS */
1246 /* but it helps speed up case sensitive checks for other
1247 servers such as Samba */
1248 if (tcon->ses->capabilities & CAP_UNIX)
1249 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1250
1251 /* if ((omode & S_IWUGO) == 0)
1252 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1253 /* Above line causes problems due to vfs splitting create into two
1254 pieces - need to set mode after file created not while it is
1255 being created */
1256 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1257 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001258 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001259 /* BB Expirement with various impersonation levels and verify */
1260 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 pSMB->SecurityFlags =
1262 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1263
1264 count += name_len;
1265 pSMB->hdr.smb_buf_length += count;
1266
1267 pSMB->ByteCount = cpu_to_le16(count);
1268 /* long_op set to 1 to allow for oplock break timeouts */
1269 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1270 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001271 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 if (rc) {
1273 cFYI(1, ("Error in Open = %d", rc));
1274 } else {
Steve French09d1db52005-04-28 22:41:08 -07001275 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1277 /* Let caller know file was created so we can set the mode. */
1278 /* Do we care about the CreateAction in any other cases? */
1279 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1280 *pOplock |= CIFS_CREATE_ACTION;
1281 if(pfile_info) {
1282 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1283 36 /* CreationTime to Attributes */);
1284 /* the file_info buf is endian converted by caller */
1285 pfile_info->AllocationSize = pSMBr->AllocationSize;
1286 pfile_info->EndOfFile = pSMBr->EndOfFile;
1287 pfile_info->NumberOfLinks = cpu_to_le32(1);
1288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001290
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 cifs_buf_release(pSMB);
1292 if (rc == -EAGAIN)
1293 goto openRetry;
1294 return rc;
1295}
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297int
1298CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001299 const int netfid, const unsigned int count,
1300 const __u64 lseek, unsigned int *nbytes, char **buf,
1301 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
1303 int rc = -EACCES;
1304 READ_REQ *pSMB = NULL;
1305 READ_RSP *pSMBr = NULL;
1306 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001307 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001308 int resp_buf_type = 0;
1309 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
1311 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001312 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1313 wct = 12;
1314 else
1315 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
1317 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001318 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (rc)
1320 return rc;
1321
1322 /* tcon and ses pointer are checked in smb_init */
1323 if (tcon->ses->server == NULL)
1324 return -ECONNABORTED;
1325
Steve Frenchec637e32005-12-12 20:53:18 -08001326 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 pSMB->Fid = netfid;
1328 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001329 if(wct == 12)
1330 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001331 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1332 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001333
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 pSMB->Remaining = 0;
1335 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1336 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001337 if(wct == 12)
1338 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1339 else {
1340 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001341 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001342 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001343 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001344 }
Steve Frenchec637e32005-12-12 20:53:18 -08001345
1346 iov[0].iov_base = (char *)pSMB;
1347 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1348 rc = SendReceive2(xid, tcon->ses, iov,
1349 1 /* num iovecs */,
1350 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001351 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001352 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 if (rc) {
1354 cERROR(1, ("Send error in read = %d", rc));
1355 } else {
1356 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1357 data_length = data_length << 16;
1358 data_length += le16_to_cpu(pSMBr->DataLength);
1359 *nbytes = data_length;
1360
1361 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001362 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 || (data_length > count)) {
1364 cFYI(1,("bad length %d for count %d",data_length,count));
1365 rc = -EIO;
1366 *nbytes = 0;
1367 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001368 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001370/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1371 cERROR(1,("Faulting on read rc = %d",rc));
1372 rc = -EFAULT;
1373 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001375 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
1377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Steve French4b8f9302006-02-26 16:41:18 +00001379/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001380 if(*buf) {
1381 if(resp_buf_type == CIFS_SMALL_BUFFER)
1382 cifs_small_buf_release(iov[0].iov_base);
1383 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1384 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001385 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1386 /* return buffer to caller to free */
1387 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001388 if(resp_buf_type == CIFS_SMALL_BUFFER)
1389 *pbuf_type = CIFS_SMALL_BUFFER;
1390 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1391 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001392 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001393
1394 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 since file handle passed in no longer valid */
1396 return rc;
1397}
1398
Steve Frenchec637e32005-12-12 20:53:18 -08001399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400int
1401CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1402 const int netfid, const unsigned int count,
1403 const __u64 offset, unsigned int *nbytes, const char *buf,
1404 const char __user * ubuf, const int long_op)
1405{
1406 int rc = -EACCES;
1407 WRITE_REQ *pSMB = NULL;
1408 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001409 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 __u32 bytes_sent;
1411 __u16 byte_count;
1412
1413 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001414 if(tcon->ses == NULL)
1415 return -ECONNABORTED;
1416
1417 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1418 wct = 14;
1419 else
1420 wct = 12;
1421
1422 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 (void **) &pSMBr);
1424 if (rc)
1425 return rc;
1426 /* tcon and ses pointer are checked in smb_init */
1427 if (tcon->ses->server == NULL)
1428 return -ECONNABORTED;
1429
1430 pSMB->AndXCommand = 0xFF; /* none */
1431 pSMB->Fid = netfid;
1432 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001433 if(wct == 14)
1434 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1435 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1436 return -EIO;
1437
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 pSMB->Reserved = 0xFFFFFFFF;
1439 pSMB->WriteMode = 0;
1440 pSMB->Remaining = 0;
1441
1442 /* Can increase buffer size if buffer is big enough in some cases - ie we
1443 can send more if LARGE_WRITE_X capability returned by the server and if
1444 our buffer is big enough or if we convert to iovecs on socket writes
1445 and eliminate the copy to the CIFS buffer */
1446 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1447 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1448 } else {
1449 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1450 & ~0xFF;
1451 }
1452
1453 if (bytes_sent > count)
1454 bytes_sent = count;
1455 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001456 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 if(buf)
1458 memcpy(pSMB->Data,buf,bytes_sent);
1459 else if(ubuf) {
1460 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1461 cifs_buf_release(pSMB);
1462 return -EFAULT;
1463 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001464 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 /* No buffer */
1466 cifs_buf_release(pSMB);
1467 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001468 } /* else setting file size with write of zero bytes */
1469 if(wct == 14)
1470 byte_count = bytes_sent + 1; /* pad */
1471 else /* wct == 12 */ {
1472 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1475 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001476 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001477
1478 if(wct == 14)
1479 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001480 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001481 struct smb_com_writex_req * pSMBW =
1482 (struct smb_com_writex_req *)pSMB;
1483 pSMBW->ByteCount = cpu_to_le16(byte_count);
1484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
1486 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1487 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001488 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (rc) {
1490 cFYI(1, ("Send error in write = %d", rc));
1491 *nbytes = 0;
1492 } else {
1493 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1494 *nbytes = (*nbytes) << 16;
1495 *nbytes += le16_to_cpu(pSMBr->Count);
1496 }
1497
1498 cifs_buf_release(pSMB);
1499
1500 /* Note: On -EAGAIN error only caller can retry on handle based calls
1501 since file handle passed in no longer valid */
1502
1503 return rc;
1504}
1505
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001506int
1507CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001509 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1510 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
1512 int rc = -EACCES;
1513 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001514 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001515 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001516 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
Steve Frenchff7feac2005-11-15 16:45:16 -08001518 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1519
Steve French8cc64c62005-10-03 13:49:43 -07001520 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1521 wct = 14;
1522 else
1523 wct = 12;
1524 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 if (rc)
1526 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 /* tcon and ses pointer are checked in smb_init */
1528 if (tcon->ses->server == NULL)
1529 return -ECONNABORTED;
1530
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001531 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 pSMB->Fid = netfid;
1533 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001534 if(wct == 14)
1535 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1536 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1537 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 pSMB->Reserved = 0xFFFFFFFF;
1539 pSMB->WriteMode = 0;
1540 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 pSMB->DataOffset =
1543 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1544
Steve French3e844692005-10-03 13:37:24 -07001545 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1546 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001547 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001548 if(wct == 14)
1549 pSMB->hdr.smb_buf_length += count+1;
1550 else /* wct == 12 */
1551 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1552 if(wct == 14)
1553 pSMB->ByteCount = cpu_to_le16(count + 1);
1554 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1555 struct smb_com_writex_req * pSMBW =
1556 (struct smb_com_writex_req *)pSMB;
1557 pSMBW->ByteCount = cpu_to_le16(count + 5);
1558 }
Steve French3e844692005-10-03 13:37:24 -07001559 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001560 if(wct == 14)
1561 iov[0].iov_len = smb_hdr_len + 4;
1562 else /* wct == 12 pad bigger by four bytes */
1563 iov[0].iov_len = smb_hdr_len + 8;
1564
Steve French3e844692005-10-03 13:37:24 -07001565
Steve Frenchec637e32005-12-12 20:53:18 -08001566 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001567 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001568 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001570 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001572 } else if(resp_buf_type == 0) {
1573 /* presumably this can not happen, but best to be safe */
1574 rc = -EIO;
1575 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001576 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001577 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001578 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1579 *nbytes = (*nbytes) << 16;
1580 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Steve French4b8f9302006-02-26 16:41:18 +00001583/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001584 if(resp_buf_type == CIFS_SMALL_BUFFER)
1585 cifs_small_buf_release(iov[0].iov_base);
1586 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1587 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589 /* Note: On -EAGAIN error only caller can retry on handle based calls
1590 since file handle passed in no longer valid */
1591
1592 return rc;
1593}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001594
1595
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596int
1597CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1598 const __u16 smb_file_id, const __u64 len,
1599 const __u64 offset, const __u32 numUnlock,
1600 const __u32 numLock, const __u8 lockType, const int waitFlag)
1601{
1602 int rc = 0;
1603 LOCK_REQ *pSMB = NULL;
1604 LOCK_RSP *pSMBr = NULL;
1605 int bytes_returned;
1606 int timeout = 0;
1607 __u16 count;
1608
1609 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001610 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 if (rc)
1613 return rc;
1614
Steve French46810cb2005-04-28 22:41:09 -07001615 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1616
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1618 timeout = -1; /* no response expected */
1619 pSMB->Timeout = 0;
1620 } else if (waitFlag == TRUE) {
1621 timeout = 3; /* blocking operation, no timeout */
1622 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1623 } else {
1624 pSMB->Timeout = 0;
1625 }
1626
1627 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1628 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1629 pSMB->LockType = lockType;
1630 pSMB->AndXCommand = 0xFF; /* none */
1631 pSMB->Fid = smb_file_id; /* netfid stays le */
1632
1633 if((numLock != 0) || (numUnlock != 0)) {
1634 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1635 /* BB where to store pid high? */
1636 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1637 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1638 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1639 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1640 count = sizeof(LOCKING_ANDX_RANGE);
1641 } else {
1642 /* oplock break */
1643 count = 0;
1644 }
1645 pSMB->hdr.smb_buf_length += count;
1646 pSMB->ByteCount = cpu_to_le16(count);
1647
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001648 if (waitFlag) {
1649 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1650 (struct smb_hdr *) pSMBr, &bytes_returned);
1651 } else {
1652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001654 }
Steve Frencha4544342005-08-24 13:59:35 -07001655 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 if (rc) {
1657 cFYI(1, ("Send error in Lock = %d", rc));
1658 }
Steve French46810cb2005-04-28 22:41:09 -07001659 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661 /* Note: On -EAGAIN error only caller can retry on handle based calls
1662 since file handle passed in no longer valid */
1663 return rc;
1664}
1665
1666int
Steve French08547b02006-02-28 22:39:25 +00001667CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1668 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001669 struct file_lock *pLockData, const __u16 lock_type,
1670 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001671{
1672 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1673 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1674 char *data_offset;
1675 struct cifs_posix_lock *parm_data;
1676 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001677 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001678 int bytes_returned = 0;
1679 __u16 params, param_offset, offset, byte_count, count;
1680
1681 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001682
1683 if(pLockData == NULL)
1684 return EINVAL;
1685
Steve French08547b02006-02-28 22:39:25 +00001686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1687
1688 if (rc)
1689 return rc;
1690
1691 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1692
1693 params = 6;
1694 pSMB->MaxSetupCount = 0;
1695 pSMB->Reserved = 0;
1696 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001697 pSMB->Reserved2 = 0;
1698 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1699 offset = param_offset + params;
1700
1701 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1702
1703 count = sizeof(struct cifs_posix_lock);
1704 pSMB->MaxParameterCount = cpu_to_le16(2);
1705 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1706 pSMB->SetupCount = 1;
1707 pSMB->Reserved3 = 0;
1708 if(get_flag)
1709 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1710 else
1711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1712 byte_count = 3 /* pad */ + params + count;
1713 pSMB->DataCount = cpu_to_le16(count);
1714 pSMB->ParameterCount = cpu_to_le16(params);
1715 pSMB->TotalDataCount = pSMB->DataCount;
1716 pSMB->TotalParameterCount = pSMB->ParameterCount;
1717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1718 parm_data = (struct cifs_posix_lock *)
1719 (((char *) &pSMB->hdr.Protocol) + offset);
1720
1721 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001722 if(waitFlag) {
1723 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001724 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001725 pSMB->Timeout = cpu_to_le32(-1);
1726 } else
1727 pSMB->Timeout = 0;
1728
Steve French08547b02006-02-28 22:39:25 +00001729 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001730 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001731 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001732
1733 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001734 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001735 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1736 pSMB->Reserved4 = 0;
1737 pSMB->hdr.smb_buf_length += byte_count;
1738 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001739 if (waitFlag) {
1740 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1741 (struct smb_hdr *) pSMBr, &bytes_returned);
1742 } else {
1743 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001744 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001745 }
1746
Steve French08547b02006-02-28 22:39:25 +00001747 if (rc) {
1748 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001749 } else if (get_flag) {
1750 /* lock structure can be returned on get */
1751 __u16 data_offset;
1752 __u16 data_count;
1753 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001754
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001755 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1756 rc = -EIO; /* bad smb */
1757 goto plk_err_exit;
1758 }
1759 if(pLockData == NULL) {
1760 rc = -EINVAL;
1761 goto plk_err_exit;
1762 }
1763 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1764 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1765 if(data_count < sizeof(struct cifs_posix_lock)) {
1766 rc = -EIO;
1767 goto plk_err_exit;
1768 }
1769 parm_data = (struct cifs_posix_lock *)
1770 ((char *)&pSMBr->hdr.Protocol + data_offset);
1771 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1772 pLockData->fl_type = F_UNLCK;
1773 }
1774
1775plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001776 if (pSMB)
1777 cifs_small_buf_release(pSMB);
1778
1779 /* Note: On -EAGAIN error only caller can retry on handle based calls
1780 since file handle passed in no longer valid */
1781
1782 return rc;
1783}
1784
1785
1786int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1788{
1789 int rc = 0;
1790 CLOSE_REQ *pSMB = NULL;
1791 CLOSE_RSP *pSMBr = NULL;
1792 int bytes_returned;
1793 cFYI(1, ("In CIFSSMBClose"));
1794
1795/* do not retry on dead session on close */
1796 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1797 if(rc == -EAGAIN)
1798 return 0;
1799 if (rc)
1800 return rc;
1801
1802 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1803
1804 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001805 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 pSMB->ByteCount = 0;
1807 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1808 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001809 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 if (rc) {
1811 if(rc!=-EINTR) {
1812 /* EINTR is expected when user ctl-c to kill app */
1813 cERROR(1, ("Send error in Close = %d", rc));
1814 }
1815 }
1816
1817 cifs_small_buf_release(pSMB);
1818
1819 /* Since session is dead, file will be closed on server already */
1820 if(rc == -EAGAIN)
1821 rc = 0;
1822
1823 return rc;
1824}
1825
1826int
1827CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1828 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001829 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830{
1831 int rc = 0;
1832 RENAME_REQ *pSMB = NULL;
1833 RENAME_RSP *pSMBr = NULL;
1834 int bytes_returned;
1835 int name_len, name_len2;
1836 __u16 count;
1837
1838 cFYI(1, ("In CIFSSMBRename"));
1839renameRetry:
1840 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1841 (void **) &pSMBr);
1842 if (rc)
1843 return rc;
1844
1845 pSMB->BufferFormat = 0x04;
1846 pSMB->SearchAttributes =
1847 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1848 ATTR_DIRECTORY);
1849
1850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1851 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001852 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001853 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 name_len++; /* trailing null */
1855 name_len *= 2;
1856 pSMB->OldFileName[name_len] = 0x04; /* pad */
1857 /* protocol requires ASCII signature byte on Unicode string */
1858 pSMB->OldFileName[name_len + 1] = 0x00;
1859 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001860 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001861 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1863 name_len2 *= 2; /* convert to bytes */
1864 } else { /* BB improve the check for buffer overruns BB */
1865 name_len = strnlen(fromName, PATH_MAX);
1866 name_len++; /* trailing null */
1867 strncpy(pSMB->OldFileName, fromName, name_len);
1868 name_len2 = strnlen(toName, PATH_MAX);
1869 name_len2++; /* trailing null */
1870 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1871 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1872 name_len2++; /* trailing null */
1873 name_len2++; /* signature byte */
1874 }
1875
1876 count = 1 /* 1st signature byte */ + name_len + name_len2;
1877 pSMB->hdr.smb_buf_length += count;
1878 pSMB->ByteCount = cpu_to_le16(count);
1879
1880 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1881 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001882 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (rc) {
1884 cFYI(1, ("Send error in rename = %d", rc));
1885 }
1886
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 cifs_buf_release(pSMB);
1888
1889 if (rc == -EAGAIN)
1890 goto renameRetry;
1891
1892 return rc;
1893}
1894
1895int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001896 int netfid, char * target_name,
1897 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898{
1899 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1900 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1901 struct set_file_rename * rename_info;
1902 char *data_offset;
1903 char dummy_string[30];
1904 int rc = 0;
1905 int bytes_returned = 0;
1906 int len_of_str;
1907 __u16 params, param_offset, offset, count, byte_count;
1908
1909 cFYI(1, ("Rename to File by handle"));
1910 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1911 (void **) &pSMBr);
1912 if (rc)
1913 return rc;
1914
1915 params = 6;
1916 pSMB->MaxSetupCount = 0;
1917 pSMB->Reserved = 0;
1918 pSMB->Flags = 0;
1919 pSMB->Timeout = 0;
1920 pSMB->Reserved2 = 0;
1921 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1922 offset = param_offset + params;
1923
1924 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1925 rename_info = (struct set_file_rename *) data_offset;
1926 pSMB->MaxParameterCount = cpu_to_le16(2);
1927 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1928 pSMB->SetupCount = 1;
1929 pSMB->Reserved3 = 0;
1930 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1931 byte_count = 3 /* pad */ + params;
1932 pSMB->ParameterCount = cpu_to_le16(params);
1933 pSMB->TotalParameterCount = pSMB->ParameterCount;
1934 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1935 pSMB->DataOffset = cpu_to_le16(offset);
1936 /* construct random name ".cifs_tmp<inodenum><mid>" */
1937 rename_info->overwrite = cpu_to_le32(1);
1938 rename_info->root_fid = 0;
1939 /* unicode only call */
1940 if(target_name == NULL) {
1941 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001942 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001943 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001945 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001946 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 }
1948 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1949 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1950 byte_count += count;
1951 pSMB->DataCount = cpu_to_le16(count);
1952 pSMB->TotalDataCount = pSMB->DataCount;
1953 pSMB->Fid = netfid;
1954 pSMB->InformationLevel =
1955 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1956 pSMB->Reserved4 = 0;
1957 pSMB->hdr.smb_buf_length += byte_count;
1958 pSMB->ByteCount = cpu_to_le16(byte_count);
1959 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001961 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 if (rc) {
1963 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1964 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 cifs_buf_release(pSMB);
1967
1968 /* Note: On -EAGAIN error only caller can retry on handle based calls
1969 since file handle passed in no longer valid */
1970
1971 return rc;
1972}
1973
1974int
1975CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1976 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001977 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978{
1979 int rc = 0;
1980 COPY_REQ *pSMB = NULL;
1981 COPY_RSP *pSMBr = NULL;
1982 int bytes_returned;
1983 int name_len, name_len2;
1984 __u16 count;
1985
1986 cFYI(1, ("In CIFSSMBCopy"));
1987copyRetry:
1988 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1989 (void **) &pSMBr);
1990 if (rc)
1991 return rc;
1992
1993 pSMB->BufferFormat = 0x04;
1994 pSMB->Tid2 = target_tid;
1995
1996 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1997
1998 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001999 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002000 fromName, PATH_MAX, nls_codepage,
2001 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 name_len++; /* trailing null */
2003 name_len *= 2;
2004 pSMB->OldFileName[name_len] = 0x04; /* pad */
2005 /* protocol requires ASCII signature byte on Unicode string */
2006 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05002007 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002008 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2010 name_len2 *= 2; /* convert to bytes */
2011 } else { /* BB improve the check for buffer overruns BB */
2012 name_len = strnlen(fromName, PATH_MAX);
2013 name_len++; /* trailing null */
2014 strncpy(pSMB->OldFileName, fromName, name_len);
2015 name_len2 = strnlen(toName, PATH_MAX);
2016 name_len2++; /* trailing null */
2017 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2018 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2019 name_len2++; /* trailing null */
2020 name_len2++; /* signature byte */
2021 }
2022
2023 count = 1 /* 1st signature byte */ + name_len + name_len2;
2024 pSMB->hdr.smb_buf_length += count;
2025 pSMB->ByteCount = cpu_to_le16(count);
2026
2027 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2029 if (rc) {
2030 cFYI(1, ("Send error in copy = %d with %d files copied",
2031 rc, le16_to_cpu(pSMBr->CopyCount)));
2032 }
2033 if (pSMB)
2034 cifs_buf_release(pSMB);
2035
2036 if (rc == -EAGAIN)
2037 goto copyRetry;
2038
2039 return rc;
2040}
2041
2042int
2043CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2044 const char *fromName, const char *toName,
2045 const struct nls_table *nls_codepage)
2046{
2047 TRANSACTION2_SPI_REQ *pSMB = NULL;
2048 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2049 char *data_offset;
2050 int name_len;
2051 int name_len_target;
2052 int rc = 0;
2053 int bytes_returned = 0;
2054 __u16 params, param_offset, offset, byte_count;
2055
2056 cFYI(1, ("In Symlink Unix style"));
2057createSymLinkRetry:
2058 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2059 (void **) &pSMBr);
2060 if (rc)
2061 return rc;
2062
2063 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2064 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002065 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 /* find define for this maxpathcomponent */
2067 , nls_codepage);
2068 name_len++; /* trailing null */
2069 name_len *= 2;
2070
2071 } else { /* BB improve the check for buffer overruns BB */
2072 name_len = strnlen(fromName, PATH_MAX);
2073 name_len++; /* trailing null */
2074 strncpy(pSMB->FileName, fromName, name_len);
2075 }
2076 params = 6 + name_len;
2077 pSMB->MaxSetupCount = 0;
2078 pSMB->Reserved = 0;
2079 pSMB->Flags = 0;
2080 pSMB->Timeout = 0;
2081 pSMB->Reserved2 = 0;
2082 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2083 InformationLevel) - 4;
2084 offset = param_offset + params;
2085
2086 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2087 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2088 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002089 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 /* find define for this maxpathcomponent */
2091 , nls_codepage);
2092 name_len_target++; /* trailing null */
2093 name_len_target *= 2;
2094 } else { /* BB improve the check for buffer overruns BB */
2095 name_len_target = strnlen(toName, PATH_MAX);
2096 name_len_target++; /* trailing null */
2097 strncpy(data_offset, toName, name_len_target);
2098 }
2099
2100 pSMB->MaxParameterCount = cpu_to_le16(2);
2101 /* BB find exact max on data count below from sess */
2102 pSMB->MaxDataCount = cpu_to_le16(1000);
2103 pSMB->SetupCount = 1;
2104 pSMB->Reserved3 = 0;
2105 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2106 byte_count = 3 /* pad */ + params + name_len_target;
2107 pSMB->DataCount = cpu_to_le16(name_len_target);
2108 pSMB->ParameterCount = cpu_to_le16(params);
2109 pSMB->TotalDataCount = pSMB->DataCount;
2110 pSMB->TotalParameterCount = pSMB->ParameterCount;
2111 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2112 pSMB->DataOffset = cpu_to_le16(offset);
2113 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2114 pSMB->Reserved4 = 0;
2115 pSMB->hdr.smb_buf_length += byte_count;
2116 pSMB->ByteCount = cpu_to_le16(byte_count);
2117 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002119 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 if (rc) {
2121 cFYI(1,
2122 ("Send error in SetPathInfo (create symlink) = %d",
2123 rc));
2124 }
2125
2126 if (pSMB)
2127 cifs_buf_release(pSMB);
2128
2129 if (rc == -EAGAIN)
2130 goto createSymLinkRetry;
2131
2132 return rc;
2133}
2134
2135int
2136CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2137 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002138 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139{
2140 TRANSACTION2_SPI_REQ *pSMB = NULL;
2141 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2142 char *data_offset;
2143 int name_len;
2144 int name_len_target;
2145 int rc = 0;
2146 int bytes_returned = 0;
2147 __u16 params, param_offset, offset, byte_count;
2148
2149 cFYI(1, ("In Create Hard link Unix style"));
2150createHardLinkRetry:
2151 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2152 (void **) &pSMBr);
2153 if (rc)
2154 return rc;
2155
2156 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002157 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002158 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 name_len++; /* trailing null */
2160 name_len *= 2;
2161
2162 } else { /* BB improve the check for buffer overruns BB */
2163 name_len = strnlen(toName, PATH_MAX);
2164 name_len++; /* trailing null */
2165 strncpy(pSMB->FileName, toName, name_len);
2166 }
2167 params = 6 + name_len;
2168 pSMB->MaxSetupCount = 0;
2169 pSMB->Reserved = 0;
2170 pSMB->Flags = 0;
2171 pSMB->Timeout = 0;
2172 pSMB->Reserved2 = 0;
2173 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2174 InformationLevel) - 4;
2175 offset = param_offset + params;
2176
2177 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2178 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2179 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002180 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002181 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 name_len_target++; /* trailing null */
2183 name_len_target *= 2;
2184 } else { /* BB improve the check for buffer overruns BB */
2185 name_len_target = strnlen(fromName, PATH_MAX);
2186 name_len_target++; /* trailing null */
2187 strncpy(data_offset, fromName, name_len_target);
2188 }
2189
2190 pSMB->MaxParameterCount = cpu_to_le16(2);
2191 /* BB find exact max on data count below from sess*/
2192 pSMB->MaxDataCount = cpu_to_le16(1000);
2193 pSMB->SetupCount = 1;
2194 pSMB->Reserved3 = 0;
2195 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2196 byte_count = 3 /* pad */ + params + name_len_target;
2197 pSMB->ParameterCount = cpu_to_le16(params);
2198 pSMB->TotalParameterCount = pSMB->ParameterCount;
2199 pSMB->DataCount = cpu_to_le16(name_len_target);
2200 pSMB->TotalDataCount = pSMB->DataCount;
2201 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2202 pSMB->DataOffset = cpu_to_le16(offset);
2203 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2204 pSMB->Reserved4 = 0;
2205 pSMB->hdr.smb_buf_length += byte_count;
2206 pSMB->ByteCount = cpu_to_le16(byte_count);
2207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002209 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 if (rc) {
2211 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2212 }
2213
2214 cifs_buf_release(pSMB);
2215 if (rc == -EAGAIN)
2216 goto createHardLinkRetry;
2217
2218 return rc;
2219}
2220
2221int
2222CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2223 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002224 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225{
2226 int rc = 0;
2227 NT_RENAME_REQ *pSMB = NULL;
2228 RENAME_RSP *pSMBr = NULL;
2229 int bytes_returned;
2230 int name_len, name_len2;
2231 __u16 count;
2232
2233 cFYI(1, ("In CIFSCreateHardLink"));
2234winCreateHardLinkRetry:
2235
2236 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2237 (void **) &pSMBr);
2238 if (rc)
2239 return rc;
2240
2241 pSMB->SearchAttributes =
2242 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2243 ATTR_DIRECTORY);
2244 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2245 pSMB->ClusterCount = 0;
2246
2247 pSMB->BufferFormat = 0x04;
2248
2249 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2250 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002251 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002252 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 name_len++; /* trailing null */
2254 name_len *= 2;
2255 pSMB->OldFileName[name_len] = 0; /* pad */
2256 pSMB->OldFileName[name_len + 1] = 0x04;
2257 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002258 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002259 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2261 name_len2 *= 2; /* convert to bytes */
2262 } else { /* BB improve the check for buffer overruns BB */
2263 name_len = strnlen(fromName, PATH_MAX);
2264 name_len++; /* trailing null */
2265 strncpy(pSMB->OldFileName, fromName, name_len);
2266 name_len2 = strnlen(toName, PATH_MAX);
2267 name_len2++; /* trailing null */
2268 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2269 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2270 name_len2++; /* trailing null */
2271 name_len2++; /* signature byte */
2272 }
2273
2274 count = 1 /* string type byte */ + name_len + name_len2;
2275 pSMB->hdr.smb_buf_length += count;
2276 pSMB->ByteCount = cpu_to_le16(count);
2277
2278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2279 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002280 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 if (rc) {
2282 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2283 }
2284 cifs_buf_release(pSMB);
2285 if (rc == -EAGAIN)
2286 goto winCreateHardLinkRetry;
2287
2288 return rc;
2289}
2290
2291int
2292CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2293 const unsigned char *searchName,
2294 char *symlinkinfo, const int buflen,
2295 const struct nls_table *nls_codepage)
2296{
2297/* SMB_QUERY_FILE_UNIX_LINK */
2298 TRANSACTION2_QPI_REQ *pSMB = NULL;
2299 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2300 int rc = 0;
2301 int bytes_returned;
2302 int name_len;
2303 __u16 params, byte_count;
2304
2305 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2306
2307querySymLinkRetry:
2308 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2309 (void **) &pSMBr);
2310 if (rc)
2311 return rc;
2312
2313 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2314 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002315 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 /* find define for this maxpathcomponent */
2317 , nls_codepage);
2318 name_len++; /* trailing null */
2319 name_len *= 2;
2320 } else { /* BB improve the check for buffer overruns BB */
2321 name_len = strnlen(searchName, PATH_MAX);
2322 name_len++; /* trailing null */
2323 strncpy(pSMB->FileName, searchName, name_len);
2324 }
2325
2326 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2327 pSMB->TotalDataCount = 0;
2328 pSMB->MaxParameterCount = cpu_to_le16(2);
2329 /* BB find exact max data count below from sess structure BB */
2330 pSMB->MaxDataCount = cpu_to_le16(4000);
2331 pSMB->MaxSetupCount = 0;
2332 pSMB->Reserved = 0;
2333 pSMB->Flags = 0;
2334 pSMB->Timeout = 0;
2335 pSMB->Reserved2 = 0;
2336 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2337 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2338 pSMB->DataCount = 0;
2339 pSMB->DataOffset = 0;
2340 pSMB->SetupCount = 1;
2341 pSMB->Reserved3 = 0;
2342 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2343 byte_count = params + 1 /* pad */ ;
2344 pSMB->TotalParameterCount = cpu_to_le16(params);
2345 pSMB->ParameterCount = pSMB->TotalParameterCount;
2346 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2347 pSMB->Reserved4 = 0;
2348 pSMB->hdr.smb_buf_length += byte_count;
2349 pSMB->ByteCount = cpu_to_le16(byte_count);
2350
2351 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2352 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2353 if (rc) {
2354 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2355 } else {
2356 /* decode response */
2357
2358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2359 if (rc || (pSMBr->ByteCount < 2))
2360 /* BB also check enough total bytes returned */
2361 rc = -EIO; /* bad smb */
2362 else {
2363 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2364 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2365
2366 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2367 name_len = UniStrnlen((wchar_t *) ((char *)
2368 &pSMBr->hdr.Protocol +data_offset),
2369 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002370 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002372 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 data_offset),
2374 name_len, nls_codepage);
2375 } else {
2376 strncpy(symlinkinfo,
2377 (char *) &pSMBr->hdr.Protocol +
2378 data_offset,
2379 min_t(const int, buflen, count));
2380 }
2381 symlinkinfo[buflen] = 0;
2382 /* just in case so calling code does not go off the end of buffer */
2383 }
2384 }
2385 cifs_buf_release(pSMB);
2386 if (rc == -EAGAIN)
2387 goto querySymLinkRetry;
2388 return rc;
2389}
2390
Steve French0a4b92c2006-01-12 15:44:21 -08002391/* Initialize NT TRANSACT SMB into small smb request buffer.
2392 This assumes that all NT TRANSACTS that we init here have
2393 total parm and data under about 400 bytes (to fit in small cifs
2394 buffer size), which is the case so far, it easily fits. NB:
2395 Setup words themselves and ByteCount
2396 MaxSetupCount (size of returned setup area) and
2397 MaxParameterCount (returned parms size) must be set by caller */
2398static int
2399smb_init_ntransact(const __u16 sub_command, const int setup_count,
2400 const int parm_len, struct cifsTconInfo *tcon,
2401 void ** ret_buf)
2402{
2403 int rc;
2404 __u32 temp_offset;
2405 struct smb_com_ntransact_req * pSMB;
2406
2407 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2408 (void **)&pSMB);
2409 if (rc)
2410 return rc;
2411 *ret_buf = (void *)pSMB;
2412 pSMB->Reserved = 0;
2413 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2414 pSMB->TotalDataCount = 0;
2415 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2416 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2417 pSMB->ParameterCount = pSMB->TotalParameterCount;
2418 pSMB->DataCount = pSMB->TotalDataCount;
2419 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2420 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2421 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2422 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2423 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2424 pSMB->SubCommand = cpu_to_le16(sub_command);
2425 return 0;
2426}
2427
2428static int
2429validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2430 int * pdatalen, int * pparmlen)
2431{
2432 char * end_of_smb;
2433 __u32 data_count, data_offset, parm_count, parm_offset;
2434 struct smb_com_ntransact_rsp * pSMBr;
2435
2436 if(buf == NULL)
2437 return -EINVAL;
2438
2439 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2440
2441 /* ByteCount was converted from little endian in SendReceive */
2442 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2443 (char *)&pSMBr->ByteCount;
2444
2445
2446 data_offset = le32_to_cpu(pSMBr->DataOffset);
2447 data_count = le32_to_cpu(pSMBr->DataCount);
2448 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2449 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2450
2451 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2452 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2453
2454 /* should we also check that parm and data areas do not overlap? */
2455 if(*ppparm > end_of_smb) {
2456 cFYI(1,("parms start after end of smb"));
2457 return -EINVAL;
2458 } else if(parm_count + *ppparm > end_of_smb) {
2459 cFYI(1,("parm end after end of smb"));
2460 return -EINVAL;
2461 } else if(*ppdata > end_of_smb) {
2462 cFYI(1,("data starts after end of smb"));
2463 return -EINVAL;
2464 } else if(data_count + *ppdata > end_of_smb) {
2465 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2466 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2467 return -EINVAL;
2468 } else if(parm_count + data_count > pSMBr->ByteCount) {
2469 cFYI(1,("parm count and data count larger than SMB"));
2470 return -EINVAL;
2471 }
2472 return 0;
2473}
2474
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475int
2476CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2477 const unsigned char *searchName,
2478 char *symlinkinfo, const int buflen,__u16 fid,
2479 const struct nls_table *nls_codepage)
2480{
2481 int rc = 0;
2482 int bytes_returned;
2483 int name_len;
2484 struct smb_com_transaction_ioctl_req * pSMB;
2485 struct smb_com_transaction_ioctl_rsp * pSMBr;
2486
2487 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2488 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2489 (void **) &pSMBr);
2490 if (rc)
2491 return rc;
2492
2493 pSMB->TotalParameterCount = 0 ;
2494 pSMB->TotalDataCount = 0;
2495 pSMB->MaxParameterCount = cpu_to_le32(2);
2496 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002497 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2498 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 pSMB->MaxSetupCount = 4;
2500 pSMB->Reserved = 0;
2501 pSMB->ParameterOffset = 0;
2502 pSMB->DataCount = 0;
2503 pSMB->DataOffset = 0;
2504 pSMB->SetupCount = 4;
2505 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2506 pSMB->ParameterCount = pSMB->TotalParameterCount;
2507 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2508 pSMB->IsFsctl = 1; /* FSCTL */
2509 pSMB->IsRootFlag = 0;
2510 pSMB->Fid = fid; /* file handle always le */
2511 pSMB->ByteCount = 0;
2512
2513 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2514 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2515 if (rc) {
2516 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2517 } else { /* decode response */
2518 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2519 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2520 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2521 /* BB also check enough total bytes returned */
2522 rc = -EIO; /* bad smb */
2523 else {
2524 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002525 char * end_of_smb = 2 /* sizeof byte count */ +
2526 pSMBr->ByteCount +
2527 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
2529 struct reparse_data * reparse_buf = (struct reparse_data *)
2530 ((char *)&pSMBr->hdr.Protocol + data_offset);
2531 if((char*)reparse_buf >= end_of_smb) {
2532 rc = -EIO;
2533 goto qreparse_out;
2534 }
2535 if((reparse_buf->LinkNamesBuf +
2536 reparse_buf->TargetNameOffset +
2537 reparse_buf->TargetNameLen) >
2538 end_of_smb) {
2539 cFYI(1,("reparse buf extended beyond SMB"));
2540 rc = -EIO;
2541 goto qreparse_out;
2542 }
2543
2544 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2545 name_len = UniStrnlen((wchar_t *)
2546 (reparse_buf->LinkNamesBuf +
2547 reparse_buf->TargetNameOffset),
2548 min(buflen/2, reparse_buf->TargetNameLen / 2));
2549 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002550 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 reparse_buf->TargetNameOffset),
2552 name_len, nls_codepage);
2553 } else { /* ASCII names */
2554 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2555 reparse_buf->TargetNameOffset,
2556 min_t(const int, buflen, reparse_buf->TargetNameLen));
2557 }
2558 } else {
2559 rc = -EIO;
2560 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2561 }
2562 symlinkinfo[buflen] = 0; /* just in case so the caller
2563 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002564 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 }
2566 }
2567qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002568 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
2570 /* Note: On -EAGAIN error only caller can retry on handle based calls
2571 since file handle passed in no longer valid */
2572
2573 return rc;
2574}
2575
2576#ifdef CONFIG_CIFS_POSIX
2577
2578/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2579static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2580{
2581 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002582 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2583 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2584 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2586
2587 return;
2588}
2589
2590/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002591static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2592 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593{
2594 int size = 0;
2595 int i;
2596 __u16 count;
2597 struct cifs_posix_ace * pACE;
2598 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2599 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2600
2601 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2602 return -EOPNOTSUPP;
2603
2604 if(acl_type & ACL_TYPE_ACCESS) {
2605 count = le16_to_cpu(cifs_acl->access_entry_count);
2606 pACE = &cifs_acl->ace_array[0];
2607 size = sizeof(struct cifs_posix_acl);
2608 size += sizeof(struct cifs_posix_ace) * count;
2609 /* check if we would go beyond end of SMB */
2610 if(size_of_data_area < size) {
2611 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2612 return -EINVAL;
2613 }
2614 } else if(acl_type & ACL_TYPE_DEFAULT) {
2615 count = le16_to_cpu(cifs_acl->access_entry_count);
2616 size = sizeof(struct cifs_posix_acl);
2617 size += sizeof(struct cifs_posix_ace) * count;
2618/* skip past access ACEs to get to default ACEs */
2619 pACE = &cifs_acl->ace_array[count];
2620 count = le16_to_cpu(cifs_acl->default_entry_count);
2621 size += sizeof(struct cifs_posix_ace) * count;
2622 /* check if we would go beyond end of SMB */
2623 if(size_of_data_area < size)
2624 return -EINVAL;
2625 } else {
2626 /* illegal type */
2627 return -EINVAL;
2628 }
2629
2630 size = posix_acl_xattr_size(count);
2631 if((buflen == 0) || (local_acl == NULL)) {
2632 /* used to query ACL EA size */
2633 } else if(size > buflen) {
2634 return -ERANGE;
2635 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002636 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 for(i = 0;i < count ;i++) {
2638 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2639 pACE ++;
2640 }
2641 }
2642 return size;
2643}
2644
2645static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2646 const posix_acl_xattr_entry * local_ace)
2647{
2648 __u16 rc = 0; /* 0 = ACL converted ok */
2649
Steve Frenchff7feac2005-11-15 16:45:16 -08002650 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2651 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002653 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 /* Probably no need to le convert -1 on any arch but can not hurt */
2655 cifs_ace->cifs_uid = cpu_to_le64(-1);
2656 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002657 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2659 return rc;
2660}
2661
2662/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2663static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2664 const int acl_type)
2665{
2666 __u16 rc = 0;
2667 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2668 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2669 int count;
2670 int i;
2671
2672 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2673 return 0;
2674
2675 count = posix_acl_xattr_count((size_t)buflen);
2676 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002677 count, buflen, le32_to_cpu(local_acl->a_version)));
2678 if(le32_to_cpu(local_acl->a_version) != 2) {
2679 cFYI(1,("unknown POSIX ACL version %d",
2680 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 return 0;
2682 }
2683 cifs_acl->version = cpu_to_le16(1);
2684 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002685 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002687 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 else {
2689 cFYI(1,("unknown ACL type %d",acl_type));
2690 return 0;
2691 }
2692 for(i=0;i<count;i++) {
2693 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2694 &local_acl->a_entries[i]);
2695 if(rc != 0) {
2696 /* ACE not converted */
2697 break;
2698 }
2699 }
2700 if(rc == 0) {
2701 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2702 rc += sizeof(struct cifs_posix_acl);
2703 /* BB add check to make sure ACL does not overflow SMB */
2704 }
2705 return rc;
2706}
2707
2708int
2709CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2710 const unsigned char *searchName,
2711 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002712 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713{
2714/* SMB_QUERY_POSIX_ACL */
2715 TRANSACTION2_QPI_REQ *pSMB = NULL;
2716 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2717 int rc = 0;
2718 int bytes_returned;
2719 int name_len;
2720 __u16 params, byte_count;
2721
2722 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2723
2724queryAclRetry:
2725 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2726 (void **) &pSMBr);
2727 if (rc)
2728 return rc;
2729
2730 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2731 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002732 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002733 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 name_len++; /* trailing null */
2735 name_len *= 2;
2736 pSMB->FileName[name_len] = 0;
2737 pSMB->FileName[name_len+1] = 0;
2738 } else { /* BB improve the check for buffer overruns BB */
2739 name_len = strnlen(searchName, PATH_MAX);
2740 name_len++; /* trailing null */
2741 strncpy(pSMB->FileName, searchName, name_len);
2742 }
2743
2744 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2745 pSMB->TotalDataCount = 0;
2746 pSMB->MaxParameterCount = cpu_to_le16(2);
2747 /* BB find exact max data count below from sess structure BB */
2748 pSMB->MaxDataCount = cpu_to_le16(4000);
2749 pSMB->MaxSetupCount = 0;
2750 pSMB->Reserved = 0;
2751 pSMB->Flags = 0;
2752 pSMB->Timeout = 0;
2753 pSMB->Reserved2 = 0;
2754 pSMB->ParameterOffset = cpu_to_le16(
2755 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2756 pSMB->DataCount = 0;
2757 pSMB->DataOffset = 0;
2758 pSMB->SetupCount = 1;
2759 pSMB->Reserved3 = 0;
2760 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2761 byte_count = params + 1 /* pad */ ;
2762 pSMB->TotalParameterCount = cpu_to_le16(params);
2763 pSMB->ParameterCount = pSMB->TotalParameterCount;
2764 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2765 pSMB->Reserved4 = 0;
2766 pSMB->hdr.smb_buf_length += byte_count;
2767 pSMB->ByteCount = cpu_to_le16(byte_count);
2768
2769 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2770 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002771 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 if (rc) {
2773 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2774 } else {
2775 /* decode response */
2776
2777 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2778 if (rc || (pSMBr->ByteCount < 2))
2779 /* BB also check enough total bytes returned */
2780 rc = -EIO; /* bad smb */
2781 else {
2782 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2783 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2784 rc = cifs_copy_posix_acl(acl_inf,
2785 (char *)&pSMBr->hdr.Protocol+data_offset,
2786 buflen,acl_type,count);
2787 }
2788 }
2789 cifs_buf_release(pSMB);
2790 if (rc == -EAGAIN)
2791 goto queryAclRetry;
2792 return rc;
2793}
2794
2795int
2796CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2797 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002798 const char *local_acl, const int buflen,
2799 const int acl_type,
2800 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801{
2802 struct smb_com_transaction2_spi_req *pSMB = NULL;
2803 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2804 char *parm_data;
2805 int name_len;
2806 int rc = 0;
2807 int bytes_returned = 0;
2808 __u16 params, byte_count, data_count, param_offset, offset;
2809
2810 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2811setAclRetry:
2812 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2813 (void **) &pSMBr);
2814 if (rc)
2815 return rc;
2816 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2817 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002818 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002819 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 name_len++; /* trailing null */
2821 name_len *= 2;
2822 } else { /* BB improve the check for buffer overruns BB */
2823 name_len = strnlen(fileName, PATH_MAX);
2824 name_len++; /* trailing null */
2825 strncpy(pSMB->FileName, fileName, name_len);
2826 }
2827 params = 6 + name_len;
2828 pSMB->MaxParameterCount = cpu_to_le16(2);
2829 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2830 pSMB->MaxSetupCount = 0;
2831 pSMB->Reserved = 0;
2832 pSMB->Flags = 0;
2833 pSMB->Timeout = 0;
2834 pSMB->Reserved2 = 0;
2835 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2836 InformationLevel) - 4;
2837 offset = param_offset + params;
2838 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2839 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2840
2841 /* convert to on the wire format for POSIX ACL */
2842 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2843
2844 if(data_count == 0) {
2845 rc = -EOPNOTSUPP;
2846 goto setACLerrorExit;
2847 }
2848 pSMB->DataOffset = cpu_to_le16(offset);
2849 pSMB->SetupCount = 1;
2850 pSMB->Reserved3 = 0;
2851 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2852 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2853 byte_count = 3 /* pad */ + params + data_count;
2854 pSMB->DataCount = cpu_to_le16(data_count);
2855 pSMB->TotalDataCount = pSMB->DataCount;
2856 pSMB->ParameterCount = cpu_to_le16(params);
2857 pSMB->TotalParameterCount = pSMB->ParameterCount;
2858 pSMB->Reserved4 = 0;
2859 pSMB->hdr.smb_buf_length += byte_count;
2860 pSMB->ByteCount = cpu_to_le16(byte_count);
2861 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2862 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2863 if (rc) {
2864 cFYI(1, ("Set POSIX ACL returned %d", rc));
2865 }
2866
2867setACLerrorExit:
2868 cifs_buf_release(pSMB);
2869 if (rc == -EAGAIN)
2870 goto setAclRetry;
2871 return rc;
2872}
2873
Steve Frenchf654bac2005-04-28 22:41:04 -07002874/* BB fix tabs in this function FIXME BB */
2875int
2876CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2877 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2878{
2879 int rc = 0;
2880 struct smb_t2_qfi_req *pSMB = NULL;
2881 struct smb_t2_qfi_rsp *pSMBr = NULL;
2882 int bytes_returned;
2883 __u16 params, byte_count;
2884
2885 cFYI(1,("In GetExtAttr"));
2886 if(tcon == NULL)
2887 return -ENODEV;
2888
2889GetExtAttrRetry:
2890 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2891 (void **) &pSMBr);
2892 if (rc)
2893 return rc;
2894
Steve Frenchc67593a2005-04-28 22:41:04 -07002895 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002896 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002897 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002898 /* BB find exact max data count below from sess structure BB */
2899 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2900 pSMB->t2.MaxSetupCount = 0;
2901 pSMB->t2.Reserved = 0;
2902 pSMB->t2.Flags = 0;
2903 pSMB->t2.Timeout = 0;
2904 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002905 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2906 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002907 pSMB->t2.DataCount = 0;
2908 pSMB->t2.DataOffset = 0;
2909 pSMB->t2.SetupCount = 1;
2910 pSMB->t2.Reserved3 = 0;
2911 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002912 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002913 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2914 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2915 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002916 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002917 pSMB->Fid = netfid;
2918 pSMB->hdr.smb_buf_length += byte_count;
2919 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2920
2921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2923 if (rc) {
2924 cFYI(1, ("error %d in GetExtAttr", rc));
2925 } else {
2926 /* decode response */
2927 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2928 if (rc || (pSMBr->ByteCount < 2))
2929 /* BB also check enough total bytes returned */
2930 /* If rc should we check for EOPNOSUPP and
2931 disable the srvino flag? or in caller? */
2932 rc = -EIO; /* bad smb */
2933 else {
2934 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2935 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2936 struct file_chattr_info * pfinfo;
2937 /* BB Do we need a cast or hash here ? */
2938 if(count != 16) {
2939 cFYI(1, ("Illegal size ret in GetExtAttr"));
2940 rc = -EIO;
2941 goto GetExtAttrOut;
2942 }
2943 pfinfo = (struct file_chattr_info *)
2944 (data_offset + (char *) &pSMBr->hdr.Protocol);
2945 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2946 *pMask = le64_to_cpu(pfinfo->mask);
2947 }
2948 }
2949GetExtAttrOut:
2950 cifs_buf_release(pSMB);
2951 if (rc == -EAGAIN)
2952 goto GetExtAttrRetry;
2953 return rc;
2954}
2955
2956
2957#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
Steve Frencheeac8042006-01-13 21:34:58 -08002959
2960/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002961static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00002962 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002963/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002964static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00002965 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002966
Steve French0a4b92c2006-01-12 15:44:21 -08002967/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002968static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002969{
Steve French0a4b92c2006-01-12 15:44:21 -08002970 return 0;
2971}
2972
2973/* Get Security Descriptor (by handle) from remote server for a file or dir */
2974int
2975CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2976 /* BB fix up return info */ char *acl_inf, const int buflen,
2977 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2978{
2979 int rc = 0;
2980 int buf_type = 0;
2981 QUERY_SEC_DESC_REQ * pSMB;
2982 struct kvec iov[1];
2983
2984 cFYI(1, ("GetCifsACL"));
2985
2986 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2987 8 /* parm len */, tcon, (void **) &pSMB);
2988 if (rc)
2989 return rc;
2990
2991 pSMB->MaxParameterCount = cpu_to_le32(4);
2992 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2993 pSMB->MaxSetupCount = 0;
2994 pSMB->Fid = fid; /* file handle always le */
2995 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2996 CIFS_ACL_DACL);
2997 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2998 pSMB->hdr.smb_buf_length += 11;
2999 iov[0].iov_base = (char *)pSMB;
3000 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3001
3002 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3003 cifs_stats_inc(&tcon->num_acl_get);
3004 if (rc) {
3005 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3006 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08003007 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003008 __le32 * parm;
3009 int parm_len;
3010 int data_len;
3011 int acl_len;
3012 struct smb_com_ntransact_rsp * pSMBr;
3013
3014/* validate_nttransact */
3015 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3016 (char **)&psec_desc,
3017 &parm_len, &data_len);
3018
3019 if(rc)
3020 goto qsec_out;
3021 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3022
3023 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
3024
3025 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3026 rc = -EIO; /* bad smb */
3027 goto qsec_out;
3028 }
3029
3030/* BB check that data area is minimum length and as big as acl_len */
3031
3032 acl_len = le32_to_cpu(*(__le32 *)parm);
3033 /* BB check if(acl_len > bufsize) */
3034
3035 parse_sec_desc(psec_desc, acl_len);
3036 }
3037qsec_out:
3038 if(buf_type == CIFS_SMALL_BUFFER)
3039 cifs_small_buf_release(iov[0].iov_base);
3040 else if(buf_type == CIFS_LARGE_BUFFER)
3041 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003042/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003043 return rc;
3044}
3045
Steve French6b8edfe2005-08-23 20:26:03 -07003046/* Legacy Query Path Information call for lookup to old servers such
3047 as Win9x/WinME */
3048int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3049 const unsigned char *searchName,
3050 FILE_ALL_INFO * pFinfo,
3051 const struct nls_table *nls_codepage, int remap)
3052{
3053 QUERY_INFORMATION_REQ * pSMB;
3054 QUERY_INFORMATION_RSP * pSMBr;
3055 int rc = 0;
3056 int bytes_returned;
3057 int name_len;
3058
3059 cFYI(1, ("In SMBQPath path %s", searchName));
3060QInfRetry:
3061 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3062 (void **) &pSMBr);
3063 if (rc)
3064 return rc;
3065
3066 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3067 name_len =
3068 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3069 PATH_MAX, nls_codepage, remap);
3070 name_len++; /* trailing null */
3071 name_len *= 2;
3072 } else {
3073 name_len = strnlen(searchName, PATH_MAX);
3074 name_len++; /* trailing null */
3075 strncpy(pSMB->FileName, searchName, name_len);
3076 }
3077 pSMB->BufferFormat = 0x04;
3078 name_len++; /* account for buffer type byte */
3079 pSMB->hdr.smb_buf_length += (__u16) name_len;
3080 pSMB->ByteCount = cpu_to_le16(name_len);
3081
3082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3084 if (rc) {
3085 cFYI(1, ("Send error in QueryInfo = %d", rc));
3086 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003087 struct timespec ts;
3088 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3089 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003090 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003091 ts.tv_nsec = 0;
3092 ts.tv_sec = time;
3093 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003094 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003095 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3096 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003097 pFinfo->AllocationSize =
3098 cpu_to_le64(le32_to_cpu(pSMBr->size));
3099 pFinfo->EndOfFile = pFinfo->AllocationSize;
3100 pFinfo->Attributes =
3101 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003102 } else
3103 rc = -EIO; /* bad buffer passed in */
3104
3105 cifs_buf_release(pSMB);
3106
3107 if (rc == -EAGAIN)
3108 goto QInfRetry;
3109
3110 return rc;
3111}
3112
3113
3114
3115
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116int
3117CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3118 const unsigned char *searchName,
3119 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003120 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003121 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122{
3123/* level 263 SMB_QUERY_FILE_ALL_INFO */
3124 TRANSACTION2_QPI_REQ *pSMB = NULL;
3125 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3126 int rc = 0;
3127 int bytes_returned;
3128 int name_len;
3129 __u16 params, byte_count;
3130
3131/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3132QPathInfoRetry:
3133 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3134 (void **) &pSMBr);
3135 if (rc)
3136 return rc;
3137
3138 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3139 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003140 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003141 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 name_len++; /* trailing null */
3143 name_len *= 2;
3144 } else { /* BB improve the check for buffer overruns BB */
3145 name_len = strnlen(searchName, PATH_MAX);
3146 name_len++; /* trailing null */
3147 strncpy(pSMB->FileName, searchName, name_len);
3148 }
3149
3150 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3151 pSMB->TotalDataCount = 0;
3152 pSMB->MaxParameterCount = cpu_to_le16(2);
3153 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3154 pSMB->MaxSetupCount = 0;
3155 pSMB->Reserved = 0;
3156 pSMB->Flags = 0;
3157 pSMB->Timeout = 0;
3158 pSMB->Reserved2 = 0;
3159 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3160 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3161 pSMB->DataCount = 0;
3162 pSMB->DataOffset = 0;
3163 pSMB->SetupCount = 1;
3164 pSMB->Reserved3 = 0;
3165 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3166 byte_count = params + 1 /* pad */ ;
3167 pSMB->TotalParameterCount = cpu_to_le16(params);
3168 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003169 if(legacy)
3170 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3171 else
3172 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 pSMB->Reserved4 = 0;
3174 pSMB->hdr.smb_buf_length += byte_count;
3175 pSMB->ByteCount = cpu_to_le16(byte_count);
3176
3177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3179 if (rc) {
3180 cFYI(1, ("Send error in QPathInfo = %d", rc));
3181 } else { /* decode response */
3182 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3183
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003184 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3185 rc = -EIO;
3186 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 rc = -EIO; /* bad smb */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003188 else if(legacy && (pSMBr->ByteCount < 24))
3189 rc = -EIO; /* 24 or 26 expected but we do not read last field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 else if (pFindData){
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003191 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003193 if(legacy) /* we do not read the last field, EAsize, fortunately
3194 since it varies by subdialect and on Set vs. Get, is
3195 two bytes or 4 bytes depending but we don't care here */
3196 size = sizeof(FILE_INFO_STANDARD);
3197 else
3198 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 memcpy((char *) pFindData,
3200 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003201 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 } else
3203 rc = -ENOMEM;
3204 }
3205 cifs_buf_release(pSMB);
3206 if (rc == -EAGAIN)
3207 goto QPathInfoRetry;
3208
3209 return rc;
3210}
3211
3212int
3213CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3214 const unsigned char *searchName,
3215 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003216 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217{
3218/* SMB_QUERY_FILE_UNIX_BASIC */
3219 TRANSACTION2_QPI_REQ *pSMB = NULL;
3220 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3221 int rc = 0;
3222 int bytes_returned = 0;
3223 int name_len;
3224 __u16 params, byte_count;
3225
3226 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3227UnixQPathInfoRetry:
3228 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3229 (void **) &pSMBr);
3230 if (rc)
3231 return rc;
3232
3233 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3234 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003235 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003236 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 name_len++; /* trailing null */
3238 name_len *= 2;
3239 } else { /* BB improve the check for buffer overruns BB */
3240 name_len = strnlen(searchName, PATH_MAX);
3241 name_len++; /* trailing null */
3242 strncpy(pSMB->FileName, searchName, name_len);
3243 }
3244
3245 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3246 pSMB->TotalDataCount = 0;
3247 pSMB->MaxParameterCount = cpu_to_le16(2);
3248 /* BB find exact max SMB PDU from sess structure BB */
3249 pSMB->MaxDataCount = cpu_to_le16(4000);
3250 pSMB->MaxSetupCount = 0;
3251 pSMB->Reserved = 0;
3252 pSMB->Flags = 0;
3253 pSMB->Timeout = 0;
3254 pSMB->Reserved2 = 0;
3255 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3256 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3257 pSMB->DataCount = 0;
3258 pSMB->DataOffset = 0;
3259 pSMB->SetupCount = 1;
3260 pSMB->Reserved3 = 0;
3261 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3262 byte_count = params + 1 /* pad */ ;
3263 pSMB->TotalParameterCount = cpu_to_le16(params);
3264 pSMB->ParameterCount = pSMB->TotalParameterCount;
3265 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3266 pSMB->Reserved4 = 0;
3267 pSMB->hdr.smb_buf_length += byte_count;
3268 pSMB->ByteCount = cpu_to_le16(byte_count);
3269
3270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3271 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3272 if (rc) {
3273 cFYI(1, ("Send error in QPathInfo = %d", rc));
3274 } else { /* decode response */
3275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3276
3277 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3278 rc = -EIO; /* bad smb */
3279 } else {
3280 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3281 memcpy((char *) pFindData,
3282 (char *) &pSMBr->hdr.Protocol +
3283 data_offset,
3284 sizeof (FILE_UNIX_BASIC_INFO));
3285 }
3286 }
3287 cifs_buf_release(pSMB);
3288 if (rc == -EAGAIN)
3289 goto UnixQPathInfoRetry;
3290
3291 return rc;
3292}
3293
3294#if 0 /* function unused at present */
3295int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3296 const char *searchName, FILE_ALL_INFO * findData,
3297 const struct nls_table *nls_codepage)
3298{
3299/* level 257 SMB_ */
3300 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3301 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3302 int rc = 0;
3303 int bytes_returned;
3304 int name_len;
3305 __u16 params, byte_count;
3306
3307 cFYI(1, ("In FindUnique"));
3308findUniqueRetry:
3309 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3310 (void **) &pSMBr);
3311 if (rc)
3312 return rc;
3313
3314 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3315 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003316 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 /* find define for this maxpathcomponent */
3318 , nls_codepage);
3319 name_len++; /* trailing null */
3320 name_len *= 2;
3321 } else { /* BB improve the check for buffer overruns BB */
3322 name_len = strnlen(searchName, PATH_MAX);
3323 name_len++; /* trailing null */
3324 strncpy(pSMB->FileName, searchName, name_len);
3325 }
3326
3327 params = 12 + name_len /* includes null */ ;
3328 pSMB->TotalDataCount = 0; /* no EAs */
3329 pSMB->MaxParameterCount = cpu_to_le16(2);
3330 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3331 pSMB->MaxSetupCount = 0;
3332 pSMB->Reserved = 0;
3333 pSMB->Flags = 0;
3334 pSMB->Timeout = 0;
3335 pSMB->Reserved2 = 0;
3336 pSMB->ParameterOffset = cpu_to_le16(
3337 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3338 pSMB->DataCount = 0;
3339 pSMB->DataOffset = 0;
3340 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3341 pSMB->Reserved3 = 0;
3342 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3343 byte_count = params + 1 /* pad */ ;
3344 pSMB->TotalParameterCount = cpu_to_le16(params);
3345 pSMB->ParameterCount = pSMB->TotalParameterCount;
3346 pSMB->SearchAttributes =
3347 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3348 ATTR_DIRECTORY);
3349 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3350 pSMB->SearchFlags = cpu_to_le16(1);
3351 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3352 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3353 pSMB->hdr.smb_buf_length += byte_count;
3354 pSMB->ByteCount = cpu_to_le16(byte_count);
3355
3356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3358
3359 if (rc) {
3360 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3361 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003362 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 /* BB fill in */
3364 }
3365
3366 cifs_buf_release(pSMB);
3367 if (rc == -EAGAIN)
3368 goto findUniqueRetry;
3369
3370 return rc;
3371}
3372#endif /* end unused (temporarily) function */
3373
3374/* xid, tcon, searchName and codepage are input parms, rest are returned */
3375int
3376CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3377 const char *searchName,
3378 const struct nls_table *nls_codepage,
3379 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003380 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381{
3382/* level 257 SMB_ */
3383 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3384 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3385 T2_FFIRST_RSP_PARMS * parms;
3386 int rc = 0;
3387 int bytes_returned = 0;
3388 int name_len;
3389 __u16 params, byte_count;
3390
Steve French737b7582005-04-28 22:41:06 -07003391 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
3393findFirstRetry:
3394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3395 (void **) &pSMBr);
3396 if (rc)
3397 return rc;
3398
3399 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3400 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003401 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003402 PATH_MAX, nls_codepage, remap);
3403 /* We can not add the asterik earlier in case
3404 it got remapped to 0xF03A as if it were part of the
3405 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003407 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003408 pSMB->FileName[name_len+1] = 0;
3409 pSMB->FileName[name_len+2] = '*';
3410 pSMB->FileName[name_len+3] = 0;
3411 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3413 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003414 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 } else { /* BB add check for overrun of SMB buf BB */
3416 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417/* BB fix here and in unicode clause above ie
3418 if(name_len > buffersize-header)
3419 free buffer exit; BB */
3420 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003421 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003422 pSMB->FileName[name_len+1] = '*';
3423 pSMB->FileName[name_len+2] = 0;
3424 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 }
3426
3427 params = 12 + name_len /* includes null */ ;
3428 pSMB->TotalDataCount = 0; /* no EAs */
3429 pSMB->MaxParameterCount = cpu_to_le16(10);
3430 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3431 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3432 pSMB->MaxSetupCount = 0;
3433 pSMB->Reserved = 0;
3434 pSMB->Flags = 0;
3435 pSMB->Timeout = 0;
3436 pSMB->Reserved2 = 0;
3437 byte_count = params + 1 /* pad */ ;
3438 pSMB->TotalParameterCount = cpu_to_le16(params);
3439 pSMB->ParameterCount = pSMB->TotalParameterCount;
3440 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003441 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3442 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 pSMB->DataCount = 0;
3444 pSMB->DataOffset = 0;
3445 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3446 pSMB->Reserved3 = 0;
3447 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3448 pSMB->SearchAttributes =
3449 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3450 ATTR_DIRECTORY);
3451 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3452 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3453 CIFS_SEARCH_RETURN_RESUME);
3454 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3455
3456 /* BB what should we set StorageType to? Does it matter? BB */
3457 pSMB->SearchStorageType = 0;
3458 pSMB->hdr.smb_buf_length += byte_count;
3459 pSMB->ByteCount = cpu_to_le16(byte_count);
3460
3461 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3462 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003463 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
Steve French88274812006-03-09 22:21:45 +00003465 if (rc) {/* BB add logic to retry regular search if Unix search
3466 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 /* BB Add code to handle unsupported level rc */
3468 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003469
Steve French88274812006-03-09 22:21:45 +00003470 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
3472 /* BB eventually could optimize out free and realloc of buf */
3473 /* for this case */
3474 if (rc == -EAGAIN)
3475 goto findFirstRetry;
3476 } else { /* decode response */
3477 /* BB remember to free buffer if error BB */
3478 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3479 if(rc == 0) {
3480 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3481 psrch_inf->unicode = TRUE;
3482 else
3483 psrch_inf->unicode = FALSE;
3484
3485 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003486 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 psrch_inf->srch_entries_start =
3488 (char *) &pSMBr->hdr.Protocol +
3489 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3491 le16_to_cpu(pSMBr->t2.ParameterOffset));
3492
3493 if(parms->EndofSearch)
3494 psrch_inf->endOfSearch = TRUE;
3495 else
3496 psrch_inf->endOfSearch = FALSE;
3497
3498 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003499 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 *pnetfid = parms->SearchHandle;
3502 } else {
3503 cifs_buf_release(pSMB);
3504 }
3505 }
3506
3507 return rc;
3508}
3509
3510int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3511 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3512{
3513 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3514 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3515 T2_FNEXT_RSP_PARMS * parms;
3516 char *response_data;
3517 int rc = 0;
3518 int bytes_returned, name_len;
3519 __u16 params, byte_count;
3520
3521 cFYI(1, ("In FindNext"));
3522
3523 if(psrch_inf->endOfSearch == TRUE)
3524 return -ENOENT;
3525
3526 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3527 (void **) &pSMBr);
3528 if (rc)
3529 return rc;
3530
3531 params = 14; /* includes 2 bytes of null string, converted to LE below */
3532 byte_count = 0;
3533 pSMB->TotalDataCount = 0; /* no EAs */
3534 pSMB->MaxParameterCount = cpu_to_le16(8);
3535 pSMB->MaxDataCount =
3536 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3537 pSMB->MaxSetupCount = 0;
3538 pSMB->Reserved = 0;
3539 pSMB->Flags = 0;
3540 pSMB->Timeout = 0;
3541 pSMB->Reserved2 = 0;
3542 pSMB->ParameterOffset = cpu_to_le16(
3543 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3544 pSMB->DataCount = 0;
3545 pSMB->DataOffset = 0;
3546 pSMB->SetupCount = 1;
3547 pSMB->Reserved3 = 0;
3548 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3549 pSMB->SearchHandle = searchHandle; /* always kept as le */
3550 pSMB->SearchCount =
3551 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3552 /* test for Unix extensions */
3553/* if (tcon->ses->capabilities & CAP_UNIX) {
3554 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3555 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3556 } else {
3557 pSMB->InformationLevel =
3558 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3559 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3560 } */
3561 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3562 pSMB->ResumeKey = psrch_inf->resume_key;
3563 pSMB->SearchFlags =
3564 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3565
3566 name_len = psrch_inf->resume_name_len;
3567 params += name_len;
3568 if(name_len < PATH_MAX) {
3569 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3570 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003571 /* 14 byte parm len above enough for 2 byte null terminator */
3572 pSMB->ResumeFileName[name_len] = 0;
3573 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 } else {
3575 rc = -EINVAL;
3576 goto FNext2_err_exit;
3577 }
3578 byte_count = params + 1 /* pad */ ;
3579 pSMB->TotalParameterCount = cpu_to_le16(params);
3580 pSMB->ParameterCount = pSMB->TotalParameterCount;
3581 pSMB->hdr.smb_buf_length += byte_count;
3582 pSMB->ByteCount = cpu_to_le16(byte_count);
3583
3584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003586 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 if (rc) {
3588 if (rc == -EBADF) {
3589 psrch_inf->endOfSearch = TRUE;
3590 rc = 0; /* search probably was closed at end of search above */
3591 } else
3592 cFYI(1, ("FindNext returned = %d", rc));
3593 } else { /* decode response */
3594 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3595
3596 if(rc == 0) {
3597 /* BB fixme add lock for file (srch_info) struct here */
3598 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3599 psrch_inf->unicode = TRUE;
3600 else
3601 psrch_inf->unicode = FALSE;
3602 response_data = (char *) &pSMBr->hdr.Protocol +
3603 le16_to_cpu(pSMBr->t2.ParameterOffset);
3604 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3605 response_data = (char *)&pSMBr->hdr.Protocol +
3606 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003607 if(psrch_inf->smallBuf)
3608 cifs_small_buf_release(
3609 psrch_inf->ntwrk_buf_start);
3610 else
3611 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 psrch_inf->srch_entries_start = response_data;
3613 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003614 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 if(parms->EndofSearch)
3616 psrch_inf->endOfSearch = TRUE;
3617 else
3618 psrch_inf->endOfSearch = FALSE;
3619
3620 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3621 psrch_inf->index_of_last_entry +=
3622 psrch_inf->entries_in_buffer;
3623/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3624
3625 /* BB fixme add unlock here */
3626 }
3627
3628 }
3629
3630 /* BB On error, should we leave previous search buf (and count and
3631 last entry fields) intact or free the previous one? */
3632
3633 /* Note: On -EAGAIN error only caller can retry on handle based calls
3634 since file handle passed in no longer valid */
3635FNext2_err_exit:
3636 if (rc != 0)
3637 cifs_buf_release(pSMB);
3638
3639 return rc;
3640}
3641
3642int
3643CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3644{
3645 int rc = 0;
3646 FINDCLOSE_REQ *pSMB = NULL;
3647 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3648 int bytes_returned;
3649
3650 cFYI(1, ("In CIFSSMBFindClose"));
3651 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3652
3653 /* no sense returning error if session restarted
3654 as file handle has been closed */
3655 if(rc == -EAGAIN)
3656 return 0;
3657 if (rc)
3658 return rc;
3659
3660 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3661 pSMB->FileID = searchHandle;
3662 pSMB->ByteCount = 0;
3663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3664 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3665 if (rc) {
3666 cERROR(1, ("Send error in FindClose = %d", rc));
3667 }
Steve Frencha4544342005-08-24 13:59:35 -07003668 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 cifs_small_buf_release(pSMB);
3670
3671 /* Since session is dead, search handle closed on server already */
3672 if (rc == -EAGAIN)
3673 rc = 0;
3674
3675 return rc;
3676}
3677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678int
3679CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3680 const unsigned char *searchName,
3681 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003682 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683{
3684 int rc = 0;
3685 TRANSACTION2_QPI_REQ *pSMB = NULL;
3686 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3687 int name_len, bytes_returned;
3688 __u16 params, byte_count;
3689
3690 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3691 if(tcon == NULL)
3692 return -ENODEV;
3693
3694GetInodeNumberRetry:
3695 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3696 (void **) &pSMBr);
3697 if (rc)
3698 return rc;
3699
3700
3701 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3702 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003703 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003704 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 name_len++; /* trailing null */
3706 name_len *= 2;
3707 } else { /* BB improve the check for buffer overruns BB */
3708 name_len = strnlen(searchName, PATH_MAX);
3709 name_len++; /* trailing null */
3710 strncpy(pSMB->FileName, searchName, name_len);
3711 }
3712
3713 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3714 pSMB->TotalDataCount = 0;
3715 pSMB->MaxParameterCount = cpu_to_le16(2);
3716 /* BB find exact max data count below from sess structure BB */
3717 pSMB->MaxDataCount = cpu_to_le16(4000);
3718 pSMB->MaxSetupCount = 0;
3719 pSMB->Reserved = 0;
3720 pSMB->Flags = 0;
3721 pSMB->Timeout = 0;
3722 pSMB->Reserved2 = 0;
3723 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3724 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3725 pSMB->DataCount = 0;
3726 pSMB->DataOffset = 0;
3727 pSMB->SetupCount = 1;
3728 pSMB->Reserved3 = 0;
3729 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3730 byte_count = params + 1 /* pad */ ;
3731 pSMB->TotalParameterCount = cpu_to_le16(params);
3732 pSMB->ParameterCount = pSMB->TotalParameterCount;
3733 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3734 pSMB->Reserved4 = 0;
3735 pSMB->hdr.smb_buf_length += byte_count;
3736 pSMB->ByteCount = cpu_to_le16(byte_count);
3737
3738 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3739 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3740 if (rc) {
3741 cFYI(1, ("error %d in QueryInternalInfo", rc));
3742 } else {
3743 /* decode response */
3744 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3745 if (rc || (pSMBr->ByteCount < 2))
3746 /* BB also check enough total bytes returned */
3747 /* If rc should we check for EOPNOSUPP and
3748 disable the srvino flag? or in caller? */
3749 rc = -EIO; /* bad smb */
3750 else {
3751 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3752 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3753 struct file_internal_info * pfinfo;
3754 /* BB Do we need a cast or hash here ? */
3755 if(count < 8) {
3756 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3757 rc = -EIO;
3758 goto GetInodeNumOut;
3759 }
3760 pfinfo = (struct file_internal_info *)
3761 (data_offset + (char *) &pSMBr->hdr.Protocol);
3762 *inode_number = pfinfo->UniqueId;
3763 }
3764 }
3765GetInodeNumOut:
3766 cifs_buf_release(pSMB);
3767 if (rc == -EAGAIN)
3768 goto GetInodeNumberRetry;
3769 return rc;
3770}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771
3772int
3773CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3774 const unsigned char *searchName,
3775 unsigned char **targetUNCs,
3776 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003777 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778{
3779/* TRANS2_GET_DFS_REFERRAL */
3780 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3781 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3782 struct dfs_referral_level_3 * referrals = NULL;
3783 int rc = 0;
3784 int bytes_returned;
3785 int name_len;
3786 unsigned int i;
3787 char * temp;
3788 __u16 params, byte_count;
3789 *number_of_UNC_in_array = 0;
3790 *targetUNCs = NULL;
3791
3792 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3793 if (ses == NULL)
3794 return -ENODEV;
3795getDFSRetry:
3796 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3797 (void **) &pSMBr);
3798 if (rc)
3799 return rc;
Steve French1982c342005-08-17 12:38:22 -07003800
3801 /* server pointer checked in called function,
3802 but should never be null here anyway */
3803 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 pSMB->hdr.Tid = ses->ipc_tid;
3805 pSMB->hdr.Uid = ses->Suid;
3806 if (ses->capabilities & CAP_STATUS32) {
3807 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3808 }
3809 if (ses->capabilities & CAP_DFS) {
3810 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3811 }
3812
3813 if (ses->capabilities & CAP_UNICODE) {
3814 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3815 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003816 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003817 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 name_len++; /* trailing null */
3819 name_len *= 2;
3820 } else { /* BB improve the check for buffer overruns BB */
3821 name_len = strnlen(searchName, PATH_MAX);
3822 name_len++; /* trailing null */
3823 strncpy(pSMB->RequestFileName, searchName, name_len);
3824 }
3825
Steve French1a4e15a2006-10-12 21:33:51 +00003826 if(ses->server) {
3827 if(ses->server->secMode &
3828 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3829 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3830 }
3831
3832 pSMB->hdr.Uid = ses->Suid;
3833
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 params = 2 /* level */ + name_len /*includes null */ ;
3835 pSMB->TotalDataCount = 0;
3836 pSMB->DataCount = 0;
3837 pSMB->DataOffset = 0;
3838 pSMB->MaxParameterCount = 0;
3839 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3840 pSMB->MaxSetupCount = 0;
3841 pSMB->Reserved = 0;
3842 pSMB->Flags = 0;
3843 pSMB->Timeout = 0;
3844 pSMB->Reserved2 = 0;
3845 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3846 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3847 pSMB->SetupCount = 1;
3848 pSMB->Reserved3 = 0;
3849 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3850 byte_count = params + 3 /* pad */ ;
3851 pSMB->ParameterCount = cpu_to_le16(params);
3852 pSMB->TotalParameterCount = pSMB->ParameterCount;
3853 pSMB->MaxReferralLevel = cpu_to_le16(3);
3854 pSMB->hdr.smb_buf_length += byte_count;
3855 pSMB->ByteCount = cpu_to_le16(byte_count);
3856
3857 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3859 if (rc) {
3860 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3861 } else { /* decode response */
3862/* BB Add logic to parse referrals here */
3863 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3864
3865 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3866 rc = -EIO; /* bad smb */
3867 else {
3868 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3869 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3870
3871 cFYI(1,
3872 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3873 pSMBr->ByteCount, data_offset));
3874 referrals =
3875 (struct dfs_referral_level_3 *)
3876 (8 /* sizeof start of data block */ +
3877 data_offset +
3878 (char *) &pSMBr->hdr.Protocol);
3879 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",
3880 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)));
3881 /* BB This field is actually two bytes in from start of
3882 data block so we could do safety check that DataBlock
3883 begins at address of pSMBr->NumberOfReferrals */
3884 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3885
3886 /* BB Fix below so can return more than one referral */
3887 if(*number_of_UNC_in_array > 1)
3888 *number_of_UNC_in_array = 1;
3889
3890 /* get the length of the strings describing refs */
3891 name_len = 0;
3892 for(i=0;i<*number_of_UNC_in_array;i++) {
3893 /* make sure that DfsPathOffset not past end */
3894 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3895 if (offset > data_count) {
3896 /* if invalid referral, stop here and do
3897 not try to copy any more */
3898 *number_of_UNC_in_array = i;
3899 break;
3900 }
3901 temp = ((char *)referrals) + offset;
3902
3903 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3904 name_len += UniStrnlen((wchar_t *)temp,data_count);
3905 } else {
3906 name_len += strnlen(temp,data_count);
3907 }
3908 referrals++;
3909 /* BB add check that referral pointer does not fall off end PDU */
3910
3911 }
3912 /* BB add check for name_len bigger than bcc */
3913 *targetUNCs =
3914 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3915 if(*targetUNCs == NULL) {
3916 rc = -ENOMEM;
3917 goto GetDFSRefExit;
3918 }
3919 /* copy the ref strings */
3920 referrals =
3921 (struct dfs_referral_level_3 *)
3922 (8 /* sizeof data hdr */ +
3923 data_offset +
3924 (char *) &pSMBr->hdr.Protocol);
3925
3926 for(i=0;i<*number_of_UNC_in_array;i++) {
3927 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3928 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3929 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003930 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 } else {
3932 strncpy(*targetUNCs,temp,name_len);
3933 }
3934 /* BB update target_uncs pointers */
3935 referrals++;
3936 }
3937 temp = *targetUNCs;
3938 temp[name_len] = 0;
3939 }
3940
3941 }
3942GetDFSRefExit:
3943 if (pSMB)
3944 cifs_buf_release(pSMB);
3945
3946 if (rc == -EAGAIN)
3947 goto getDFSRetry;
3948
3949 return rc;
3950}
3951
Steve French20962432005-09-21 22:05:57 -07003952/* Query File System Info such as free space to old servers such as Win 9x */
3953int
3954SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3955{
3956/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3957 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3958 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3959 FILE_SYSTEM_ALLOC_INFO *response_data;
3960 int rc = 0;
3961 int bytes_returned = 0;
3962 __u16 params, byte_count;
3963
3964 cFYI(1, ("OldQFSInfo"));
3965oldQFSInfoRetry:
3966 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3967 (void **) &pSMBr);
3968 if (rc)
3969 return rc;
3970 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3971 (void **) &pSMBr);
3972 if (rc)
3973 return rc;
3974
3975 params = 2; /* level */
3976 pSMB->TotalDataCount = 0;
3977 pSMB->MaxParameterCount = cpu_to_le16(2);
3978 pSMB->MaxDataCount = cpu_to_le16(1000);
3979 pSMB->MaxSetupCount = 0;
3980 pSMB->Reserved = 0;
3981 pSMB->Flags = 0;
3982 pSMB->Timeout = 0;
3983 pSMB->Reserved2 = 0;
3984 byte_count = params + 1 /* pad */ ;
3985 pSMB->TotalParameterCount = cpu_to_le16(params);
3986 pSMB->ParameterCount = pSMB->TotalParameterCount;
3987 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3988 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3989 pSMB->DataCount = 0;
3990 pSMB->DataOffset = 0;
3991 pSMB->SetupCount = 1;
3992 pSMB->Reserved3 = 0;
3993 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3994 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3995 pSMB->hdr.smb_buf_length += byte_count;
3996 pSMB->ByteCount = cpu_to_le16(byte_count);
3997
3998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4000 if (rc) {
4001 cFYI(1, ("Send error in QFSInfo = %d", rc));
4002 } else { /* decode response */
4003 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4004
4005 if (rc || (pSMBr->ByteCount < 18))
4006 rc = -EIO; /* bad smb */
4007 else {
4008 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4009 cFYI(1,("qfsinf resp BCC: %d Offset %d",
4010 pSMBr->ByteCount, data_offset));
4011
4012 response_data =
4013 (FILE_SYSTEM_ALLOC_INFO *)
4014 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4015 FSData->f_bsize =
4016 le16_to_cpu(response_data->BytesPerSector) *
4017 le32_to_cpu(response_data->
4018 SectorsPerAllocationUnit);
4019 FSData->f_blocks =
4020 le32_to_cpu(response_data->TotalAllocationUnits);
4021 FSData->f_bfree = FSData->f_bavail =
4022 le32_to_cpu(response_data->FreeAllocationUnits);
4023 cFYI(1,
4024 ("Blocks: %lld Free: %lld Block size %ld",
4025 (unsigned long long)FSData->f_blocks,
4026 (unsigned long long)FSData->f_bfree,
4027 FSData->f_bsize));
4028 }
4029 }
4030 cifs_buf_release(pSMB);
4031
4032 if (rc == -EAGAIN)
4033 goto oldQFSInfoRetry;
4034
4035 return rc;
4036}
4037
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038int
Steve French737b7582005-04-28 22:41:06 -07004039CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040{
4041/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4042 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4043 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4044 FILE_SYSTEM_INFO *response_data;
4045 int rc = 0;
4046 int bytes_returned = 0;
4047 __u16 params, byte_count;
4048
4049 cFYI(1, ("In QFSInfo"));
4050QFSInfoRetry:
4051 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4052 (void **) &pSMBr);
4053 if (rc)
4054 return rc;
4055
4056 params = 2; /* level */
4057 pSMB->TotalDataCount = 0;
4058 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004059 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 pSMB->MaxSetupCount = 0;
4061 pSMB->Reserved = 0;
4062 pSMB->Flags = 0;
4063 pSMB->Timeout = 0;
4064 pSMB->Reserved2 = 0;
4065 byte_count = params + 1 /* pad */ ;
4066 pSMB->TotalParameterCount = cpu_to_le16(params);
4067 pSMB->ParameterCount = pSMB->TotalParameterCount;
4068 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4069 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4070 pSMB->DataCount = 0;
4071 pSMB->DataOffset = 0;
4072 pSMB->SetupCount = 1;
4073 pSMB->Reserved3 = 0;
4074 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4075 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4076 pSMB->hdr.smb_buf_length += byte_count;
4077 pSMB->ByteCount = cpu_to_le16(byte_count);
4078
4079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4081 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004082 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 } else { /* decode response */
4084 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4085
Steve French20962432005-09-21 22:05:57 -07004086 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 rc = -EIO; /* bad smb */
4088 else {
4089 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090
4091 response_data =
4092 (FILE_SYSTEM_INFO
4093 *) (((char *) &pSMBr->hdr.Protocol) +
4094 data_offset);
4095 FSData->f_bsize =
4096 le32_to_cpu(response_data->BytesPerSector) *
4097 le32_to_cpu(response_data->
4098 SectorsPerAllocationUnit);
4099 FSData->f_blocks =
4100 le64_to_cpu(response_data->TotalAllocationUnits);
4101 FSData->f_bfree = FSData->f_bavail =
4102 le64_to_cpu(response_data->FreeAllocationUnits);
4103 cFYI(1,
4104 ("Blocks: %lld Free: %lld Block size %ld",
4105 (unsigned long long)FSData->f_blocks,
4106 (unsigned long long)FSData->f_bfree,
4107 FSData->f_bsize));
4108 }
4109 }
4110 cifs_buf_release(pSMB);
4111
4112 if (rc == -EAGAIN)
4113 goto QFSInfoRetry;
4114
4115 return rc;
4116}
4117
4118int
Steve French737b7582005-04-28 22:41:06 -07004119CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120{
4121/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4122 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4123 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4124 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4125 int rc = 0;
4126 int bytes_returned = 0;
4127 __u16 params, byte_count;
4128
4129 cFYI(1, ("In QFSAttributeInfo"));
4130QFSAttributeRetry:
4131 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4132 (void **) &pSMBr);
4133 if (rc)
4134 return rc;
4135
4136 params = 2; /* level */
4137 pSMB->TotalDataCount = 0;
4138 pSMB->MaxParameterCount = cpu_to_le16(2);
4139 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4140 pSMB->MaxSetupCount = 0;
4141 pSMB->Reserved = 0;
4142 pSMB->Flags = 0;
4143 pSMB->Timeout = 0;
4144 pSMB->Reserved2 = 0;
4145 byte_count = params + 1 /* pad */ ;
4146 pSMB->TotalParameterCount = cpu_to_le16(params);
4147 pSMB->ParameterCount = pSMB->TotalParameterCount;
4148 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4149 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4150 pSMB->DataCount = 0;
4151 pSMB->DataOffset = 0;
4152 pSMB->SetupCount = 1;
4153 pSMB->Reserved3 = 0;
4154 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4155 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4156 pSMB->hdr.smb_buf_length += byte_count;
4157 pSMB->ByteCount = cpu_to_le16(byte_count);
4158
4159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4161 if (rc) {
4162 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4163 } else { /* decode response */
4164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4165
4166 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4167 rc = -EIO; /* bad smb */
4168 } else {
4169 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4170 response_data =
4171 (FILE_SYSTEM_ATTRIBUTE_INFO
4172 *) (((char *) &pSMBr->hdr.Protocol) +
4173 data_offset);
4174 memcpy(&tcon->fsAttrInfo, response_data,
4175 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4176 }
4177 }
4178 cifs_buf_release(pSMB);
4179
4180 if (rc == -EAGAIN)
4181 goto QFSAttributeRetry;
4182
4183 return rc;
4184}
4185
4186int
Steve French737b7582005-04-28 22:41:06 -07004187CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188{
4189/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4190 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4191 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4192 FILE_SYSTEM_DEVICE_INFO *response_data;
4193 int rc = 0;
4194 int bytes_returned = 0;
4195 __u16 params, byte_count;
4196
4197 cFYI(1, ("In QFSDeviceInfo"));
4198QFSDeviceRetry:
4199 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4200 (void **) &pSMBr);
4201 if (rc)
4202 return rc;
4203
4204 params = 2; /* level */
4205 pSMB->TotalDataCount = 0;
4206 pSMB->MaxParameterCount = cpu_to_le16(2);
4207 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4208 pSMB->MaxSetupCount = 0;
4209 pSMB->Reserved = 0;
4210 pSMB->Flags = 0;
4211 pSMB->Timeout = 0;
4212 pSMB->Reserved2 = 0;
4213 byte_count = params + 1 /* pad */ ;
4214 pSMB->TotalParameterCount = cpu_to_le16(params);
4215 pSMB->ParameterCount = pSMB->TotalParameterCount;
4216 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4217 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4218
4219 pSMB->DataCount = 0;
4220 pSMB->DataOffset = 0;
4221 pSMB->SetupCount = 1;
4222 pSMB->Reserved3 = 0;
4223 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4224 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4225 pSMB->hdr.smb_buf_length += byte_count;
4226 pSMB->ByteCount = cpu_to_le16(byte_count);
4227
4228 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4229 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4230 if (rc) {
4231 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4232 } else { /* decode response */
4233 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4234
4235 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4236 rc = -EIO; /* bad smb */
4237 else {
4238 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4239 response_data =
Steve French737b7582005-04-28 22:41:06 -07004240 (FILE_SYSTEM_DEVICE_INFO *)
4241 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 data_offset);
4243 memcpy(&tcon->fsDevInfo, response_data,
4244 sizeof (FILE_SYSTEM_DEVICE_INFO));
4245 }
4246 }
4247 cifs_buf_release(pSMB);
4248
4249 if (rc == -EAGAIN)
4250 goto QFSDeviceRetry;
4251
4252 return rc;
4253}
4254
4255int
Steve French737b7582005-04-28 22:41:06 -07004256CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257{
4258/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4259 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4260 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4261 FILE_SYSTEM_UNIX_INFO *response_data;
4262 int rc = 0;
4263 int bytes_returned = 0;
4264 __u16 params, byte_count;
4265
4266 cFYI(1, ("In QFSUnixInfo"));
4267QFSUnixRetry:
4268 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4269 (void **) &pSMBr);
4270 if (rc)
4271 return rc;
4272
4273 params = 2; /* level */
4274 pSMB->TotalDataCount = 0;
4275 pSMB->DataCount = 0;
4276 pSMB->DataOffset = 0;
4277 pSMB->MaxParameterCount = cpu_to_le16(2);
4278 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4279 pSMB->MaxSetupCount = 0;
4280 pSMB->Reserved = 0;
4281 pSMB->Flags = 0;
4282 pSMB->Timeout = 0;
4283 pSMB->Reserved2 = 0;
4284 byte_count = params + 1 /* pad */ ;
4285 pSMB->ParameterCount = cpu_to_le16(params);
4286 pSMB->TotalParameterCount = pSMB->ParameterCount;
4287 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4288 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4289 pSMB->SetupCount = 1;
4290 pSMB->Reserved3 = 0;
4291 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4292 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4293 pSMB->hdr.smb_buf_length += byte_count;
4294 pSMB->ByteCount = cpu_to_le16(byte_count);
4295
4296 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4297 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4298 if (rc) {
4299 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4300 } else { /* decode response */
4301 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4302
4303 if (rc || (pSMBr->ByteCount < 13)) {
4304 rc = -EIO; /* bad smb */
4305 } else {
4306 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4307 response_data =
4308 (FILE_SYSTEM_UNIX_INFO
4309 *) (((char *) &pSMBr->hdr.Protocol) +
4310 data_offset);
4311 memcpy(&tcon->fsUnixInfo, response_data,
4312 sizeof (FILE_SYSTEM_UNIX_INFO));
4313 }
4314 }
4315 cifs_buf_release(pSMB);
4316
4317 if (rc == -EAGAIN)
4318 goto QFSUnixRetry;
4319
4320
4321 return rc;
4322}
4323
Jeremy Allisonac670552005-06-22 17:26:35 -07004324int
Steve French45abc6e2005-06-23 13:42:03 -05004325CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004326{
4327/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4328 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4329 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4330 int rc = 0;
4331 int bytes_returned = 0;
4332 __u16 params, param_offset, offset, byte_count;
4333
4334 cFYI(1, ("In SETFSUnixInfo"));
4335SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004336 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004337 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4338 (void **) &pSMBr);
4339 if (rc)
4340 return rc;
4341
4342 params = 4; /* 2 bytes zero followed by info level. */
4343 pSMB->MaxSetupCount = 0;
4344 pSMB->Reserved = 0;
4345 pSMB->Flags = 0;
4346 pSMB->Timeout = 0;
4347 pSMB->Reserved2 = 0;
4348 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4349 offset = param_offset + params;
4350
4351 pSMB->MaxParameterCount = cpu_to_le16(4);
4352 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4353 pSMB->SetupCount = 1;
4354 pSMB->Reserved3 = 0;
4355 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4356 byte_count = 1 /* pad */ + params + 12;
4357
4358 pSMB->DataCount = cpu_to_le16(12);
4359 pSMB->ParameterCount = cpu_to_le16(params);
4360 pSMB->TotalDataCount = pSMB->DataCount;
4361 pSMB->TotalParameterCount = pSMB->ParameterCount;
4362 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4363 pSMB->DataOffset = cpu_to_le16(offset);
4364
4365 /* Params. */
4366 pSMB->FileNum = 0;
4367 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4368
4369 /* Data. */
4370 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4371 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4372 pSMB->ClientUnixCap = cpu_to_le64(cap);
4373
4374 pSMB->hdr.smb_buf_length += byte_count;
4375 pSMB->ByteCount = cpu_to_le16(byte_count);
4376
4377 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4378 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4379 if (rc) {
4380 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4381 } else { /* decode response */
4382 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4383 if (rc) {
4384 rc = -EIO; /* bad smb */
4385 }
4386 }
4387 cifs_buf_release(pSMB);
4388
4389 if (rc == -EAGAIN)
4390 goto SETFSUnixRetry;
4391
4392 return rc;
4393}
4394
4395
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396
4397int
4398CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004399 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400{
4401/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4402 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4403 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4404 FILE_SYSTEM_POSIX_INFO *response_data;
4405 int rc = 0;
4406 int bytes_returned = 0;
4407 __u16 params, byte_count;
4408
4409 cFYI(1, ("In QFSPosixInfo"));
4410QFSPosixRetry:
4411 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4412 (void **) &pSMBr);
4413 if (rc)
4414 return rc;
4415
4416 params = 2; /* level */
4417 pSMB->TotalDataCount = 0;
4418 pSMB->DataCount = 0;
4419 pSMB->DataOffset = 0;
4420 pSMB->MaxParameterCount = cpu_to_le16(2);
4421 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4422 pSMB->MaxSetupCount = 0;
4423 pSMB->Reserved = 0;
4424 pSMB->Flags = 0;
4425 pSMB->Timeout = 0;
4426 pSMB->Reserved2 = 0;
4427 byte_count = params + 1 /* pad */ ;
4428 pSMB->ParameterCount = cpu_to_le16(params);
4429 pSMB->TotalParameterCount = pSMB->ParameterCount;
4430 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4431 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4432 pSMB->SetupCount = 1;
4433 pSMB->Reserved3 = 0;
4434 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4435 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4436 pSMB->hdr.smb_buf_length += byte_count;
4437 pSMB->ByteCount = cpu_to_le16(byte_count);
4438
4439 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4440 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4441 if (rc) {
4442 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4443 } else { /* decode response */
4444 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4445
4446 if (rc || (pSMBr->ByteCount < 13)) {
4447 rc = -EIO; /* bad smb */
4448 } else {
4449 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4450 response_data =
4451 (FILE_SYSTEM_POSIX_INFO
4452 *) (((char *) &pSMBr->hdr.Protocol) +
4453 data_offset);
4454 FSData->f_bsize =
4455 le32_to_cpu(response_data->BlockSize);
4456 FSData->f_blocks =
4457 le64_to_cpu(response_data->TotalBlocks);
4458 FSData->f_bfree =
4459 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004460 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 FSData->f_bavail = FSData->f_bfree;
4462 } else {
4463 FSData->f_bavail =
4464 le64_to_cpu(response_data->UserBlocksAvail);
4465 }
Steve French70ca7342005-09-22 16:32:06 -07004466 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 FSData->f_files =
4468 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004469 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 FSData->f_ffree =
4471 le64_to_cpu(response_data->FreeFileNodes);
4472 }
4473 }
4474 cifs_buf_release(pSMB);
4475
4476 if (rc == -EAGAIN)
4477 goto QFSPosixRetry;
4478
4479 return rc;
4480}
4481
4482
4483/* We can not use write of zero bytes trick to
4484 set file size due to need for large file support. Also note that
4485 this SetPathInfo is preferred to SetFileInfo based method in next
4486 routine which is only needed to work around a sharing violation bug
4487 in Samba which this routine can run into */
4488
4489int
4490CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004491 __u64 size, int SetAllocation,
4492 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493{
4494 struct smb_com_transaction2_spi_req *pSMB = NULL;
4495 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4496 struct file_end_of_file_info *parm_data;
4497 int name_len;
4498 int rc = 0;
4499 int bytes_returned = 0;
4500 __u16 params, byte_count, data_count, param_offset, offset;
4501
4502 cFYI(1, ("In SetEOF"));
4503SetEOFRetry:
4504 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4505 (void **) &pSMBr);
4506 if (rc)
4507 return rc;
4508
4509 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4510 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004511 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004512 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 name_len++; /* trailing null */
4514 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004515 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 name_len = strnlen(fileName, PATH_MAX);
4517 name_len++; /* trailing null */
4518 strncpy(pSMB->FileName, fileName, name_len);
4519 }
4520 params = 6 + name_len;
4521 data_count = sizeof (struct file_end_of_file_info);
4522 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004523 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 pSMB->MaxSetupCount = 0;
4525 pSMB->Reserved = 0;
4526 pSMB->Flags = 0;
4527 pSMB->Timeout = 0;
4528 pSMB->Reserved2 = 0;
4529 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4530 InformationLevel) - 4;
4531 offset = param_offset + params;
4532 if(SetAllocation) {
4533 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4534 pSMB->InformationLevel =
4535 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4536 else
4537 pSMB->InformationLevel =
4538 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4539 } else /* Set File Size */ {
4540 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4541 pSMB->InformationLevel =
4542 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4543 else
4544 pSMB->InformationLevel =
4545 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4546 }
4547
4548 parm_data =
4549 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4550 offset);
4551 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4552 pSMB->DataOffset = cpu_to_le16(offset);
4553 pSMB->SetupCount = 1;
4554 pSMB->Reserved3 = 0;
4555 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4556 byte_count = 3 /* pad */ + params + data_count;
4557 pSMB->DataCount = cpu_to_le16(data_count);
4558 pSMB->TotalDataCount = pSMB->DataCount;
4559 pSMB->ParameterCount = cpu_to_le16(params);
4560 pSMB->TotalParameterCount = pSMB->ParameterCount;
4561 pSMB->Reserved4 = 0;
4562 pSMB->hdr.smb_buf_length += byte_count;
4563 parm_data->FileSize = cpu_to_le64(size);
4564 pSMB->ByteCount = cpu_to_le16(byte_count);
4565 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4566 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4567 if (rc) {
4568 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4569 }
4570
4571 cifs_buf_release(pSMB);
4572
4573 if (rc == -EAGAIN)
4574 goto SetEOFRetry;
4575
4576 return rc;
4577}
4578
4579int
4580CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4581 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4582{
4583 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4584 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4585 char *data_offset;
4586 struct file_end_of_file_info *parm_data;
4587 int rc = 0;
4588 int bytes_returned = 0;
4589 __u16 params, param_offset, offset, byte_count, count;
4590
4591 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4592 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004593 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4594
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 if (rc)
4596 return rc;
4597
Steve Frenchcd634992005-04-28 22:41:10 -07004598 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4599
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4601 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4602
4603 params = 6;
4604 pSMB->MaxSetupCount = 0;
4605 pSMB->Reserved = 0;
4606 pSMB->Flags = 0;
4607 pSMB->Timeout = 0;
4608 pSMB->Reserved2 = 0;
4609 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4610 offset = param_offset + params;
4611
4612 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4613
4614 count = sizeof(struct file_end_of_file_info);
4615 pSMB->MaxParameterCount = cpu_to_le16(2);
4616 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4617 pSMB->SetupCount = 1;
4618 pSMB->Reserved3 = 0;
4619 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4620 byte_count = 3 /* pad */ + params + count;
4621 pSMB->DataCount = cpu_to_le16(count);
4622 pSMB->ParameterCount = cpu_to_le16(params);
4623 pSMB->TotalDataCount = pSMB->DataCount;
4624 pSMB->TotalParameterCount = pSMB->ParameterCount;
4625 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4626 parm_data =
4627 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4628 offset);
4629 pSMB->DataOffset = cpu_to_le16(offset);
4630 parm_data->FileSize = cpu_to_le64(size);
4631 pSMB->Fid = fid;
4632 if(SetAllocation) {
4633 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4634 pSMB->InformationLevel =
4635 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4636 else
4637 pSMB->InformationLevel =
4638 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4639 } else /* Set File Size */ {
4640 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4641 pSMB->InformationLevel =
4642 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4643 else
4644 pSMB->InformationLevel =
4645 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4646 }
4647 pSMB->Reserved4 = 0;
4648 pSMB->hdr.smb_buf_length += byte_count;
4649 pSMB->ByteCount = cpu_to_le16(byte_count);
4650 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4651 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4652 if (rc) {
4653 cFYI(1,
4654 ("Send error in SetFileInfo (SetFileSize) = %d",
4655 rc));
4656 }
4657
4658 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004659 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
4661 /* Note: On -EAGAIN error only caller can retry on handle based calls
4662 since file handle passed in no longer valid */
4663
4664 return rc;
4665}
4666
4667/* Some legacy servers such as NT4 require that the file times be set on
4668 an open handle, rather than by pathname - this is awkward due to
4669 potential access conflicts on the open, but it is unavoidable for these
4670 old servers since the only other choice is to go from 100 nanosecond DCE
4671 time and resort to the original setpathinfo level which takes the ancient
4672 DOS time format with 2 second granularity */
4673int
4674CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4675 __u16 fid)
4676{
4677 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4678 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4679 char *data_offset;
4680 int rc = 0;
4681 int bytes_returned = 0;
4682 __u16 params, param_offset, offset, byte_count, count;
4683
4684 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004685 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4686
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 if (rc)
4688 return rc;
4689
Steve Frenchcd634992005-04-28 22:41:10 -07004690 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4691
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 /* At this point there is no need to override the current pid
4693 with the pid of the opener, but that could change if we someday
4694 use an existing handle (rather than opening one on the fly) */
4695 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4696 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4697
4698 params = 6;
4699 pSMB->MaxSetupCount = 0;
4700 pSMB->Reserved = 0;
4701 pSMB->Flags = 0;
4702 pSMB->Timeout = 0;
4703 pSMB->Reserved2 = 0;
4704 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4705 offset = param_offset + params;
4706
4707 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4708
4709 count = sizeof (FILE_BASIC_INFO);
4710 pSMB->MaxParameterCount = cpu_to_le16(2);
4711 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4712 pSMB->SetupCount = 1;
4713 pSMB->Reserved3 = 0;
4714 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4715 byte_count = 3 /* pad */ + params + count;
4716 pSMB->DataCount = cpu_to_le16(count);
4717 pSMB->ParameterCount = cpu_to_le16(params);
4718 pSMB->TotalDataCount = pSMB->DataCount;
4719 pSMB->TotalParameterCount = pSMB->ParameterCount;
4720 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4721 pSMB->DataOffset = cpu_to_le16(offset);
4722 pSMB->Fid = fid;
4723 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4724 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4725 else
4726 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4727 pSMB->Reserved4 = 0;
4728 pSMB->hdr.smb_buf_length += byte_count;
4729 pSMB->ByteCount = cpu_to_le16(byte_count);
4730 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4732 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4733 if (rc) {
4734 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4735 }
4736
Steve Frenchcd634992005-04-28 22:41:10 -07004737 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738
4739 /* Note: On -EAGAIN error only caller can retry on handle based calls
4740 since file handle passed in no longer valid */
4741
4742 return rc;
4743}
4744
4745
4746int
4747CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4748 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004749 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750{
4751 TRANSACTION2_SPI_REQ *pSMB = NULL;
4752 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4753 int name_len;
4754 int rc = 0;
4755 int bytes_returned = 0;
4756 char *data_offset;
4757 __u16 params, param_offset, offset, byte_count, count;
4758
4759 cFYI(1, ("In SetTimes"));
4760
4761SetTimesRetry:
4762 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4763 (void **) &pSMBr);
4764 if (rc)
4765 return rc;
4766
4767 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4768 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004769 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004770 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 name_len++; /* trailing null */
4772 name_len *= 2;
4773 } else { /* BB improve the check for buffer overruns BB */
4774 name_len = strnlen(fileName, PATH_MAX);
4775 name_len++; /* trailing null */
4776 strncpy(pSMB->FileName, fileName, name_len);
4777 }
4778
4779 params = 6 + name_len;
4780 count = sizeof (FILE_BASIC_INFO);
4781 pSMB->MaxParameterCount = cpu_to_le16(2);
4782 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4783 pSMB->MaxSetupCount = 0;
4784 pSMB->Reserved = 0;
4785 pSMB->Flags = 0;
4786 pSMB->Timeout = 0;
4787 pSMB->Reserved2 = 0;
4788 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4789 InformationLevel) - 4;
4790 offset = param_offset + params;
4791 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4792 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4793 pSMB->DataOffset = cpu_to_le16(offset);
4794 pSMB->SetupCount = 1;
4795 pSMB->Reserved3 = 0;
4796 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4797 byte_count = 3 /* pad */ + params + count;
4798
4799 pSMB->DataCount = cpu_to_le16(count);
4800 pSMB->ParameterCount = cpu_to_le16(params);
4801 pSMB->TotalDataCount = pSMB->DataCount;
4802 pSMB->TotalParameterCount = pSMB->ParameterCount;
4803 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4804 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4805 else
4806 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4807 pSMB->Reserved4 = 0;
4808 pSMB->hdr.smb_buf_length += byte_count;
4809 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4810 pSMB->ByteCount = cpu_to_le16(byte_count);
4811 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4813 if (rc) {
4814 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4815 }
4816
4817 cifs_buf_release(pSMB);
4818
4819 if (rc == -EAGAIN)
4820 goto SetTimesRetry;
4821
4822 return rc;
4823}
4824
4825/* Can not be used to set time stamps yet (due to old DOS time format) */
4826/* Can be used to set attributes */
4827#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4828 handling it anyway and NT4 was what we thought it would be needed for
4829 Do not delete it until we prove whether needed for Win9x though */
4830int
4831CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4832 __u16 dos_attrs, const struct nls_table *nls_codepage)
4833{
4834 SETATTR_REQ *pSMB = NULL;
4835 SETATTR_RSP *pSMBr = NULL;
4836 int rc = 0;
4837 int bytes_returned;
4838 int name_len;
4839
4840 cFYI(1, ("In SetAttrLegacy"));
4841
4842SetAttrLgcyRetry:
4843 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4844 (void **) &pSMBr);
4845 if (rc)
4846 return rc;
4847
4848 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4849 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004850 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 PATH_MAX, nls_codepage);
4852 name_len++; /* trailing null */
4853 name_len *= 2;
4854 } else { /* BB improve the check for buffer overruns BB */
4855 name_len = strnlen(fileName, PATH_MAX);
4856 name_len++; /* trailing null */
4857 strncpy(pSMB->fileName, fileName, name_len);
4858 }
4859 pSMB->attr = cpu_to_le16(dos_attrs);
4860 pSMB->BufferFormat = 0x04;
4861 pSMB->hdr.smb_buf_length += name_len + 1;
4862 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4863 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4864 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4865 if (rc) {
4866 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4867 }
4868
4869 cifs_buf_release(pSMB);
4870
4871 if (rc == -EAGAIN)
4872 goto SetAttrLgcyRetry;
4873
4874 return rc;
4875}
4876#endif /* temporarily unneeded SetAttr legacy function */
4877
4878int
4879CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004880 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4881 dev_t device, const struct nls_table *nls_codepage,
4882 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883{
4884 TRANSACTION2_SPI_REQ *pSMB = NULL;
4885 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4886 int name_len;
4887 int rc = 0;
4888 int bytes_returned = 0;
4889 FILE_UNIX_BASIC_INFO *data_offset;
4890 __u16 params, param_offset, offset, count, byte_count;
4891
4892 cFYI(1, ("In SetUID/GID/Mode"));
4893setPermsRetry:
4894 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4895 (void **) &pSMBr);
4896 if (rc)
4897 return rc;
4898
4899 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4900 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004901 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004902 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 name_len++; /* trailing null */
4904 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004905 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 name_len = strnlen(fileName, PATH_MAX);
4907 name_len++; /* trailing null */
4908 strncpy(pSMB->FileName, fileName, name_len);
4909 }
4910
4911 params = 6 + name_len;
4912 count = sizeof (FILE_UNIX_BASIC_INFO);
4913 pSMB->MaxParameterCount = cpu_to_le16(2);
4914 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4915 pSMB->MaxSetupCount = 0;
4916 pSMB->Reserved = 0;
4917 pSMB->Flags = 0;
4918 pSMB->Timeout = 0;
4919 pSMB->Reserved2 = 0;
4920 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4921 InformationLevel) - 4;
4922 offset = param_offset + params;
4923 data_offset =
4924 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4925 offset);
4926 memset(data_offset, 0, count);
4927 pSMB->DataOffset = cpu_to_le16(offset);
4928 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4929 pSMB->SetupCount = 1;
4930 pSMB->Reserved3 = 0;
4931 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4932 byte_count = 3 /* pad */ + params + count;
4933 pSMB->ParameterCount = cpu_to_le16(params);
4934 pSMB->DataCount = cpu_to_le16(count);
4935 pSMB->TotalParameterCount = pSMB->ParameterCount;
4936 pSMB->TotalDataCount = pSMB->DataCount;
4937 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4938 pSMB->Reserved4 = 0;
4939 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00004940 /* Samba server ignores set of file size to zero due to bugs in some
4941 older clients, but we should be precise - we use SetFileSize to
4942 set file size and do not want to truncate file size to zero
4943 accidently as happened on one Samba server beta by putting
4944 zero instead of -1 here */
4945 data_offset->EndOfFile = NO_CHANGE_64;
4946 data_offset->NumOfBytes = NO_CHANGE_64;
4947 data_offset->LastStatusChange = NO_CHANGE_64;
4948 data_offset->LastAccessTime = NO_CHANGE_64;
4949 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 data_offset->Uid = cpu_to_le64(uid);
4951 data_offset->Gid = cpu_to_le64(gid);
4952 /* better to leave device as zero when it is */
4953 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4954 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4955 data_offset->Permissions = cpu_to_le64(mode);
4956
4957 if(S_ISREG(mode))
4958 data_offset->Type = cpu_to_le32(UNIX_FILE);
4959 else if(S_ISDIR(mode))
4960 data_offset->Type = cpu_to_le32(UNIX_DIR);
4961 else if(S_ISLNK(mode))
4962 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4963 else if(S_ISCHR(mode))
4964 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4965 else if(S_ISBLK(mode))
4966 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4967 else if(S_ISFIFO(mode))
4968 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4969 else if(S_ISSOCK(mode))
4970 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4971
4972
4973 pSMB->ByteCount = cpu_to_le16(byte_count);
4974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4976 if (rc) {
4977 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4978 }
4979
4980 if (pSMB)
4981 cifs_buf_release(pSMB);
4982 if (rc == -EAGAIN)
4983 goto setPermsRetry;
4984 return rc;
4985}
4986
4987int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004988 const int notify_subdirs, const __u16 netfid,
4989 __u32 filter, struct file * pfile, int multishot,
4990 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991{
4992 int rc = 0;
4993 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004994 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004995 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 int bytes_returned;
4997
4998 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4999 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5000 (void **) &pSMBr);
5001 if (rc)
5002 return rc;
5003
5004 pSMB->TotalParameterCount = 0 ;
5005 pSMB->TotalDataCount = 0;
5006 pSMB->MaxParameterCount = cpu_to_le32(2);
5007 /* BB find exact data count max from sess structure BB */
5008 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005009/* BB VERIFY verify which is correct for above BB */
5010 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5011 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5012
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 pSMB->MaxSetupCount = 4;
5014 pSMB->Reserved = 0;
5015 pSMB->ParameterOffset = 0;
5016 pSMB->DataCount = 0;
5017 pSMB->DataOffset = 0;
5018 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5019 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5020 pSMB->ParameterCount = pSMB->TotalParameterCount;
5021 if(notify_subdirs)
5022 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5023 pSMB->Reserved2 = 0;
5024 pSMB->CompletionFilter = cpu_to_le32(filter);
5025 pSMB->Fid = netfid; /* file handle always le */
5026 pSMB->ByteCount = 0;
5027
5028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5029 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5030 if (rc) {
5031 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005032 } else {
5033 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07005034 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005035 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005036 sizeof(struct dir_notify_req),
5037 GFP_KERNEL);
5038 if(dnotify_req) {
5039 dnotify_req->Pid = pSMB->hdr.Pid;
5040 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5041 dnotify_req->Mid = pSMB->hdr.Mid;
5042 dnotify_req->Tid = pSMB->hdr.Tid;
5043 dnotify_req->Uid = pSMB->hdr.Uid;
5044 dnotify_req->netfid = netfid;
5045 dnotify_req->pfile = pfile;
5046 dnotify_req->filter = filter;
5047 dnotify_req->multishot = multishot;
5048 spin_lock(&GlobalMid_Lock);
5049 list_add_tail(&dnotify_req->lhead,
5050 &GlobalDnotifyReqList);
5051 spin_unlock(&GlobalMid_Lock);
5052 } else
5053 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 }
5055 cifs_buf_release(pSMB);
5056 return rc;
5057}
5058#ifdef CONFIG_CIFS_XATTR
5059ssize_t
5060CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5061 const unsigned char *searchName,
5062 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005063 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064{
5065 /* BB assumes one setup word */
5066 TRANSACTION2_QPI_REQ *pSMB = NULL;
5067 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5068 int rc = 0;
5069 int bytes_returned;
5070 int name_len;
5071 struct fea * temp_fea;
5072 char * temp_ptr;
5073 __u16 params, byte_count;
5074
5075 cFYI(1, ("In Query All EAs path %s", searchName));
5076QAllEAsRetry:
5077 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5078 (void **) &pSMBr);
5079 if (rc)
5080 return rc;
5081
5082 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5083 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005084 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005085 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 name_len++; /* trailing null */
5087 name_len *= 2;
5088 } else { /* BB improve the check for buffer overruns BB */
5089 name_len = strnlen(searchName, PATH_MAX);
5090 name_len++; /* trailing null */
5091 strncpy(pSMB->FileName, searchName, name_len);
5092 }
5093
5094 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5095 pSMB->TotalDataCount = 0;
5096 pSMB->MaxParameterCount = cpu_to_le16(2);
5097 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5098 pSMB->MaxSetupCount = 0;
5099 pSMB->Reserved = 0;
5100 pSMB->Flags = 0;
5101 pSMB->Timeout = 0;
5102 pSMB->Reserved2 = 0;
5103 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5104 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5105 pSMB->DataCount = 0;
5106 pSMB->DataOffset = 0;
5107 pSMB->SetupCount = 1;
5108 pSMB->Reserved3 = 0;
5109 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5110 byte_count = params + 1 /* pad */ ;
5111 pSMB->TotalParameterCount = cpu_to_le16(params);
5112 pSMB->ParameterCount = pSMB->TotalParameterCount;
5113 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5114 pSMB->Reserved4 = 0;
5115 pSMB->hdr.smb_buf_length += byte_count;
5116 pSMB->ByteCount = cpu_to_le16(byte_count);
5117
5118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5120 if (rc) {
5121 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5122 } else { /* decode response */
5123 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5124
5125 /* BB also check enough total bytes returned */
5126 /* BB we need to improve the validity checking
5127 of these trans2 responses */
5128 if (rc || (pSMBr->ByteCount < 4))
5129 rc = -EIO; /* bad smb */
5130 /* else if (pFindData){
5131 memcpy((char *) pFindData,
5132 (char *) &pSMBr->hdr.Protocol +
5133 data_offset, kl);
5134 }*/ else {
5135 /* check that length of list is not more than bcc */
5136 /* check that each entry does not go beyond length
5137 of list */
5138 /* check that each element of each entry does not
5139 go beyond end of list */
5140 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5141 struct fealist * ea_response_data;
5142 rc = 0;
5143 /* validate_trans2_offsets() */
5144 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5145 ea_response_data = (struct fealist *)
5146 (((char *) &pSMBr->hdr.Protocol) +
5147 data_offset);
5148 name_len = le32_to_cpu(ea_response_data->list_len);
5149 cFYI(1,("ea length %d", name_len));
5150 if(name_len <= 8) {
5151 /* returned EA size zeroed at top of function */
5152 cFYI(1,("empty EA list returned from server"));
5153 } else {
5154 /* account for ea list len */
5155 name_len -= 4;
5156 temp_fea = ea_response_data->list;
5157 temp_ptr = (char *)temp_fea;
5158 while(name_len > 0) {
5159 __u16 value_len;
5160 name_len -= 4;
5161 temp_ptr += 4;
5162 rc += temp_fea->name_len;
5163 /* account for prefix user. and trailing null */
5164 rc = rc + 5 + 1;
5165 if(rc<(int)buf_size) {
5166 memcpy(EAData,"user.",5);
5167 EAData+=5;
5168 memcpy(EAData,temp_ptr,temp_fea->name_len);
5169 EAData+=temp_fea->name_len;
5170 /* null terminate name */
5171 *EAData = 0;
5172 EAData = EAData + 1;
5173 } else if(buf_size == 0) {
5174 /* skip copy - calc size only */
5175 } else {
5176 /* stop before overrun buffer */
5177 rc = -ERANGE;
5178 break;
5179 }
5180 name_len -= temp_fea->name_len;
5181 temp_ptr += temp_fea->name_len;
5182 /* account for trailing null */
5183 name_len--;
5184 temp_ptr++;
5185 value_len = le16_to_cpu(temp_fea->value_len);
5186 name_len -= value_len;
5187 temp_ptr += value_len;
5188 /* BB check that temp_ptr is still within smb BB*/
5189 /* no trailing null to account for in value len */
5190 /* go on to next EA */
5191 temp_fea = (struct fea *)temp_ptr;
5192 }
5193 }
5194 }
5195 }
5196 if (pSMB)
5197 cifs_buf_release(pSMB);
5198 if (rc == -EAGAIN)
5199 goto QAllEAsRetry;
5200
5201 return (ssize_t)rc;
5202}
5203
5204ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5205 const unsigned char * searchName,const unsigned char * ea_name,
5206 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005207 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208{
5209 TRANSACTION2_QPI_REQ *pSMB = NULL;
5210 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5211 int rc = 0;
5212 int bytes_returned;
5213 int name_len;
5214 struct fea * temp_fea;
5215 char * temp_ptr;
5216 __u16 params, byte_count;
5217
5218 cFYI(1, ("In Query EA path %s", searchName));
5219QEARetry:
5220 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5221 (void **) &pSMBr);
5222 if (rc)
5223 return rc;
5224
5225 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5226 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005227 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005228 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 name_len++; /* trailing null */
5230 name_len *= 2;
5231 } else { /* BB improve the check for buffer overruns BB */
5232 name_len = strnlen(searchName, PATH_MAX);
5233 name_len++; /* trailing null */
5234 strncpy(pSMB->FileName, searchName, name_len);
5235 }
5236
5237 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5238 pSMB->TotalDataCount = 0;
5239 pSMB->MaxParameterCount = cpu_to_le16(2);
5240 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5241 pSMB->MaxSetupCount = 0;
5242 pSMB->Reserved = 0;
5243 pSMB->Flags = 0;
5244 pSMB->Timeout = 0;
5245 pSMB->Reserved2 = 0;
5246 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5247 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5248 pSMB->DataCount = 0;
5249 pSMB->DataOffset = 0;
5250 pSMB->SetupCount = 1;
5251 pSMB->Reserved3 = 0;
5252 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5253 byte_count = params + 1 /* pad */ ;
5254 pSMB->TotalParameterCount = cpu_to_le16(params);
5255 pSMB->ParameterCount = pSMB->TotalParameterCount;
5256 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5257 pSMB->Reserved4 = 0;
5258 pSMB->hdr.smb_buf_length += byte_count;
5259 pSMB->ByteCount = cpu_to_le16(byte_count);
5260
5261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5263 if (rc) {
5264 cFYI(1, ("Send error in Query EA = %d", rc));
5265 } else { /* decode response */
5266 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5267
5268 /* BB also check enough total bytes returned */
5269 /* BB we need to improve the validity checking
5270 of these trans2 responses */
5271 if (rc || (pSMBr->ByteCount < 4))
5272 rc = -EIO; /* bad smb */
5273 /* else if (pFindData){
5274 memcpy((char *) pFindData,
5275 (char *) &pSMBr->hdr.Protocol +
5276 data_offset, kl);
5277 }*/ else {
5278 /* check that length of list is not more than bcc */
5279 /* check that each entry does not go beyond length
5280 of list */
5281 /* check that each element of each entry does not
5282 go beyond end of list */
5283 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5284 struct fealist * ea_response_data;
5285 rc = -ENODATA;
5286 /* validate_trans2_offsets() */
5287 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5288 ea_response_data = (struct fealist *)
5289 (((char *) &pSMBr->hdr.Protocol) +
5290 data_offset);
5291 name_len = le32_to_cpu(ea_response_data->list_len);
5292 cFYI(1,("ea length %d", name_len));
5293 if(name_len <= 8) {
5294 /* returned EA size zeroed at top of function */
5295 cFYI(1,("empty EA list returned from server"));
5296 } else {
5297 /* account for ea list len */
5298 name_len -= 4;
5299 temp_fea = ea_response_data->list;
5300 temp_ptr = (char *)temp_fea;
5301 /* loop through checking if we have a matching
5302 name and then return the associated value */
5303 while(name_len > 0) {
5304 __u16 value_len;
5305 name_len -= 4;
5306 temp_ptr += 4;
5307 value_len = le16_to_cpu(temp_fea->value_len);
5308 /* BB validate that value_len falls within SMB,
5309 even though maximum for name_len is 255 */
5310 if(memcmp(temp_fea->name,ea_name,
5311 temp_fea->name_len) == 0) {
5312 /* found a match */
5313 rc = value_len;
5314 /* account for prefix user. and trailing null */
5315 if(rc<=(int)buf_size) {
5316 memcpy(ea_value,
5317 temp_fea->name+temp_fea->name_len+1,
5318 rc);
5319 /* ea values, unlike ea names,
5320 are not null terminated */
5321 } else if(buf_size == 0) {
5322 /* skip copy - calc size only */
5323 } else {
5324 /* stop before overrun buffer */
5325 rc = -ERANGE;
5326 }
5327 break;
5328 }
5329 name_len -= temp_fea->name_len;
5330 temp_ptr += temp_fea->name_len;
5331 /* account for trailing null */
5332 name_len--;
5333 temp_ptr++;
5334 name_len -= value_len;
5335 temp_ptr += value_len;
5336 /* no trailing null to account for in value len */
5337 /* go on to next EA */
5338 temp_fea = (struct fea *)temp_ptr;
5339 }
5340 }
5341 }
5342 }
5343 if (pSMB)
5344 cifs_buf_release(pSMB);
5345 if (rc == -EAGAIN)
5346 goto QEARetry;
5347
5348 return (ssize_t)rc;
5349}
5350
5351int
5352CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5353 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005354 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5355 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356{
5357 struct smb_com_transaction2_spi_req *pSMB = NULL;
5358 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5359 struct fealist *parm_data;
5360 int name_len;
5361 int rc = 0;
5362 int bytes_returned = 0;
5363 __u16 params, param_offset, byte_count, offset, count;
5364
5365 cFYI(1, ("In SetEA"));
5366SetEARetry:
5367 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5368 (void **) &pSMBr);
5369 if (rc)
5370 return rc;
5371
5372 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5373 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005374 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005375 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 name_len++; /* trailing null */
5377 name_len *= 2;
5378 } else { /* BB improve the check for buffer overruns BB */
5379 name_len = strnlen(fileName, PATH_MAX);
5380 name_len++; /* trailing null */
5381 strncpy(pSMB->FileName, fileName, name_len);
5382 }
5383
5384 params = 6 + name_len;
5385
5386 /* done calculating parms using name_len of file name,
5387 now use name_len to calculate length of ea name
5388 we are going to create in the inode xattrs */
5389 if(ea_name == NULL)
5390 name_len = 0;
5391 else
5392 name_len = strnlen(ea_name,255);
5393
5394 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5395 pSMB->MaxParameterCount = cpu_to_le16(2);
5396 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5397 pSMB->MaxSetupCount = 0;
5398 pSMB->Reserved = 0;
5399 pSMB->Flags = 0;
5400 pSMB->Timeout = 0;
5401 pSMB->Reserved2 = 0;
5402 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5403 InformationLevel) - 4;
5404 offset = param_offset + params;
5405 pSMB->InformationLevel =
5406 cpu_to_le16(SMB_SET_FILE_EA);
5407
5408 parm_data =
5409 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5410 offset);
5411 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5412 pSMB->DataOffset = cpu_to_le16(offset);
5413 pSMB->SetupCount = 1;
5414 pSMB->Reserved3 = 0;
5415 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5416 byte_count = 3 /* pad */ + params + count;
5417 pSMB->DataCount = cpu_to_le16(count);
5418 parm_data->list_len = cpu_to_le32(count);
5419 parm_data->list[0].EA_flags = 0;
5420 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005421 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 /* EA names are always ASCII */
5423 if(ea_name)
5424 strncpy(parm_data->list[0].name,ea_name,name_len);
5425 parm_data->list[0].name[name_len] = 0;
5426 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5427 /* caller ensures that ea_value_len is less than 64K but
5428 we need to ensure that it fits within the smb */
5429
5430 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5431 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5432 if(ea_value_len)
5433 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5434
5435 pSMB->TotalDataCount = pSMB->DataCount;
5436 pSMB->ParameterCount = cpu_to_le16(params);
5437 pSMB->TotalParameterCount = pSMB->ParameterCount;
5438 pSMB->Reserved4 = 0;
5439 pSMB->hdr.smb_buf_length += byte_count;
5440 pSMB->ByteCount = cpu_to_le16(byte_count);
5441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5443 if (rc) {
5444 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5445 }
5446
5447 cifs_buf_release(pSMB);
5448
5449 if (rc == -EAGAIN)
5450 goto SetEARetry;
5451
5452 return rc;
5453}
5454
5455#endif