blob: 57419a176688356cec33d80e2c89d22b13d0fedc [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)))
429 secFlags = ses->overrideSecFlg;
430 else /* if override flags set only sign/seal OR them with global auth */
431 secFlags = extended_security | ses->overrideSecFlg;
432
Steve Frenchf40c5622006-06-28 00:13:38 +0000433 cFYI(1,("secFlags 0x%x",secFlags));
434
Steve French1982c342005-08-17 12:38:22 -0700435 pSMB->hdr.Mid = GetNextMid(server);
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 French254e55e2006-06-04 05:53:15 +0000636 if(sign_CIFS_PDUs == FALSE) {
637 if(server->secMode & SECMODE_SIGN_REQUIRED)
638 cERROR(1,("Server requires "
639 "/proc/fs/cifs/PacketSigningEnabled to be on"));
640 server->secMode &=
641 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
642 } else if(sign_CIFS_PDUs == 1) {
643 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
644 server->secMode &=
645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
646 } else if(sign_CIFS_PDUs == 2) {
647 if((server->secMode &
648 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
649 cERROR(1,("signing required but server lacks support"));
650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
Steve French39798772006-05-31 22:40:51 +0000652neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700653 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000654
655 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 return rc;
657}
658
659int
660CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
661{
662 struct smb_hdr *smb_buffer;
663 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
664 int rc = 0;
665 int length;
666
667 cFYI(1, ("In tree disconnect"));
668 /*
669 * If last user of the connection and
670 * connection alive - disconnect it
671 * If this is the last connection on the server session disconnect it
672 * (and inside session disconnect we should check if tcp socket needs
673 * to be freed and kernel thread woken up).
674 */
675 if (tcon)
676 down(&tcon->tconSem);
677 else
678 return -EIO;
679
680 atomic_dec(&tcon->useCount);
681 if (atomic_read(&tcon->useCount) > 0) {
682 up(&tcon->tconSem);
683 return -EBUSY;
684 }
685
686 /* No need to return error on this operation if tid invalidated and
687 closed on server already e.g. due to tcp session crashing */
688 if(tcon->tidStatus == CifsNeedReconnect) {
689 up(&tcon->tconSem);
690 return 0;
691 }
692
693 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
694 up(&tcon->tconSem);
695 return -EIO;
696 }
Steve French09d1db52005-04-28 22:41:08 -0700697 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
698 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (rc) {
700 up(&tcon->tconSem);
701 return rc;
702 } else {
703 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
706 &length, 0);
707 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700708 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 if (smb_buffer)
711 cifs_small_buf_release(smb_buffer);
712 up(&tcon->tconSem);
713
714 /* No need to return error on this operation if tid invalidated and
715 closed on server already e.g. due to tcp session crashing */
716 if (rc == -EAGAIN)
717 rc = 0;
718
719 return rc;
720}
721
722int
723CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
724{
725 struct smb_hdr *smb_buffer_response;
726 LOGOFF_ANDX_REQ *pSMB;
727 int rc = 0;
728 int length;
729
730 cFYI(1, ("In SMBLogoff for session disconnect"));
731 if (ses)
732 down(&ses->sesSem);
733 else
734 return -EIO;
735
736 atomic_dec(&ses->inUse);
737 if (atomic_read(&ses->inUse) > 0) {
738 up(&ses->sesSem);
739 return -EBUSY;
740 }
741 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
742 if (rc) {
743 up(&ses->sesSem);
744 return rc;
745 }
746
747 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
748
749 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700750 pSMB->hdr.Mid = GetNextMid(ses->server);
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if(ses->server->secMode &
753 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
754 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
755 }
756
757 pSMB->hdr.Uid = ses->Suid;
758
759 pSMB->AndXCommand = 0xFF;
760 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
761 smb_buffer_response, &length, 0);
762 if (ses->server) {
763 atomic_dec(&ses->server->socketUseCount);
764 if (atomic_read(&ses->server->socketUseCount) == 0) {
765 spin_lock(&GlobalMid_Lock);
766 ses->server->tcpStatus = CifsExiting;
767 spin_unlock(&GlobalMid_Lock);
768 rc = -ESHUTDOWN;
769 }
770 }
Steve Frencha59c6582005-08-17 12:12:19 -0700771 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700772 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774 /* if session dead then we do not need to do ulogoff,
775 since server closed smb session, no sense reporting
776 error */
777 if (rc == -EAGAIN)
778 rc = 0;
779 return rc;
780}
781
782int
Steve French737b7582005-04-28 22:41:06 -0700783CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
784 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
786 DELETE_FILE_REQ *pSMB = NULL;
787 DELETE_FILE_RSP *pSMBr = NULL;
788 int rc = 0;
789 int bytes_returned;
790 int name_len;
791
792DelFileRetry:
793 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
794 (void **) &pSMBr);
795 if (rc)
796 return rc;
797
798 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
799 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500800 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700801 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 name_len++; /* trailing null */
803 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700804 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 name_len = strnlen(fileName, PATH_MAX);
806 name_len++; /* trailing null */
807 strncpy(pSMB->fileName, fileName, name_len);
808 }
809 pSMB->SearchAttributes =
810 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
811 pSMB->BufferFormat = 0x04;
812 pSMB->hdr.smb_buf_length += name_len + 1;
813 pSMB->ByteCount = cpu_to_le16(name_len + 1);
814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700816 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (rc) {
818 cFYI(1, ("Error in RMFile = %d", rc));
819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 cifs_buf_release(pSMB);
822 if (rc == -EAGAIN)
823 goto DelFileRetry;
824
825 return rc;
826}
827
828int
Steve French737b7582005-04-28 22:41:06 -0700829CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
830 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
832 DELETE_DIRECTORY_REQ *pSMB = NULL;
833 DELETE_DIRECTORY_RSP *pSMBr = NULL;
834 int rc = 0;
835 int bytes_returned;
836 int name_len;
837
838 cFYI(1, ("In CIFSSMBRmDir"));
839RmDirRetry:
840 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
841 (void **) &pSMBr);
842 if (rc)
843 return rc;
844
845 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700846 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
847 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 name_len++; /* trailing null */
849 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700850 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 name_len = strnlen(dirName, PATH_MAX);
852 name_len++; /* trailing null */
853 strncpy(pSMB->DirName, dirName, name_len);
854 }
855
856 pSMB->BufferFormat = 0x04;
857 pSMB->hdr.smb_buf_length += name_len + 1;
858 pSMB->ByteCount = cpu_to_le16(name_len + 1);
859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700861 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (rc) {
863 cFYI(1, ("Error in RMDir = %d", rc));
864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 cifs_buf_release(pSMB);
867 if (rc == -EAGAIN)
868 goto RmDirRetry;
869 return rc;
870}
871
872int
873CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700874 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 int rc = 0;
877 CREATE_DIRECTORY_REQ *pSMB = NULL;
878 CREATE_DIRECTORY_RSP *pSMBr = NULL;
879 int bytes_returned;
880 int name_len;
881
882 cFYI(1, ("In CIFSSMBMkDir"));
883MkDirRetry:
884 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
885 (void **) &pSMBr);
886 if (rc)
887 return rc;
888
889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500890 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700891 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 name_len++; /* trailing null */
893 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700894 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 name_len = strnlen(name, PATH_MAX);
896 name_len++; /* trailing null */
897 strncpy(pSMB->DirName, name, name_len);
898 }
899
900 pSMB->BufferFormat = 0x04;
901 pSMB->hdr.smb_buf_length += name_len + 1;
902 pSMB->ByteCount = cpu_to_le16(name_len + 1);
903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700905 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (rc) {
907 cFYI(1, ("Error in Mkdir = %d", rc));
908 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 cifs_buf_release(pSMB);
911 if (rc == -EAGAIN)
912 goto MkDirRetry;
913 return rc;
914}
915
Steve French2dd29d32007-04-23 22:07:35 +0000916int
917CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
918 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
919 __u32 *pOplock, const char *name,
920 const struct nls_table *nls_codepage, int remap)
921{
922 TRANSACTION2_SPI_REQ *pSMB = NULL;
923 TRANSACTION2_SPI_RSP *pSMBr = NULL;
924 int name_len;
925 int rc = 0;
926 int bytes_returned = 0;
927 char *data_offset;
928 __u16 params, param_offset, offset, byte_count, count;
929 OPEN_PSX_REQ * pdata;
930 OPEN_PSX_RSP * psx_rsp;
931
932 cFYI(1, ("In POSIX Create"));
933PsxCreat:
934 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
938
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
940 name_len =
941 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
942 PATH_MAX, nls_codepage, remap);
943 name_len++; /* trailing null */
944 name_len *= 2;
945 } else { /* BB improve the check for buffer overruns BB */
946 name_len = strnlen(name, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->FileName, name, name_len);
949 }
950
951 params = 6 + name_len;
952 count = sizeof(OPEN_PSX_REQ);
953 pSMB->MaxParameterCount = cpu_to_le16(2);
954 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
955 pSMB->MaxSetupCount = 0;
956 pSMB->Reserved = 0;
957 pSMB->Flags = 0;
958 pSMB->Timeout = 0;
959 pSMB->Reserved2 = 0;
960 param_offset = offsetof(struct smb_com_transaction2_spi_req,
961 InformationLevel) - 4;
962 offset = param_offset + params;
963 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
964 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
965 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
966 pdata->Permissions = cpu_to_le64(mode);
967 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
968 pdata->OpenFlags = cpu_to_le32(*pOplock);
969 pSMB->ParameterOffset = cpu_to_le16(param_offset);
970 pSMB->DataOffset = cpu_to_le16(offset);
971 pSMB->SetupCount = 1;
972 pSMB->Reserved3 = 0;
973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
974 byte_count = 3 /* pad */ + params + count;
975
976 pSMB->DataCount = cpu_to_le16(count);
977 pSMB->ParameterCount = cpu_to_le16(params);
978 pSMB->TotalDataCount = pSMB->DataCount;
979 pSMB->TotalParameterCount = pSMB->ParameterCount;
980 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
981 pSMB->Reserved4 = 0;
982 pSMB->hdr.smb_buf_length += byte_count;
983 pSMB->ByteCount = cpu_to_le16(byte_count);
984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
986 if (rc) {
987 cFYI(1, ("Posix create returned %d", rc));
988 goto psx_create_err;
989 }
990
991 cFYI(1,("copying inode info"));
992 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
993
994 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
995 rc = -EIO; /* bad smb */
996 goto psx_create_err;
997 }
998
999 /* copy return information to pRetData */
1000 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1001 + le16_to_cpu(pSMBr->t2.DataOffset));
1002
1003 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1004 if(netfid)
1005 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1006 /* Let caller know file was created so we can set the mode. */
1007 /* Do we care about the CreateAction in any other cases? */
1008 if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1009 *pOplock |= CIFS_CREATE_ACTION;
1010 /* check to make sure response data is there */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001011 if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
1012 pRetData->Type = -1; /* unknown */
1013#ifdef CONFIG_CIFS_DEBUG2
1014 cFYI(1,("unknown type"));
1015#endif
1016 } else {
Steve French2dd29d32007-04-23 22:07:35 +00001017 if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1018 + sizeof(FILE_UNIX_BASIC_INFO)) {
1019 cERROR(1,("Open response data too small"));
1020 pRetData->Type = -1;
1021 goto psx_create_err;
1022 }
1023 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001024 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French2dd29d32007-04-23 22:07:35 +00001025 sizeof (FILE_UNIX_BASIC_INFO));
1026 }
1027
1028
1029psx_create_err:
1030 cifs_buf_release(pSMB);
1031
1032 cifs_stats_inc(&tcon->num_mkdirs);
1033
1034 if (rc == -EAGAIN)
1035 goto PsxCreat;
1036
1037 return rc;
1038}
1039
Steve Frencha9d02ad2005-08-24 23:06:05 -07001040static __u16 convert_disposition(int disposition)
1041{
1042 __u16 ofun = 0;
1043
1044 switch (disposition) {
1045 case FILE_SUPERSEDE:
1046 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1047 break;
1048 case FILE_OPEN:
1049 ofun = SMBOPEN_OAPPEND;
1050 break;
1051 case FILE_CREATE:
1052 ofun = SMBOPEN_OCREATE;
1053 break;
1054 case FILE_OPEN_IF:
1055 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1056 break;
1057 case FILE_OVERWRITE:
1058 ofun = SMBOPEN_OTRUNC;
1059 break;
1060 case FILE_OVERWRITE_IF:
1061 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1062 break;
1063 default:
1064 cFYI(1,("unknown disposition %d",disposition));
1065 ofun = SMBOPEN_OAPPEND; /* regular open */
1066 }
1067 return ofun;
1068}
1069
1070int
1071SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1072 const char *fileName, const int openDisposition,
1073 const int access_flags, const int create_options, __u16 * netfid,
1074 int *pOplock, FILE_ALL_INFO * pfile_info,
1075 const struct nls_table *nls_codepage, int remap)
1076{
1077 int rc = -EACCES;
1078 OPENX_REQ *pSMB = NULL;
1079 OPENX_RSP *pSMBr = NULL;
1080 int bytes_returned;
1081 int name_len;
1082 __u16 count;
1083
1084OldOpenRetry:
1085 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1086 (void **) &pSMBr);
1087 if (rc)
1088 return rc;
1089
1090 pSMB->AndXCommand = 0xFF; /* none */
1091
1092 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1093 count = 1; /* account for one byte pad to word boundary */
1094 name_len =
1095 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1096 fileName, PATH_MAX, nls_codepage, remap);
1097 name_len++; /* trailing null */
1098 name_len *= 2;
1099 } else { /* BB improve check for buffer overruns BB */
1100 count = 0; /* no pad */
1101 name_len = strnlen(fileName, PATH_MAX);
1102 name_len++; /* trailing null */
1103 strncpy(pSMB->fileName, fileName, name_len);
1104 }
1105 if (*pOplock & REQ_OPLOCK)
1106 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1107 else if (*pOplock & REQ_BATCHOPLOCK) {
1108 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1109 }
1110 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1111 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1112 /* 0 = read
1113 1 = write
1114 2 = rw
1115 3 = execute
1116 */
1117 pSMB->Mode = cpu_to_le16(2);
1118 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1119 /* set file as system file if special file such
1120 as fifo and server expecting SFU style and
1121 no Unix extensions */
1122
1123 if(create_options & CREATE_OPTION_SPECIAL)
1124 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1125 else
Steve French3e87d802005-09-18 20:49:21 -07001126 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001127
1128 /* if ((omode & S_IWUGO) == 0)
1129 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1130 /* Above line causes problems due to vfs splitting create into two
1131 pieces - need to set mode after file created not while it is
1132 being created */
1133
1134 /* BB FIXME BB */
1135/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
1136 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001137
1138 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001139 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001140 count += name_len;
1141 pSMB->hdr.smb_buf_length += count;
1142
1143 pSMB->ByteCount = cpu_to_le16(count);
1144 /* long_op set to 1 to allow for oplock break timeouts */
1145 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1146 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1147 cifs_stats_inc(&tcon->num_opens);
1148 if (rc) {
1149 cFYI(1, ("Error in Open = %d", rc));
1150 } else {
1151 /* BB verify if wct == 15 */
1152
1153/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1154
1155 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1156 /* Let caller know file was created so we can set the mode. */
1157 /* Do we care about the CreateAction in any other cases? */
1158 /* BB FIXME BB */
1159/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1160 *pOplock |= CIFS_CREATE_ACTION; */
1161 /* BB FIXME END */
1162
1163 if(pfile_info) {
1164 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1165 pfile_info->LastAccessTime = 0; /* BB fixme */
1166 pfile_info->LastWriteTime = 0; /* BB fixme */
1167 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001168 pfile_info->Attributes =
1169 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001170 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001171 pfile_info->AllocationSize =
1172 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1173 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 pfile_info->NumberOfLinks = cpu_to_le32(1);
1175 }
1176 }
1177
1178 cifs_buf_release(pSMB);
1179 if (rc == -EAGAIN)
1180 goto OldOpenRetry;
1181 return rc;
1182}
1183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184int
1185CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1186 const char *fileName, const int openDisposition,
1187 const int access_flags, const int create_options, __u16 * netfid,
1188 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001189 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190{
1191 int rc = -EACCES;
1192 OPEN_REQ *pSMB = NULL;
1193 OPEN_RSP *pSMBr = NULL;
1194 int bytes_returned;
1195 int name_len;
1196 __u16 count;
1197
1198openRetry:
1199 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1200 (void **) &pSMBr);
1201 if (rc)
1202 return rc;
1203
1204 pSMB->AndXCommand = 0xFF; /* none */
1205
1206 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1207 count = 1; /* account for one byte pad to word boundary */
1208 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001209 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001210 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 name_len++; /* trailing null */
1212 name_len *= 2;
1213 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001214 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 count = 0; /* no pad */
1216 name_len = strnlen(fileName, PATH_MAX);
1217 name_len++; /* trailing null */
1218 pSMB->NameLength = cpu_to_le16(name_len);
1219 strncpy(pSMB->fileName, fileName, name_len);
1220 }
1221 if (*pOplock & REQ_OPLOCK)
1222 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1223 else if (*pOplock & REQ_BATCHOPLOCK) {
1224 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1225 }
1226 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1227 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001228 /* set file as system file if special file such
1229 as fifo and server expecting SFU style and
1230 no Unix extensions */
1231 if(create_options & CREATE_OPTION_SPECIAL)
1232 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1233 else
1234 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 /* XP does not handle ATTR_POSIX_SEMANTICS */
1236 /* but it helps speed up case sensitive checks for other
1237 servers such as Samba */
1238 if (tcon->ses->capabilities & CAP_UNIX)
1239 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1240
1241 /* if ((omode & S_IWUGO) == 0)
1242 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1243 /* Above line causes problems due to vfs splitting create into two
1244 pieces - need to set mode after file created not while it is
1245 being created */
1246 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1247 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001248 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001249 /* BB Expirement with various impersonation levels and verify */
1250 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 pSMB->SecurityFlags =
1252 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1253
1254 count += name_len;
1255 pSMB->hdr.smb_buf_length += count;
1256
1257 pSMB->ByteCount = cpu_to_le16(count);
1258 /* long_op set to 1 to allow for oplock break timeouts */
1259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1260 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001261 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 if (rc) {
1263 cFYI(1, ("Error in Open = %d", rc));
1264 } else {
Steve French09d1db52005-04-28 22:41:08 -07001265 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1267 /* Let caller know file was created so we can set the mode. */
1268 /* Do we care about the CreateAction in any other cases? */
1269 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1270 *pOplock |= CIFS_CREATE_ACTION;
1271 if(pfile_info) {
1272 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1273 36 /* CreationTime to Attributes */);
1274 /* the file_info buf is endian converted by caller */
1275 pfile_info->AllocationSize = pSMBr->AllocationSize;
1276 pfile_info->EndOfFile = pSMBr->EndOfFile;
1277 pfile_info->NumberOfLinks = cpu_to_le32(1);
1278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 cifs_buf_release(pSMB);
1282 if (rc == -EAGAIN)
1283 goto openRetry;
1284 return rc;
1285}
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287int
1288CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001289 const int netfid, const unsigned int count,
1290 const __u64 lseek, unsigned int *nbytes, char **buf,
1291 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292{
1293 int rc = -EACCES;
1294 READ_REQ *pSMB = NULL;
1295 READ_RSP *pSMBr = NULL;
1296 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001297 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001298 int resp_buf_type = 0;
1299 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001302 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1303 wct = 12;
1304 else
1305 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
1307 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001308 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 if (rc)
1310 return rc;
1311
1312 /* tcon and ses pointer are checked in smb_init */
1313 if (tcon->ses->server == NULL)
1314 return -ECONNABORTED;
1315
Steve Frenchec637e32005-12-12 20:53:18 -08001316 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 pSMB->Fid = netfid;
1318 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001319 if(wct == 12)
1320 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001321 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1322 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 pSMB->Remaining = 0;
1325 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1326 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001327 if(wct == 12)
1328 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1329 else {
1330 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001331 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001332 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001333 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001334 }
Steve Frenchec637e32005-12-12 20:53:18 -08001335
1336 iov[0].iov_base = (char *)pSMB;
1337 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1338 rc = SendReceive2(xid, tcon->ses, iov,
1339 1 /* num iovecs */,
1340 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001341 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001342 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 if (rc) {
1344 cERROR(1, ("Send error in read = %d", rc));
1345 } else {
1346 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1347 data_length = data_length << 16;
1348 data_length += le16_to_cpu(pSMBr->DataLength);
1349 *nbytes = data_length;
1350
1351 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001352 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 || (data_length > count)) {
1354 cFYI(1,("bad length %d for count %d",data_length,count));
1355 rc = -EIO;
1356 *nbytes = 0;
1357 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001358 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001360/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1361 cERROR(1,("Faulting on read rc = %d",rc));
1362 rc = -EFAULT;
1363 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001365 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 }
1367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
Steve French4b8f9302006-02-26 16:41:18 +00001369/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001370 if(*buf) {
1371 if(resp_buf_type == CIFS_SMALL_BUFFER)
1372 cifs_small_buf_release(iov[0].iov_base);
1373 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1374 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001375 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1376 /* return buffer to caller to free */
1377 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001378 if(resp_buf_type == CIFS_SMALL_BUFFER)
1379 *pbuf_type = CIFS_SMALL_BUFFER;
1380 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1381 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001382 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001383
1384 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 since file handle passed in no longer valid */
1386 return rc;
1387}
1388
Steve Frenchec637e32005-12-12 20:53:18 -08001389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390int
1391CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1392 const int netfid, const unsigned int count,
1393 const __u64 offset, unsigned int *nbytes, const char *buf,
1394 const char __user * ubuf, const int long_op)
1395{
1396 int rc = -EACCES;
1397 WRITE_REQ *pSMB = NULL;
1398 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001399 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 __u32 bytes_sent;
1401 __u16 byte_count;
1402
1403 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001404 if(tcon->ses == NULL)
1405 return -ECONNABORTED;
1406
1407 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1408 wct = 14;
1409 else
1410 wct = 12;
1411
1412 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 (void **) &pSMBr);
1414 if (rc)
1415 return rc;
1416 /* tcon and ses pointer are checked in smb_init */
1417 if (tcon->ses->server == NULL)
1418 return -ECONNABORTED;
1419
1420 pSMB->AndXCommand = 0xFF; /* none */
1421 pSMB->Fid = netfid;
1422 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001423 if(wct == 14)
1424 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1425 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1426 return -EIO;
1427
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 pSMB->Reserved = 0xFFFFFFFF;
1429 pSMB->WriteMode = 0;
1430 pSMB->Remaining = 0;
1431
1432 /* Can increase buffer size if buffer is big enough in some cases - ie we
1433 can send more if LARGE_WRITE_X capability returned by the server and if
1434 our buffer is big enough or if we convert to iovecs on socket writes
1435 and eliminate the copy to the CIFS buffer */
1436 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1437 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1438 } else {
1439 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1440 & ~0xFF;
1441 }
1442
1443 if (bytes_sent > count)
1444 bytes_sent = count;
1445 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001446 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 if(buf)
1448 memcpy(pSMB->Data,buf,bytes_sent);
1449 else if(ubuf) {
1450 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1451 cifs_buf_release(pSMB);
1452 return -EFAULT;
1453 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001454 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 /* No buffer */
1456 cifs_buf_release(pSMB);
1457 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001458 } /* else setting file size with write of zero bytes */
1459 if(wct == 14)
1460 byte_count = bytes_sent + 1; /* pad */
1461 else /* wct == 12 */ {
1462 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1465 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001466 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001467
1468 if(wct == 14)
1469 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001470 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001471 struct smb_com_writex_req * pSMBW =
1472 (struct smb_com_writex_req *)pSMB;
1473 pSMBW->ByteCount = cpu_to_le16(byte_count);
1474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1477 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001478 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 if (rc) {
1480 cFYI(1, ("Send error in write = %d", rc));
1481 *nbytes = 0;
1482 } else {
1483 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1484 *nbytes = (*nbytes) << 16;
1485 *nbytes += le16_to_cpu(pSMBr->Count);
1486 }
1487
1488 cifs_buf_release(pSMB);
1489
1490 /* Note: On -EAGAIN error only caller can retry on handle based calls
1491 since file handle passed in no longer valid */
1492
1493 return rc;
1494}
1495
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001496int
1497CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001499 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1500 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501{
1502 int rc = -EACCES;
1503 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001504 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001505 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001506 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
Steve Frenchff7feac2005-11-15 16:45:16 -08001508 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1509
Steve French8cc64c62005-10-03 13:49:43 -07001510 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1511 wct = 14;
1512 else
1513 wct = 12;
1514 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 if (rc)
1516 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 /* tcon and ses pointer are checked in smb_init */
1518 if (tcon->ses->server == NULL)
1519 return -ECONNABORTED;
1520
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001521 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 pSMB->Fid = netfid;
1523 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001524 if(wct == 14)
1525 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1526 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1527 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 pSMB->Reserved = 0xFFFFFFFF;
1529 pSMB->WriteMode = 0;
1530 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001531
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 pSMB->DataOffset =
1533 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1534
Steve French3e844692005-10-03 13:37:24 -07001535 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1536 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001537 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001538 if(wct == 14)
1539 pSMB->hdr.smb_buf_length += count+1;
1540 else /* wct == 12 */
1541 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1542 if(wct == 14)
1543 pSMB->ByteCount = cpu_to_le16(count + 1);
1544 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1545 struct smb_com_writex_req * pSMBW =
1546 (struct smb_com_writex_req *)pSMB;
1547 pSMBW->ByteCount = cpu_to_le16(count + 5);
1548 }
Steve French3e844692005-10-03 13:37:24 -07001549 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001550 if(wct == 14)
1551 iov[0].iov_len = smb_hdr_len + 4;
1552 else /* wct == 12 pad bigger by four bytes */
1553 iov[0].iov_len = smb_hdr_len + 8;
1554
Steve French3e844692005-10-03 13:37:24 -07001555
Steve Frenchec637e32005-12-12 20:53:18 -08001556 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001557 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001558 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001560 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001562 } else if(resp_buf_type == 0) {
1563 /* presumably this can not happen, but best to be safe */
1564 rc = -EIO;
1565 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001566 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001567 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001568 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1569 *nbytes = (*nbytes) << 16;
1570 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Steve French4b8f9302006-02-26 16:41:18 +00001573/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001574 if(resp_buf_type == CIFS_SMALL_BUFFER)
1575 cifs_small_buf_release(iov[0].iov_base);
1576 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1577 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
1579 /* Note: On -EAGAIN error only caller can retry on handle based calls
1580 since file handle passed in no longer valid */
1581
1582 return rc;
1583}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001584
1585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586int
1587CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1588 const __u16 smb_file_id, const __u64 len,
1589 const __u64 offset, const __u32 numUnlock,
1590 const __u32 numLock, const __u8 lockType, const int waitFlag)
1591{
1592 int rc = 0;
1593 LOCK_REQ *pSMB = NULL;
1594 LOCK_RSP *pSMBr = NULL;
1595 int bytes_returned;
1596 int timeout = 0;
1597 __u16 count;
1598
1599 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001600 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1601
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 if (rc)
1603 return rc;
1604
Steve French46810cb2005-04-28 22:41:09 -07001605 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1608 timeout = -1; /* no response expected */
1609 pSMB->Timeout = 0;
1610 } else if (waitFlag == TRUE) {
1611 timeout = 3; /* blocking operation, no timeout */
1612 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1613 } else {
1614 pSMB->Timeout = 0;
1615 }
1616
1617 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1618 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1619 pSMB->LockType = lockType;
1620 pSMB->AndXCommand = 0xFF; /* none */
1621 pSMB->Fid = smb_file_id; /* netfid stays le */
1622
1623 if((numLock != 0) || (numUnlock != 0)) {
1624 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1625 /* BB where to store pid high? */
1626 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1627 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1628 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1629 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1630 count = sizeof(LOCKING_ANDX_RANGE);
1631 } else {
1632 /* oplock break */
1633 count = 0;
1634 }
1635 pSMB->hdr.smb_buf_length += count;
1636 pSMB->ByteCount = cpu_to_le16(count);
1637
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001638 if (waitFlag) {
1639 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1640 (struct smb_hdr *) pSMBr, &bytes_returned);
1641 } else {
1642 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001644 }
Steve Frencha4544342005-08-24 13:59:35 -07001645 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 if (rc) {
1647 cFYI(1, ("Send error in Lock = %d", rc));
1648 }
Steve French46810cb2005-04-28 22:41:09 -07001649 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
1651 /* Note: On -EAGAIN error only caller can retry on handle based calls
1652 since file handle passed in no longer valid */
1653 return rc;
1654}
1655
1656int
Steve French08547b02006-02-28 22:39:25 +00001657CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1658 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001659 struct file_lock *pLockData, const __u16 lock_type,
1660 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001661{
1662 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1663 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1664 char *data_offset;
1665 struct cifs_posix_lock *parm_data;
1666 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001667 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001668 int bytes_returned = 0;
1669 __u16 params, param_offset, offset, byte_count, count;
1670
1671 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001672
1673 if(pLockData == NULL)
1674 return EINVAL;
1675
Steve French08547b02006-02-28 22:39:25 +00001676 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1677
1678 if (rc)
1679 return rc;
1680
1681 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1682
1683 params = 6;
1684 pSMB->MaxSetupCount = 0;
1685 pSMB->Reserved = 0;
1686 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001687 pSMB->Reserved2 = 0;
1688 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1689 offset = param_offset + params;
1690
1691 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1692
1693 count = sizeof(struct cifs_posix_lock);
1694 pSMB->MaxParameterCount = cpu_to_le16(2);
1695 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1696 pSMB->SetupCount = 1;
1697 pSMB->Reserved3 = 0;
1698 if(get_flag)
1699 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1700 else
1701 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1702 byte_count = 3 /* pad */ + params + count;
1703 pSMB->DataCount = cpu_to_le16(count);
1704 pSMB->ParameterCount = cpu_to_le16(params);
1705 pSMB->TotalDataCount = pSMB->DataCount;
1706 pSMB->TotalParameterCount = pSMB->ParameterCount;
1707 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1708 parm_data = (struct cifs_posix_lock *)
1709 (((char *) &pSMB->hdr.Protocol) + offset);
1710
1711 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001712 if(waitFlag) {
1713 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001714 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001715 pSMB->Timeout = cpu_to_le32(-1);
1716 } else
1717 pSMB->Timeout = 0;
1718
Steve French08547b02006-02-28 22:39:25 +00001719 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001720 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001721 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001722
1723 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001724 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001725 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1726 pSMB->Reserved4 = 0;
1727 pSMB->hdr.smb_buf_length += byte_count;
1728 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001729 if (waitFlag) {
1730 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1731 (struct smb_hdr *) pSMBr, &bytes_returned);
1732 } else {
1733 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001734 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001735 }
1736
Steve French08547b02006-02-28 22:39:25 +00001737 if (rc) {
1738 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001739 } else if (get_flag) {
1740 /* lock structure can be returned on get */
1741 __u16 data_offset;
1742 __u16 data_count;
1743 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001744
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001745 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1746 rc = -EIO; /* bad smb */
1747 goto plk_err_exit;
1748 }
1749 if(pLockData == NULL) {
1750 rc = -EINVAL;
1751 goto plk_err_exit;
1752 }
1753 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1754 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1755 if(data_count < sizeof(struct cifs_posix_lock)) {
1756 rc = -EIO;
1757 goto plk_err_exit;
1758 }
1759 parm_data = (struct cifs_posix_lock *)
1760 ((char *)&pSMBr->hdr.Protocol + data_offset);
1761 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1762 pLockData->fl_type = F_UNLCK;
1763 }
1764
1765plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001766 if (pSMB)
1767 cifs_small_buf_release(pSMB);
1768
1769 /* Note: On -EAGAIN error only caller can retry on handle based calls
1770 since file handle passed in no longer valid */
1771
1772 return rc;
1773}
1774
1775
1776int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1778{
1779 int rc = 0;
1780 CLOSE_REQ *pSMB = NULL;
1781 CLOSE_RSP *pSMBr = NULL;
1782 int bytes_returned;
1783 cFYI(1, ("In CIFSSMBClose"));
1784
1785/* do not retry on dead session on close */
1786 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1787 if(rc == -EAGAIN)
1788 return 0;
1789 if (rc)
1790 return rc;
1791
1792 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1793
1794 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001795 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 pSMB->ByteCount = 0;
1797 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1798 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001799 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 if (rc) {
1801 if(rc!=-EINTR) {
1802 /* EINTR is expected when user ctl-c to kill app */
1803 cERROR(1, ("Send error in Close = %d", rc));
1804 }
1805 }
1806
1807 cifs_small_buf_release(pSMB);
1808
1809 /* Since session is dead, file will be closed on server already */
1810 if(rc == -EAGAIN)
1811 rc = 0;
1812
1813 return rc;
1814}
1815
1816int
1817CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1818 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001819 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820{
1821 int rc = 0;
1822 RENAME_REQ *pSMB = NULL;
1823 RENAME_RSP *pSMBr = NULL;
1824 int bytes_returned;
1825 int name_len, name_len2;
1826 __u16 count;
1827
1828 cFYI(1, ("In CIFSSMBRename"));
1829renameRetry:
1830 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1831 (void **) &pSMBr);
1832 if (rc)
1833 return rc;
1834
1835 pSMB->BufferFormat = 0x04;
1836 pSMB->SearchAttributes =
1837 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1838 ATTR_DIRECTORY);
1839
1840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1841 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001842 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001843 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 name_len++; /* trailing null */
1845 name_len *= 2;
1846 pSMB->OldFileName[name_len] = 0x04; /* pad */
1847 /* protocol requires ASCII signature byte on Unicode string */
1848 pSMB->OldFileName[name_len + 1] = 0x00;
1849 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001850 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001851 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1853 name_len2 *= 2; /* convert to bytes */
1854 } else { /* BB improve the check for buffer overruns BB */
1855 name_len = strnlen(fromName, PATH_MAX);
1856 name_len++; /* trailing null */
1857 strncpy(pSMB->OldFileName, fromName, name_len);
1858 name_len2 = strnlen(toName, PATH_MAX);
1859 name_len2++; /* trailing null */
1860 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1861 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1862 name_len2++; /* trailing null */
1863 name_len2++; /* signature byte */
1864 }
1865
1866 count = 1 /* 1st signature byte */ + name_len + name_len2;
1867 pSMB->hdr.smb_buf_length += count;
1868 pSMB->ByteCount = cpu_to_le16(count);
1869
1870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001872 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (rc) {
1874 cFYI(1, ("Send error in rename = %d", rc));
1875 }
1876
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 cifs_buf_release(pSMB);
1878
1879 if (rc == -EAGAIN)
1880 goto renameRetry;
1881
1882 return rc;
1883}
1884
1885int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001886 int netfid, char * target_name,
1887 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888{
1889 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1890 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1891 struct set_file_rename * rename_info;
1892 char *data_offset;
1893 char dummy_string[30];
1894 int rc = 0;
1895 int bytes_returned = 0;
1896 int len_of_str;
1897 __u16 params, param_offset, offset, count, byte_count;
1898
1899 cFYI(1, ("Rename to File by handle"));
1900 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1901 (void **) &pSMBr);
1902 if (rc)
1903 return rc;
1904
1905 params = 6;
1906 pSMB->MaxSetupCount = 0;
1907 pSMB->Reserved = 0;
1908 pSMB->Flags = 0;
1909 pSMB->Timeout = 0;
1910 pSMB->Reserved2 = 0;
1911 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1912 offset = param_offset + params;
1913
1914 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1915 rename_info = (struct set_file_rename *) data_offset;
1916 pSMB->MaxParameterCount = cpu_to_le16(2);
1917 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1918 pSMB->SetupCount = 1;
1919 pSMB->Reserved3 = 0;
1920 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1921 byte_count = 3 /* pad */ + params;
1922 pSMB->ParameterCount = cpu_to_le16(params);
1923 pSMB->TotalParameterCount = pSMB->ParameterCount;
1924 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1925 pSMB->DataOffset = cpu_to_le16(offset);
1926 /* construct random name ".cifs_tmp<inodenum><mid>" */
1927 rename_info->overwrite = cpu_to_le32(1);
1928 rename_info->root_fid = 0;
1929 /* unicode only call */
1930 if(target_name == NULL) {
1931 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001932 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001933 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001935 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001936 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 }
1938 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1939 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1940 byte_count += count;
1941 pSMB->DataCount = cpu_to_le16(count);
1942 pSMB->TotalDataCount = pSMB->DataCount;
1943 pSMB->Fid = netfid;
1944 pSMB->InformationLevel =
1945 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1946 pSMB->Reserved4 = 0;
1947 pSMB->hdr.smb_buf_length += byte_count;
1948 pSMB->ByteCount = cpu_to_le16(byte_count);
1949 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1950 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001951 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 if (rc) {
1953 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1954 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001955
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 cifs_buf_release(pSMB);
1957
1958 /* Note: On -EAGAIN error only caller can retry on handle based calls
1959 since file handle passed in no longer valid */
1960
1961 return rc;
1962}
1963
1964int
1965CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1966 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001967 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968{
1969 int rc = 0;
1970 COPY_REQ *pSMB = NULL;
1971 COPY_RSP *pSMBr = NULL;
1972 int bytes_returned;
1973 int name_len, name_len2;
1974 __u16 count;
1975
1976 cFYI(1, ("In CIFSSMBCopy"));
1977copyRetry:
1978 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1979 (void **) &pSMBr);
1980 if (rc)
1981 return rc;
1982
1983 pSMB->BufferFormat = 0x04;
1984 pSMB->Tid2 = target_tid;
1985
1986 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1987
1988 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001989 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001990 fromName, PATH_MAX, nls_codepage,
1991 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 name_len++; /* trailing null */
1993 name_len *= 2;
1994 pSMB->OldFileName[name_len] = 0x04; /* pad */
1995 /* protocol requires ASCII signature byte on Unicode string */
1996 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001997 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001998 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2000 name_len2 *= 2; /* convert to bytes */
2001 } else { /* BB improve the check for buffer overruns BB */
2002 name_len = strnlen(fromName, PATH_MAX);
2003 name_len++; /* trailing null */
2004 strncpy(pSMB->OldFileName, fromName, name_len);
2005 name_len2 = strnlen(toName, PATH_MAX);
2006 name_len2++; /* trailing null */
2007 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2008 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2009 name_len2++; /* trailing null */
2010 name_len2++; /* signature byte */
2011 }
2012
2013 count = 1 /* 1st signature byte */ + name_len + name_len2;
2014 pSMB->hdr.smb_buf_length += count;
2015 pSMB->ByteCount = cpu_to_le16(count);
2016
2017 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2018 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2019 if (rc) {
2020 cFYI(1, ("Send error in copy = %d with %d files copied",
2021 rc, le16_to_cpu(pSMBr->CopyCount)));
2022 }
2023 if (pSMB)
2024 cifs_buf_release(pSMB);
2025
2026 if (rc == -EAGAIN)
2027 goto copyRetry;
2028
2029 return rc;
2030}
2031
2032int
2033CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2034 const char *fromName, const char *toName,
2035 const struct nls_table *nls_codepage)
2036{
2037 TRANSACTION2_SPI_REQ *pSMB = NULL;
2038 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2039 char *data_offset;
2040 int name_len;
2041 int name_len_target;
2042 int rc = 0;
2043 int bytes_returned = 0;
2044 __u16 params, param_offset, offset, byte_count;
2045
2046 cFYI(1, ("In Symlink Unix style"));
2047createSymLinkRetry:
2048 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2049 (void **) &pSMBr);
2050 if (rc)
2051 return rc;
2052
2053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2054 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002055 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 /* find define for this maxpathcomponent */
2057 , nls_codepage);
2058 name_len++; /* trailing null */
2059 name_len *= 2;
2060
2061 } else { /* BB improve the check for buffer overruns BB */
2062 name_len = strnlen(fromName, PATH_MAX);
2063 name_len++; /* trailing null */
2064 strncpy(pSMB->FileName, fromName, name_len);
2065 }
2066 params = 6 + name_len;
2067 pSMB->MaxSetupCount = 0;
2068 pSMB->Reserved = 0;
2069 pSMB->Flags = 0;
2070 pSMB->Timeout = 0;
2071 pSMB->Reserved2 = 0;
2072 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2073 InformationLevel) - 4;
2074 offset = param_offset + params;
2075
2076 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2077 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2078 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002079 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 /* find define for this maxpathcomponent */
2081 , nls_codepage);
2082 name_len_target++; /* trailing null */
2083 name_len_target *= 2;
2084 } else { /* BB improve the check for buffer overruns BB */
2085 name_len_target = strnlen(toName, PATH_MAX);
2086 name_len_target++; /* trailing null */
2087 strncpy(data_offset, toName, name_len_target);
2088 }
2089
2090 pSMB->MaxParameterCount = cpu_to_le16(2);
2091 /* BB find exact max on data count below from sess */
2092 pSMB->MaxDataCount = cpu_to_le16(1000);
2093 pSMB->SetupCount = 1;
2094 pSMB->Reserved3 = 0;
2095 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2096 byte_count = 3 /* pad */ + params + name_len_target;
2097 pSMB->DataCount = cpu_to_le16(name_len_target);
2098 pSMB->ParameterCount = cpu_to_le16(params);
2099 pSMB->TotalDataCount = pSMB->DataCount;
2100 pSMB->TotalParameterCount = pSMB->ParameterCount;
2101 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2102 pSMB->DataOffset = cpu_to_le16(offset);
2103 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2104 pSMB->Reserved4 = 0;
2105 pSMB->hdr.smb_buf_length += byte_count;
2106 pSMB->ByteCount = cpu_to_le16(byte_count);
2107 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2108 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002109 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 if (rc) {
2111 cFYI(1,
2112 ("Send error in SetPathInfo (create symlink) = %d",
2113 rc));
2114 }
2115
2116 if (pSMB)
2117 cifs_buf_release(pSMB);
2118
2119 if (rc == -EAGAIN)
2120 goto createSymLinkRetry;
2121
2122 return rc;
2123}
2124
2125int
2126CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2127 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002128 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129{
2130 TRANSACTION2_SPI_REQ *pSMB = NULL;
2131 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2132 char *data_offset;
2133 int name_len;
2134 int name_len_target;
2135 int rc = 0;
2136 int bytes_returned = 0;
2137 __u16 params, param_offset, offset, byte_count;
2138
2139 cFYI(1, ("In Create Hard link Unix style"));
2140createHardLinkRetry:
2141 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2142 (void **) &pSMBr);
2143 if (rc)
2144 return rc;
2145
2146 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002147 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002148 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 name_len++; /* trailing null */
2150 name_len *= 2;
2151
2152 } else { /* BB improve the check for buffer overruns BB */
2153 name_len = strnlen(toName, PATH_MAX);
2154 name_len++; /* trailing null */
2155 strncpy(pSMB->FileName, toName, name_len);
2156 }
2157 params = 6 + name_len;
2158 pSMB->MaxSetupCount = 0;
2159 pSMB->Reserved = 0;
2160 pSMB->Flags = 0;
2161 pSMB->Timeout = 0;
2162 pSMB->Reserved2 = 0;
2163 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2164 InformationLevel) - 4;
2165 offset = param_offset + params;
2166
2167 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2168 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2169 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002170 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002171 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 name_len_target++; /* trailing null */
2173 name_len_target *= 2;
2174 } else { /* BB improve the check for buffer overruns BB */
2175 name_len_target = strnlen(fromName, PATH_MAX);
2176 name_len_target++; /* trailing null */
2177 strncpy(data_offset, fromName, name_len_target);
2178 }
2179
2180 pSMB->MaxParameterCount = cpu_to_le16(2);
2181 /* BB find exact max on data count below from sess*/
2182 pSMB->MaxDataCount = cpu_to_le16(1000);
2183 pSMB->SetupCount = 1;
2184 pSMB->Reserved3 = 0;
2185 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2186 byte_count = 3 /* pad */ + params + name_len_target;
2187 pSMB->ParameterCount = cpu_to_le16(params);
2188 pSMB->TotalParameterCount = pSMB->ParameterCount;
2189 pSMB->DataCount = cpu_to_le16(name_len_target);
2190 pSMB->TotalDataCount = pSMB->DataCount;
2191 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2192 pSMB->DataOffset = cpu_to_le16(offset);
2193 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2194 pSMB->Reserved4 = 0;
2195 pSMB->hdr.smb_buf_length += byte_count;
2196 pSMB->ByteCount = cpu_to_le16(byte_count);
2197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002199 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 if (rc) {
2201 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2202 }
2203
2204 cifs_buf_release(pSMB);
2205 if (rc == -EAGAIN)
2206 goto createHardLinkRetry;
2207
2208 return rc;
2209}
2210
2211int
2212CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2213 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002214 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215{
2216 int rc = 0;
2217 NT_RENAME_REQ *pSMB = NULL;
2218 RENAME_RSP *pSMBr = NULL;
2219 int bytes_returned;
2220 int name_len, name_len2;
2221 __u16 count;
2222
2223 cFYI(1, ("In CIFSCreateHardLink"));
2224winCreateHardLinkRetry:
2225
2226 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2227 (void **) &pSMBr);
2228 if (rc)
2229 return rc;
2230
2231 pSMB->SearchAttributes =
2232 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2233 ATTR_DIRECTORY);
2234 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2235 pSMB->ClusterCount = 0;
2236
2237 pSMB->BufferFormat = 0x04;
2238
2239 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2240 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002241 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002242 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 name_len++; /* trailing null */
2244 name_len *= 2;
2245 pSMB->OldFileName[name_len] = 0; /* pad */
2246 pSMB->OldFileName[name_len + 1] = 0x04;
2247 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002248 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002249 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2251 name_len2 *= 2; /* convert to bytes */
2252 } else { /* BB improve the check for buffer overruns BB */
2253 name_len = strnlen(fromName, PATH_MAX);
2254 name_len++; /* trailing null */
2255 strncpy(pSMB->OldFileName, fromName, name_len);
2256 name_len2 = strnlen(toName, PATH_MAX);
2257 name_len2++; /* trailing null */
2258 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2259 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2260 name_len2++; /* trailing null */
2261 name_len2++; /* signature byte */
2262 }
2263
2264 count = 1 /* string type byte */ + name_len + name_len2;
2265 pSMB->hdr.smb_buf_length += count;
2266 pSMB->ByteCount = cpu_to_le16(count);
2267
2268 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2269 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002270 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 if (rc) {
2272 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2273 }
2274 cifs_buf_release(pSMB);
2275 if (rc == -EAGAIN)
2276 goto winCreateHardLinkRetry;
2277
2278 return rc;
2279}
2280
2281int
2282CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2283 const unsigned char *searchName,
2284 char *symlinkinfo, const int buflen,
2285 const struct nls_table *nls_codepage)
2286{
2287/* SMB_QUERY_FILE_UNIX_LINK */
2288 TRANSACTION2_QPI_REQ *pSMB = NULL;
2289 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2290 int rc = 0;
2291 int bytes_returned;
2292 int name_len;
2293 __u16 params, byte_count;
2294
2295 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2296
2297querySymLinkRetry:
2298 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2299 (void **) &pSMBr);
2300 if (rc)
2301 return rc;
2302
2303 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2304 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002305 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 /* find define for this maxpathcomponent */
2307 , nls_codepage);
2308 name_len++; /* trailing null */
2309 name_len *= 2;
2310 } else { /* BB improve the check for buffer overruns BB */
2311 name_len = strnlen(searchName, PATH_MAX);
2312 name_len++; /* trailing null */
2313 strncpy(pSMB->FileName, searchName, name_len);
2314 }
2315
2316 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2317 pSMB->TotalDataCount = 0;
2318 pSMB->MaxParameterCount = cpu_to_le16(2);
2319 /* BB find exact max data count below from sess structure BB */
2320 pSMB->MaxDataCount = cpu_to_le16(4000);
2321 pSMB->MaxSetupCount = 0;
2322 pSMB->Reserved = 0;
2323 pSMB->Flags = 0;
2324 pSMB->Timeout = 0;
2325 pSMB->Reserved2 = 0;
2326 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2327 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2328 pSMB->DataCount = 0;
2329 pSMB->DataOffset = 0;
2330 pSMB->SetupCount = 1;
2331 pSMB->Reserved3 = 0;
2332 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2333 byte_count = params + 1 /* pad */ ;
2334 pSMB->TotalParameterCount = cpu_to_le16(params);
2335 pSMB->ParameterCount = pSMB->TotalParameterCount;
2336 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2337 pSMB->Reserved4 = 0;
2338 pSMB->hdr.smb_buf_length += byte_count;
2339 pSMB->ByteCount = cpu_to_le16(byte_count);
2340
2341 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2342 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2343 if (rc) {
2344 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2345 } else {
2346 /* decode response */
2347
2348 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2349 if (rc || (pSMBr->ByteCount < 2))
2350 /* BB also check enough total bytes returned */
2351 rc = -EIO; /* bad smb */
2352 else {
2353 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2354 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2355
2356 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2357 name_len = UniStrnlen((wchar_t *) ((char *)
2358 &pSMBr->hdr.Protocol +data_offset),
2359 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002360 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002362 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 data_offset),
2364 name_len, nls_codepage);
2365 } else {
2366 strncpy(symlinkinfo,
2367 (char *) &pSMBr->hdr.Protocol +
2368 data_offset,
2369 min_t(const int, buflen, count));
2370 }
2371 symlinkinfo[buflen] = 0;
2372 /* just in case so calling code does not go off the end of buffer */
2373 }
2374 }
2375 cifs_buf_release(pSMB);
2376 if (rc == -EAGAIN)
2377 goto querySymLinkRetry;
2378 return rc;
2379}
2380
Steve French0a4b92c2006-01-12 15:44:21 -08002381/* Initialize NT TRANSACT SMB into small smb request buffer.
2382 This assumes that all NT TRANSACTS that we init here have
2383 total parm and data under about 400 bytes (to fit in small cifs
2384 buffer size), which is the case so far, it easily fits. NB:
2385 Setup words themselves and ByteCount
2386 MaxSetupCount (size of returned setup area) and
2387 MaxParameterCount (returned parms size) must be set by caller */
2388static int
2389smb_init_ntransact(const __u16 sub_command, const int setup_count,
2390 const int parm_len, struct cifsTconInfo *tcon,
2391 void ** ret_buf)
2392{
2393 int rc;
2394 __u32 temp_offset;
2395 struct smb_com_ntransact_req * pSMB;
2396
2397 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2398 (void **)&pSMB);
2399 if (rc)
2400 return rc;
2401 *ret_buf = (void *)pSMB;
2402 pSMB->Reserved = 0;
2403 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2404 pSMB->TotalDataCount = 0;
2405 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2406 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2407 pSMB->ParameterCount = pSMB->TotalParameterCount;
2408 pSMB->DataCount = pSMB->TotalDataCount;
2409 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2410 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2411 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2412 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2413 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2414 pSMB->SubCommand = cpu_to_le16(sub_command);
2415 return 0;
2416}
2417
2418static int
2419validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2420 int * pdatalen, int * pparmlen)
2421{
2422 char * end_of_smb;
2423 __u32 data_count, data_offset, parm_count, parm_offset;
2424 struct smb_com_ntransact_rsp * pSMBr;
2425
2426 if(buf == NULL)
2427 return -EINVAL;
2428
2429 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2430
2431 /* ByteCount was converted from little endian in SendReceive */
2432 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2433 (char *)&pSMBr->ByteCount;
2434
2435
2436 data_offset = le32_to_cpu(pSMBr->DataOffset);
2437 data_count = le32_to_cpu(pSMBr->DataCount);
2438 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2439 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2440
2441 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2442 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2443
2444 /* should we also check that parm and data areas do not overlap? */
2445 if(*ppparm > end_of_smb) {
2446 cFYI(1,("parms start after end of smb"));
2447 return -EINVAL;
2448 } else if(parm_count + *ppparm > end_of_smb) {
2449 cFYI(1,("parm end after end of smb"));
2450 return -EINVAL;
2451 } else if(*ppdata > end_of_smb) {
2452 cFYI(1,("data starts after end of smb"));
2453 return -EINVAL;
2454 } else if(data_count + *ppdata > end_of_smb) {
2455 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2456 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2457 return -EINVAL;
2458 } else if(parm_count + data_count > pSMBr->ByteCount) {
2459 cFYI(1,("parm count and data count larger than SMB"));
2460 return -EINVAL;
2461 }
2462 return 0;
2463}
2464
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465int
2466CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2467 const unsigned char *searchName,
2468 char *symlinkinfo, const int buflen,__u16 fid,
2469 const struct nls_table *nls_codepage)
2470{
2471 int rc = 0;
2472 int bytes_returned;
2473 int name_len;
2474 struct smb_com_transaction_ioctl_req * pSMB;
2475 struct smb_com_transaction_ioctl_rsp * pSMBr;
2476
2477 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2478 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2479 (void **) &pSMBr);
2480 if (rc)
2481 return rc;
2482
2483 pSMB->TotalParameterCount = 0 ;
2484 pSMB->TotalDataCount = 0;
2485 pSMB->MaxParameterCount = cpu_to_le32(2);
2486 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002487 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2488 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 pSMB->MaxSetupCount = 4;
2490 pSMB->Reserved = 0;
2491 pSMB->ParameterOffset = 0;
2492 pSMB->DataCount = 0;
2493 pSMB->DataOffset = 0;
2494 pSMB->SetupCount = 4;
2495 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2496 pSMB->ParameterCount = pSMB->TotalParameterCount;
2497 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2498 pSMB->IsFsctl = 1; /* FSCTL */
2499 pSMB->IsRootFlag = 0;
2500 pSMB->Fid = fid; /* file handle always le */
2501 pSMB->ByteCount = 0;
2502
2503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2505 if (rc) {
2506 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2507 } else { /* decode response */
2508 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2509 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2510 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2511 /* BB also check enough total bytes returned */
2512 rc = -EIO; /* bad smb */
2513 else {
2514 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002515 char * end_of_smb = 2 /* sizeof byte count */ +
2516 pSMBr->ByteCount +
2517 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518
2519 struct reparse_data * reparse_buf = (struct reparse_data *)
2520 ((char *)&pSMBr->hdr.Protocol + data_offset);
2521 if((char*)reparse_buf >= end_of_smb) {
2522 rc = -EIO;
2523 goto qreparse_out;
2524 }
2525 if((reparse_buf->LinkNamesBuf +
2526 reparse_buf->TargetNameOffset +
2527 reparse_buf->TargetNameLen) >
2528 end_of_smb) {
2529 cFYI(1,("reparse buf extended beyond SMB"));
2530 rc = -EIO;
2531 goto qreparse_out;
2532 }
2533
2534 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2535 name_len = UniStrnlen((wchar_t *)
2536 (reparse_buf->LinkNamesBuf +
2537 reparse_buf->TargetNameOffset),
2538 min(buflen/2, reparse_buf->TargetNameLen / 2));
2539 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002540 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 reparse_buf->TargetNameOffset),
2542 name_len, nls_codepage);
2543 } else { /* ASCII names */
2544 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2545 reparse_buf->TargetNameOffset,
2546 min_t(const int, buflen, reparse_buf->TargetNameLen));
2547 }
2548 } else {
2549 rc = -EIO;
2550 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2551 }
2552 symlinkinfo[buflen] = 0; /* just in case so the caller
2553 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002554 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 }
2556 }
2557qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002558 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
2560 /* Note: On -EAGAIN error only caller can retry on handle based calls
2561 since file handle passed in no longer valid */
2562
2563 return rc;
2564}
2565
2566#ifdef CONFIG_CIFS_POSIX
2567
2568/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2569static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2570{
2571 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002572 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2573 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2574 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2576
2577 return;
2578}
2579
2580/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002581static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2582 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583{
2584 int size = 0;
2585 int i;
2586 __u16 count;
2587 struct cifs_posix_ace * pACE;
2588 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2589 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2590
2591 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2592 return -EOPNOTSUPP;
2593
2594 if(acl_type & ACL_TYPE_ACCESS) {
2595 count = le16_to_cpu(cifs_acl->access_entry_count);
2596 pACE = &cifs_acl->ace_array[0];
2597 size = sizeof(struct cifs_posix_acl);
2598 size += sizeof(struct cifs_posix_ace) * count;
2599 /* check if we would go beyond end of SMB */
2600 if(size_of_data_area < size) {
2601 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2602 return -EINVAL;
2603 }
2604 } else if(acl_type & ACL_TYPE_DEFAULT) {
2605 count = le16_to_cpu(cifs_acl->access_entry_count);
2606 size = sizeof(struct cifs_posix_acl);
2607 size += sizeof(struct cifs_posix_ace) * count;
2608/* skip past access ACEs to get to default ACEs */
2609 pACE = &cifs_acl->ace_array[count];
2610 count = le16_to_cpu(cifs_acl->default_entry_count);
2611 size += sizeof(struct cifs_posix_ace) * count;
2612 /* check if we would go beyond end of SMB */
2613 if(size_of_data_area < size)
2614 return -EINVAL;
2615 } else {
2616 /* illegal type */
2617 return -EINVAL;
2618 }
2619
2620 size = posix_acl_xattr_size(count);
2621 if((buflen == 0) || (local_acl == NULL)) {
2622 /* used to query ACL EA size */
2623 } else if(size > buflen) {
2624 return -ERANGE;
2625 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002626 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 for(i = 0;i < count ;i++) {
2628 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2629 pACE ++;
2630 }
2631 }
2632 return size;
2633}
2634
2635static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2636 const posix_acl_xattr_entry * local_ace)
2637{
2638 __u16 rc = 0; /* 0 = ACL converted ok */
2639
Steve Frenchff7feac2005-11-15 16:45:16 -08002640 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2641 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002643 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 /* Probably no need to le convert -1 on any arch but can not hurt */
2645 cifs_ace->cifs_uid = cpu_to_le64(-1);
2646 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002647 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2649 return rc;
2650}
2651
2652/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2653static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2654 const int acl_type)
2655{
2656 __u16 rc = 0;
2657 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2658 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2659 int count;
2660 int i;
2661
2662 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2663 return 0;
2664
2665 count = posix_acl_xattr_count((size_t)buflen);
2666 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002667 count, buflen, le32_to_cpu(local_acl->a_version)));
2668 if(le32_to_cpu(local_acl->a_version) != 2) {
2669 cFYI(1,("unknown POSIX ACL version %d",
2670 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 return 0;
2672 }
2673 cifs_acl->version = cpu_to_le16(1);
2674 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002675 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002677 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 else {
2679 cFYI(1,("unknown ACL type %d",acl_type));
2680 return 0;
2681 }
2682 for(i=0;i<count;i++) {
2683 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2684 &local_acl->a_entries[i]);
2685 if(rc != 0) {
2686 /* ACE not converted */
2687 break;
2688 }
2689 }
2690 if(rc == 0) {
2691 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2692 rc += sizeof(struct cifs_posix_acl);
2693 /* BB add check to make sure ACL does not overflow SMB */
2694 }
2695 return rc;
2696}
2697
2698int
2699CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2700 const unsigned char *searchName,
2701 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002702 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703{
2704/* SMB_QUERY_POSIX_ACL */
2705 TRANSACTION2_QPI_REQ *pSMB = NULL;
2706 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2707 int rc = 0;
2708 int bytes_returned;
2709 int name_len;
2710 __u16 params, byte_count;
2711
2712 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2713
2714queryAclRetry:
2715 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2716 (void **) &pSMBr);
2717 if (rc)
2718 return rc;
2719
2720 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2721 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002722 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002723 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 name_len++; /* trailing null */
2725 name_len *= 2;
2726 pSMB->FileName[name_len] = 0;
2727 pSMB->FileName[name_len+1] = 0;
2728 } else { /* BB improve the check for buffer overruns BB */
2729 name_len = strnlen(searchName, PATH_MAX);
2730 name_len++; /* trailing null */
2731 strncpy(pSMB->FileName, searchName, name_len);
2732 }
2733
2734 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2735 pSMB->TotalDataCount = 0;
2736 pSMB->MaxParameterCount = cpu_to_le16(2);
2737 /* BB find exact max data count below from sess structure BB */
2738 pSMB->MaxDataCount = cpu_to_le16(4000);
2739 pSMB->MaxSetupCount = 0;
2740 pSMB->Reserved = 0;
2741 pSMB->Flags = 0;
2742 pSMB->Timeout = 0;
2743 pSMB->Reserved2 = 0;
2744 pSMB->ParameterOffset = cpu_to_le16(
2745 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2746 pSMB->DataCount = 0;
2747 pSMB->DataOffset = 0;
2748 pSMB->SetupCount = 1;
2749 pSMB->Reserved3 = 0;
2750 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2751 byte_count = params + 1 /* pad */ ;
2752 pSMB->TotalParameterCount = cpu_to_le16(params);
2753 pSMB->ParameterCount = pSMB->TotalParameterCount;
2754 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2755 pSMB->Reserved4 = 0;
2756 pSMB->hdr.smb_buf_length += byte_count;
2757 pSMB->ByteCount = cpu_to_le16(byte_count);
2758
2759 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002761 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 if (rc) {
2763 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2764 } else {
2765 /* decode response */
2766
2767 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2768 if (rc || (pSMBr->ByteCount < 2))
2769 /* BB also check enough total bytes returned */
2770 rc = -EIO; /* bad smb */
2771 else {
2772 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2773 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2774 rc = cifs_copy_posix_acl(acl_inf,
2775 (char *)&pSMBr->hdr.Protocol+data_offset,
2776 buflen,acl_type,count);
2777 }
2778 }
2779 cifs_buf_release(pSMB);
2780 if (rc == -EAGAIN)
2781 goto queryAclRetry;
2782 return rc;
2783}
2784
2785int
2786CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2787 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002788 const char *local_acl, const int buflen,
2789 const int acl_type,
2790 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791{
2792 struct smb_com_transaction2_spi_req *pSMB = NULL;
2793 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2794 char *parm_data;
2795 int name_len;
2796 int rc = 0;
2797 int bytes_returned = 0;
2798 __u16 params, byte_count, data_count, param_offset, offset;
2799
2800 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2801setAclRetry:
2802 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2803 (void **) &pSMBr);
2804 if (rc)
2805 return rc;
2806 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2807 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002808 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002809 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 name_len++; /* trailing null */
2811 name_len *= 2;
2812 } else { /* BB improve the check for buffer overruns BB */
2813 name_len = strnlen(fileName, PATH_MAX);
2814 name_len++; /* trailing null */
2815 strncpy(pSMB->FileName, fileName, name_len);
2816 }
2817 params = 6 + name_len;
2818 pSMB->MaxParameterCount = cpu_to_le16(2);
2819 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2820 pSMB->MaxSetupCount = 0;
2821 pSMB->Reserved = 0;
2822 pSMB->Flags = 0;
2823 pSMB->Timeout = 0;
2824 pSMB->Reserved2 = 0;
2825 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2826 InformationLevel) - 4;
2827 offset = param_offset + params;
2828 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2829 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2830
2831 /* convert to on the wire format for POSIX ACL */
2832 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2833
2834 if(data_count == 0) {
2835 rc = -EOPNOTSUPP;
2836 goto setACLerrorExit;
2837 }
2838 pSMB->DataOffset = cpu_to_le16(offset);
2839 pSMB->SetupCount = 1;
2840 pSMB->Reserved3 = 0;
2841 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2842 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2843 byte_count = 3 /* pad */ + params + data_count;
2844 pSMB->DataCount = cpu_to_le16(data_count);
2845 pSMB->TotalDataCount = pSMB->DataCount;
2846 pSMB->ParameterCount = cpu_to_le16(params);
2847 pSMB->TotalParameterCount = pSMB->ParameterCount;
2848 pSMB->Reserved4 = 0;
2849 pSMB->hdr.smb_buf_length += byte_count;
2850 pSMB->ByteCount = cpu_to_le16(byte_count);
2851 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2852 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2853 if (rc) {
2854 cFYI(1, ("Set POSIX ACL returned %d", rc));
2855 }
2856
2857setACLerrorExit:
2858 cifs_buf_release(pSMB);
2859 if (rc == -EAGAIN)
2860 goto setAclRetry;
2861 return rc;
2862}
2863
Steve Frenchf654bac2005-04-28 22:41:04 -07002864/* BB fix tabs in this function FIXME BB */
2865int
2866CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2867 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2868{
2869 int rc = 0;
2870 struct smb_t2_qfi_req *pSMB = NULL;
2871 struct smb_t2_qfi_rsp *pSMBr = NULL;
2872 int bytes_returned;
2873 __u16 params, byte_count;
2874
2875 cFYI(1,("In GetExtAttr"));
2876 if(tcon == NULL)
2877 return -ENODEV;
2878
2879GetExtAttrRetry:
2880 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2881 (void **) &pSMBr);
2882 if (rc)
2883 return rc;
2884
Steve Frenchc67593a2005-04-28 22:41:04 -07002885 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002886 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002887 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002888 /* BB find exact max data count below from sess structure BB */
2889 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2890 pSMB->t2.MaxSetupCount = 0;
2891 pSMB->t2.Reserved = 0;
2892 pSMB->t2.Flags = 0;
2893 pSMB->t2.Timeout = 0;
2894 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002895 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2896 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002897 pSMB->t2.DataCount = 0;
2898 pSMB->t2.DataOffset = 0;
2899 pSMB->t2.SetupCount = 1;
2900 pSMB->t2.Reserved3 = 0;
2901 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002902 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002903 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2904 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2905 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002906 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002907 pSMB->Fid = netfid;
2908 pSMB->hdr.smb_buf_length += byte_count;
2909 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2910
2911 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2912 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2913 if (rc) {
2914 cFYI(1, ("error %d in GetExtAttr", rc));
2915 } else {
2916 /* decode response */
2917 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2918 if (rc || (pSMBr->ByteCount < 2))
2919 /* BB also check enough total bytes returned */
2920 /* If rc should we check for EOPNOSUPP and
2921 disable the srvino flag? or in caller? */
2922 rc = -EIO; /* bad smb */
2923 else {
2924 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2925 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2926 struct file_chattr_info * pfinfo;
2927 /* BB Do we need a cast or hash here ? */
2928 if(count != 16) {
2929 cFYI(1, ("Illegal size ret in GetExtAttr"));
2930 rc = -EIO;
2931 goto GetExtAttrOut;
2932 }
2933 pfinfo = (struct file_chattr_info *)
2934 (data_offset + (char *) &pSMBr->hdr.Protocol);
2935 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2936 *pMask = le64_to_cpu(pfinfo->mask);
2937 }
2938 }
2939GetExtAttrOut:
2940 cifs_buf_release(pSMB);
2941 if (rc == -EAGAIN)
2942 goto GetExtAttrRetry;
2943 return rc;
2944}
2945
2946
2947#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948
Steve Frencheeac8042006-01-13 21:34:58 -08002949
2950/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002951static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00002952 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002953/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002954static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00002955 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002956
Steve French0a4b92c2006-01-12 15:44:21 -08002957/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002958static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002959{
Steve French0a4b92c2006-01-12 15:44:21 -08002960 return 0;
2961}
2962
2963/* Get Security Descriptor (by handle) from remote server for a file or dir */
2964int
2965CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2966 /* BB fix up return info */ char *acl_inf, const int buflen,
2967 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2968{
2969 int rc = 0;
2970 int buf_type = 0;
2971 QUERY_SEC_DESC_REQ * pSMB;
2972 struct kvec iov[1];
2973
2974 cFYI(1, ("GetCifsACL"));
2975
2976 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2977 8 /* parm len */, tcon, (void **) &pSMB);
2978 if (rc)
2979 return rc;
2980
2981 pSMB->MaxParameterCount = cpu_to_le32(4);
2982 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2983 pSMB->MaxSetupCount = 0;
2984 pSMB->Fid = fid; /* file handle always le */
2985 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2986 CIFS_ACL_DACL);
2987 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2988 pSMB->hdr.smb_buf_length += 11;
2989 iov[0].iov_base = (char *)pSMB;
2990 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2991
2992 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2993 cifs_stats_inc(&tcon->num_acl_get);
2994 if (rc) {
2995 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2996 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002997 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002998 __le32 * parm;
2999 int parm_len;
3000 int data_len;
3001 int acl_len;
3002 struct smb_com_ntransact_rsp * pSMBr;
3003
3004/* validate_nttransact */
3005 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3006 (char **)&psec_desc,
3007 &parm_len, &data_len);
3008
3009 if(rc)
3010 goto qsec_out;
3011 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3012
3013 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
3014
3015 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3016 rc = -EIO; /* bad smb */
3017 goto qsec_out;
3018 }
3019
3020/* BB check that data area is minimum length and as big as acl_len */
3021
3022 acl_len = le32_to_cpu(*(__le32 *)parm);
3023 /* BB check if(acl_len > bufsize) */
3024
3025 parse_sec_desc(psec_desc, acl_len);
3026 }
3027qsec_out:
3028 if(buf_type == CIFS_SMALL_BUFFER)
3029 cifs_small_buf_release(iov[0].iov_base);
3030 else if(buf_type == CIFS_LARGE_BUFFER)
3031 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003032/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003033 return rc;
3034}
3035
Steve French6b8edfe2005-08-23 20:26:03 -07003036/* Legacy Query Path Information call for lookup to old servers such
3037 as Win9x/WinME */
3038int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3039 const unsigned char *searchName,
3040 FILE_ALL_INFO * pFinfo,
3041 const struct nls_table *nls_codepage, int remap)
3042{
3043 QUERY_INFORMATION_REQ * pSMB;
3044 QUERY_INFORMATION_RSP * pSMBr;
3045 int rc = 0;
3046 int bytes_returned;
3047 int name_len;
3048
3049 cFYI(1, ("In SMBQPath path %s", searchName));
3050QInfRetry:
3051 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3052 (void **) &pSMBr);
3053 if (rc)
3054 return rc;
3055
3056 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3057 name_len =
3058 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3059 PATH_MAX, nls_codepage, remap);
3060 name_len++; /* trailing null */
3061 name_len *= 2;
3062 } else {
3063 name_len = strnlen(searchName, PATH_MAX);
3064 name_len++; /* trailing null */
3065 strncpy(pSMB->FileName, searchName, name_len);
3066 }
3067 pSMB->BufferFormat = 0x04;
3068 name_len++; /* account for buffer type byte */
3069 pSMB->hdr.smb_buf_length += (__u16) name_len;
3070 pSMB->ByteCount = cpu_to_le16(name_len);
3071
3072 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3074 if (rc) {
3075 cFYI(1, ("Send error in QueryInfo = %d", rc));
3076 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003077 struct timespec ts;
3078 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3079 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003080 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003081 ts.tv_nsec = 0;
3082 ts.tv_sec = time;
3083 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003084 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003085 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3086 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003087 pFinfo->AllocationSize =
3088 cpu_to_le64(le32_to_cpu(pSMBr->size));
3089 pFinfo->EndOfFile = pFinfo->AllocationSize;
3090 pFinfo->Attributes =
3091 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003092 } else
3093 rc = -EIO; /* bad buffer passed in */
3094
3095 cifs_buf_release(pSMB);
3096
3097 if (rc == -EAGAIN)
3098 goto QInfRetry;
3099
3100 return rc;
3101}
3102
3103
3104
3105
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106int
3107CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3108 const unsigned char *searchName,
3109 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003110 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003111 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112{
3113/* level 263 SMB_QUERY_FILE_ALL_INFO */
3114 TRANSACTION2_QPI_REQ *pSMB = NULL;
3115 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3116 int rc = 0;
3117 int bytes_returned;
3118 int name_len;
3119 __u16 params, byte_count;
3120
3121/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3122QPathInfoRetry:
3123 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3124 (void **) &pSMBr);
3125 if (rc)
3126 return rc;
3127
3128 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3129 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003130 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003131 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 name_len++; /* trailing null */
3133 name_len *= 2;
3134 } else { /* BB improve the check for buffer overruns BB */
3135 name_len = strnlen(searchName, PATH_MAX);
3136 name_len++; /* trailing null */
3137 strncpy(pSMB->FileName, searchName, name_len);
3138 }
3139
3140 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3141 pSMB->TotalDataCount = 0;
3142 pSMB->MaxParameterCount = cpu_to_le16(2);
3143 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3144 pSMB->MaxSetupCount = 0;
3145 pSMB->Reserved = 0;
3146 pSMB->Flags = 0;
3147 pSMB->Timeout = 0;
3148 pSMB->Reserved2 = 0;
3149 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3150 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3151 pSMB->DataCount = 0;
3152 pSMB->DataOffset = 0;
3153 pSMB->SetupCount = 1;
3154 pSMB->Reserved3 = 0;
3155 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3156 byte_count = params + 1 /* pad */ ;
3157 pSMB->TotalParameterCount = cpu_to_le16(params);
3158 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003159 if(legacy)
3160 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3161 else
3162 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 pSMB->Reserved4 = 0;
3164 pSMB->hdr.smb_buf_length += byte_count;
3165 pSMB->ByteCount = cpu_to_le16(byte_count);
3166
3167 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3168 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3169 if (rc) {
3170 cFYI(1, ("Send error in QPathInfo = %d", rc));
3171 } else { /* decode response */
3172 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3173
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003174 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3175 rc = -EIO;
3176 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 rc = -EIO; /* bad smb */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003178 else if(legacy && (pSMBr->ByteCount < 24))
3179 rc = -EIO; /* 24 or 26 expected but we do not read last field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 else if (pFindData){
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003181 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003183 if(legacy) /* we do not read the last field, EAsize, fortunately
3184 since it varies by subdialect and on Set vs. Get, is
3185 two bytes or 4 bytes depending but we don't care here */
3186 size = sizeof(FILE_INFO_STANDARD);
3187 else
3188 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 memcpy((char *) pFindData,
3190 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003191 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 } else
3193 rc = -ENOMEM;
3194 }
3195 cifs_buf_release(pSMB);
3196 if (rc == -EAGAIN)
3197 goto QPathInfoRetry;
3198
3199 return rc;
3200}
3201
3202int
3203CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3204 const unsigned char *searchName,
3205 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003206 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207{
3208/* SMB_QUERY_FILE_UNIX_BASIC */
3209 TRANSACTION2_QPI_REQ *pSMB = NULL;
3210 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3211 int rc = 0;
3212 int bytes_returned = 0;
3213 int name_len;
3214 __u16 params, byte_count;
3215
3216 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3217UnixQPathInfoRetry:
3218 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3219 (void **) &pSMBr);
3220 if (rc)
3221 return rc;
3222
3223 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3224 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003225 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003226 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 name_len++; /* trailing null */
3228 name_len *= 2;
3229 } else { /* BB improve the check for buffer overruns BB */
3230 name_len = strnlen(searchName, PATH_MAX);
3231 name_len++; /* trailing null */
3232 strncpy(pSMB->FileName, searchName, name_len);
3233 }
3234
3235 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3236 pSMB->TotalDataCount = 0;
3237 pSMB->MaxParameterCount = cpu_to_le16(2);
3238 /* BB find exact max SMB PDU from sess structure BB */
3239 pSMB->MaxDataCount = cpu_to_le16(4000);
3240 pSMB->MaxSetupCount = 0;
3241 pSMB->Reserved = 0;
3242 pSMB->Flags = 0;
3243 pSMB->Timeout = 0;
3244 pSMB->Reserved2 = 0;
3245 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3246 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3247 pSMB->DataCount = 0;
3248 pSMB->DataOffset = 0;
3249 pSMB->SetupCount = 1;
3250 pSMB->Reserved3 = 0;
3251 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3252 byte_count = params + 1 /* pad */ ;
3253 pSMB->TotalParameterCount = cpu_to_le16(params);
3254 pSMB->ParameterCount = pSMB->TotalParameterCount;
3255 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3256 pSMB->Reserved4 = 0;
3257 pSMB->hdr.smb_buf_length += byte_count;
3258 pSMB->ByteCount = cpu_to_le16(byte_count);
3259
3260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3261 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3262 if (rc) {
3263 cFYI(1, ("Send error in QPathInfo = %d", rc));
3264 } else { /* decode response */
3265 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3266
3267 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3268 rc = -EIO; /* bad smb */
3269 } else {
3270 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3271 memcpy((char *) pFindData,
3272 (char *) &pSMBr->hdr.Protocol +
3273 data_offset,
3274 sizeof (FILE_UNIX_BASIC_INFO));
3275 }
3276 }
3277 cifs_buf_release(pSMB);
3278 if (rc == -EAGAIN)
3279 goto UnixQPathInfoRetry;
3280
3281 return rc;
3282}
3283
3284#if 0 /* function unused at present */
3285int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3286 const char *searchName, FILE_ALL_INFO * findData,
3287 const struct nls_table *nls_codepage)
3288{
3289/* level 257 SMB_ */
3290 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3291 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3292 int rc = 0;
3293 int bytes_returned;
3294 int name_len;
3295 __u16 params, byte_count;
3296
3297 cFYI(1, ("In FindUnique"));
3298findUniqueRetry:
3299 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3300 (void **) &pSMBr);
3301 if (rc)
3302 return rc;
3303
3304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3305 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003306 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 /* find define for this maxpathcomponent */
3308 , nls_codepage);
3309 name_len++; /* trailing null */
3310 name_len *= 2;
3311 } else { /* BB improve the check for buffer overruns BB */
3312 name_len = strnlen(searchName, PATH_MAX);
3313 name_len++; /* trailing null */
3314 strncpy(pSMB->FileName, searchName, name_len);
3315 }
3316
3317 params = 12 + name_len /* includes null */ ;
3318 pSMB->TotalDataCount = 0; /* no EAs */
3319 pSMB->MaxParameterCount = cpu_to_le16(2);
3320 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3321 pSMB->MaxSetupCount = 0;
3322 pSMB->Reserved = 0;
3323 pSMB->Flags = 0;
3324 pSMB->Timeout = 0;
3325 pSMB->Reserved2 = 0;
3326 pSMB->ParameterOffset = cpu_to_le16(
3327 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3328 pSMB->DataCount = 0;
3329 pSMB->DataOffset = 0;
3330 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3331 pSMB->Reserved3 = 0;
3332 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3333 byte_count = params + 1 /* pad */ ;
3334 pSMB->TotalParameterCount = cpu_to_le16(params);
3335 pSMB->ParameterCount = pSMB->TotalParameterCount;
3336 pSMB->SearchAttributes =
3337 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3338 ATTR_DIRECTORY);
3339 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3340 pSMB->SearchFlags = cpu_to_le16(1);
3341 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3342 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3343 pSMB->hdr.smb_buf_length += byte_count;
3344 pSMB->ByteCount = cpu_to_le16(byte_count);
3345
3346 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3347 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3348
3349 if (rc) {
3350 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3351 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003352 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 /* BB fill in */
3354 }
3355
3356 cifs_buf_release(pSMB);
3357 if (rc == -EAGAIN)
3358 goto findUniqueRetry;
3359
3360 return rc;
3361}
3362#endif /* end unused (temporarily) function */
3363
3364/* xid, tcon, searchName and codepage are input parms, rest are returned */
3365int
3366CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3367 const char *searchName,
3368 const struct nls_table *nls_codepage,
3369 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003370 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371{
3372/* level 257 SMB_ */
3373 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3374 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3375 T2_FFIRST_RSP_PARMS * parms;
3376 int rc = 0;
3377 int bytes_returned = 0;
3378 int name_len;
3379 __u16 params, byte_count;
3380
Steve French737b7582005-04-28 22:41:06 -07003381 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382
3383findFirstRetry:
3384 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3385 (void **) &pSMBr);
3386 if (rc)
3387 return rc;
3388
3389 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3390 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003391 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003392 PATH_MAX, nls_codepage, remap);
3393 /* We can not add the asterik earlier in case
3394 it got remapped to 0xF03A as if it were part of the
3395 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003397 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003398 pSMB->FileName[name_len+1] = 0;
3399 pSMB->FileName[name_len+2] = '*';
3400 pSMB->FileName[name_len+3] = 0;
3401 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3403 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003404 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 } else { /* BB add check for overrun of SMB buf BB */
3406 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407/* BB fix here and in unicode clause above ie
3408 if(name_len > buffersize-header)
3409 free buffer exit; BB */
3410 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003411 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003412 pSMB->FileName[name_len+1] = '*';
3413 pSMB->FileName[name_len+2] = 0;
3414 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 }
3416
3417 params = 12 + name_len /* includes null */ ;
3418 pSMB->TotalDataCount = 0; /* no EAs */
3419 pSMB->MaxParameterCount = cpu_to_le16(10);
3420 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3421 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3422 pSMB->MaxSetupCount = 0;
3423 pSMB->Reserved = 0;
3424 pSMB->Flags = 0;
3425 pSMB->Timeout = 0;
3426 pSMB->Reserved2 = 0;
3427 byte_count = params + 1 /* pad */ ;
3428 pSMB->TotalParameterCount = cpu_to_le16(params);
3429 pSMB->ParameterCount = pSMB->TotalParameterCount;
3430 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003431 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3432 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 pSMB->DataCount = 0;
3434 pSMB->DataOffset = 0;
3435 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3436 pSMB->Reserved3 = 0;
3437 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3438 pSMB->SearchAttributes =
3439 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3440 ATTR_DIRECTORY);
3441 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3442 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3443 CIFS_SEARCH_RETURN_RESUME);
3444 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3445
3446 /* BB what should we set StorageType to? Does it matter? BB */
3447 pSMB->SearchStorageType = 0;
3448 pSMB->hdr.smb_buf_length += byte_count;
3449 pSMB->ByteCount = cpu_to_le16(byte_count);
3450
3451 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3452 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003453 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454
Steve French88274812006-03-09 22:21:45 +00003455 if (rc) {/* BB add logic to retry regular search if Unix search
3456 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 /* BB Add code to handle unsupported level rc */
3458 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003459
Steve French88274812006-03-09 22:21:45 +00003460 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461
3462 /* BB eventually could optimize out free and realloc of buf */
3463 /* for this case */
3464 if (rc == -EAGAIN)
3465 goto findFirstRetry;
3466 } else { /* decode response */
3467 /* BB remember to free buffer if error BB */
3468 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3469 if(rc == 0) {
3470 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3471 psrch_inf->unicode = TRUE;
3472 else
3473 psrch_inf->unicode = FALSE;
3474
3475 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003476 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 psrch_inf->srch_entries_start =
3478 (char *) &pSMBr->hdr.Protocol +
3479 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3481 le16_to_cpu(pSMBr->t2.ParameterOffset));
3482
3483 if(parms->EndofSearch)
3484 psrch_inf->endOfSearch = TRUE;
3485 else
3486 psrch_inf->endOfSearch = FALSE;
3487
3488 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003489 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 *pnetfid = parms->SearchHandle;
3492 } else {
3493 cifs_buf_release(pSMB);
3494 }
3495 }
3496
3497 return rc;
3498}
3499
3500int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3501 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3502{
3503 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3504 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3505 T2_FNEXT_RSP_PARMS * parms;
3506 char *response_data;
3507 int rc = 0;
3508 int bytes_returned, name_len;
3509 __u16 params, byte_count;
3510
3511 cFYI(1, ("In FindNext"));
3512
3513 if(psrch_inf->endOfSearch == TRUE)
3514 return -ENOENT;
3515
3516 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3517 (void **) &pSMBr);
3518 if (rc)
3519 return rc;
3520
3521 params = 14; /* includes 2 bytes of null string, converted to LE below */
3522 byte_count = 0;
3523 pSMB->TotalDataCount = 0; /* no EAs */
3524 pSMB->MaxParameterCount = cpu_to_le16(8);
3525 pSMB->MaxDataCount =
3526 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3527 pSMB->MaxSetupCount = 0;
3528 pSMB->Reserved = 0;
3529 pSMB->Flags = 0;
3530 pSMB->Timeout = 0;
3531 pSMB->Reserved2 = 0;
3532 pSMB->ParameterOffset = cpu_to_le16(
3533 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3534 pSMB->DataCount = 0;
3535 pSMB->DataOffset = 0;
3536 pSMB->SetupCount = 1;
3537 pSMB->Reserved3 = 0;
3538 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3539 pSMB->SearchHandle = searchHandle; /* always kept as le */
3540 pSMB->SearchCount =
3541 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3542 /* test for Unix extensions */
3543/* if (tcon->ses->capabilities & CAP_UNIX) {
3544 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3545 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3546 } else {
3547 pSMB->InformationLevel =
3548 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3549 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3550 } */
3551 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3552 pSMB->ResumeKey = psrch_inf->resume_key;
3553 pSMB->SearchFlags =
3554 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3555
3556 name_len = psrch_inf->resume_name_len;
3557 params += name_len;
3558 if(name_len < PATH_MAX) {
3559 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3560 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003561 /* 14 byte parm len above enough for 2 byte null terminator */
3562 pSMB->ResumeFileName[name_len] = 0;
3563 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 } else {
3565 rc = -EINVAL;
3566 goto FNext2_err_exit;
3567 }
3568 byte_count = params + 1 /* pad */ ;
3569 pSMB->TotalParameterCount = cpu_to_le16(params);
3570 pSMB->ParameterCount = pSMB->TotalParameterCount;
3571 pSMB->hdr.smb_buf_length += byte_count;
3572 pSMB->ByteCount = cpu_to_le16(byte_count);
3573
3574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003576 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 if (rc) {
3578 if (rc == -EBADF) {
3579 psrch_inf->endOfSearch = TRUE;
3580 rc = 0; /* search probably was closed at end of search above */
3581 } else
3582 cFYI(1, ("FindNext returned = %d", rc));
3583 } else { /* decode response */
3584 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3585
3586 if(rc == 0) {
3587 /* BB fixme add lock for file (srch_info) struct here */
3588 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3589 psrch_inf->unicode = TRUE;
3590 else
3591 psrch_inf->unicode = FALSE;
3592 response_data = (char *) &pSMBr->hdr.Protocol +
3593 le16_to_cpu(pSMBr->t2.ParameterOffset);
3594 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3595 response_data = (char *)&pSMBr->hdr.Protocol +
3596 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003597 if(psrch_inf->smallBuf)
3598 cifs_small_buf_release(
3599 psrch_inf->ntwrk_buf_start);
3600 else
3601 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 psrch_inf->srch_entries_start = response_data;
3603 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003604 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 if(parms->EndofSearch)
3606 psrch_inf->endOfSearch = TRUE;
3607 else
3608 psrch_inf->endOfSearch = FALSE;
3609
3610 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3611 psrch_inf->index_of_last_entry +=
3612 psrch_inf->entries_in_buffer;
3613/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3614
3615 /* BB fixme add unlock here */
3616 }
3617
3618 }
3619
3620 /* BB On error, should we leave previous search buf (and count and
3621 last entry fields) intact or free the previous one? */
3622
3623 /* Note: On -EAGAIN error only caller can retry on handle based calls
3624 since file handle passed in no longer valid */
3625FNext2_err_exit:
3626 if (rc != 0)
3627 cifs_buf_release(pSMB);
3628
3629 return rc;
3630}
3631
3632int
3633CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3634{
3635 int rc = 0;
3636 FINDCLOSE_REQ *pSMB = NULL;
3637 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3638 int bytes_returned;
3639
3640 cFYI(1, ("In CIFSSMBFindClose"));
3641 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3642
3643 /* no sense returning error if session restarted
3644 as file handle has been closed */
3645 if(rc == -EAGAIN)
3646 return 0;
3647 if (rc)
3648 return rc;
3649
3650 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3651 pSMB->FileID = searchHandle;
3652 pSMB->ByteCount = 0;
3653 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3654 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3655 if (rc) {
3656 cERROR(1, ("Send error in FindClose = %d", rc));
3657 }
Steve Frencha4544342005-08-24 13:59:35 -07003658 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 cifs_small_buf_release(pSMB);
3660
3661 /* Since session is dead, search handle closed on server already */
3662 if (rc == -EAGAIN)
3663 rc = 0;
3664
3665 return rc;
3666}
3667
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668int
3669CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3670 const unsigned char *searchName,
3671 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003672 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673{
3674 int rc = 0;
3675 TRANSACTION2_QPI_REQ *pSMB = NULL;
3676 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3677 int name_len, bytes_returned;
3678 __u16 params, byte_count;
3679
3680 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3681 if(tcon == NULL)
3682 return -ENODEV;
3683
3684GetInodeNumberRetry:
3685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3686 (void **) &pSMBr);
3687 if (rc)
3688 return rc;
3689
3690
3691 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3692 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003693 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003694 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 name_len++; /* trailing null */
3696 name_len *= 2;
3697 } else { /* BB improve the check for buffer overruns BB */
3698 name_len = strnlen(searchName, PATH_MAX);
3699 name_len++; /* trailing null */
3700 strncpy(pSMB->FileName, searchName, name_len);
3701 }
3702
3703 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3704 pSMB->TotalDataCount = 0;
3705 pSMB->MaxParameterCount = cpu_to_le16(2);
3706 /* BB find exact max data count below from sess structure BB */
3707 pSMB->MaxDataCount = cpu_to_le16(4000);
3708 pSMB->MaxSetupCount = 0;
3709 pSMB->Reserved = 0;
3710 pSMB->Flags = 0;
3711 pSMB->Timeout = 0;
3712 pSMB->Reserved2 = 0;
3713 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3714 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3715 pSMB->DataCount = 0;
3716 pSMB->DataOffset = 0;
3717 pSMB->SetupCount = 1;
3718 pSMB->Reserved3 = 0;
3719 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3720 byte_count = params + 1 /* pad */ ;
3721 pSMB->TotalParameterCount = cpu_to_le16(params);
3722 pSMB->ParameterCount = pSMB->TotalParameterCount;
3723 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3724 pSMB->Reserved4 = 0;
3725 pSMB->hdr.smb_buf_length += byte_count;
3726 pSMB->ByteCount = cpu_to_le16(byte_count);
3727
3728 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3729 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3730 if (rc) {
3731 cFYI(1, ("error %d in QueryInternalInfo", rc));
3732 } else {
3733 /* decode response */
3734 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3735 if (rc || (pSMBr->ByteCount < 2))
3736 /* BB also check enough total bytes returned */
3737 /* If rc should we check for EOPNOSUPP and
3738 disable the srvino flag? or in caller? */
3739 rc = -EIO; /* bad smb */
3740 else {
3741 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3742 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3743 struct file_internal_info * pfinfo;
3744 /* BB Do we need a cast or hash here ? */
3745 if(count < 8) {
3746 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3747 rc = -EIO;
3748 goto GetInodeNumOut;
3749 }
3750 pfinfo = (struct file_internal_info *)
3751 (data_offset + (char *) &pSMBr->hdr.Protocol);
3752 *inode_number = pfinfo->UniqueId;
3753 }
3754 }
3755GetInodeNumOut:
3756 cifs_buf_release(pSMB);
3757 if (rc == -EAGAIN)
3758 goto GetInodeNumberRetry;
3759 return rc;
3760}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
3762int
3763CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3764 const unsigned char *searchName,
3765 unsigned char **targetUNCs,
3766 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003767 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768{
3769/* TRANS2_GET_DFS_REFERRAL */
3770 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3771 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3772 struct dfs_referral_level_3 * referrals = NULL;
3773 int rc = 0;
3774 int bytes_returned;
3775 int name_len;
3776 unsigned int i;
3777 char * temp;
3778 __u16 params, byte_count;
3779 *number_of_UNC_in_array = 0;
3780 *targetUNCs = NULL;
3781
3782 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3783 if (ses == NULL)
3784 return -ENODEV;
3785getDFSRetry:
3786 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3787 (void **) &pSMBr);
3788 if (rc)
3789 return rc;
Steve French1982c342005-08-17 12:38:22 -07003790
3791 /* server pointer checked in called function,
3792 but should never be null here anyway */
3793 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 pSMB->hdr.Tid = ses->ipc_tid;
3795 pSMB->hdr.Uid = ses->Suid;
3796 if (ses->capabilities & CAP_STATUS32) {
3797 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3798 }
3799 if (ses->capabilities & CAP_DFS) {
3800 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3801 }
3802
3803 if (ses->capabilities & CAP_UNICODE) {
3804 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3805 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003806 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003807 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 name_len++; /* trailing null */
3809 name_len *= 2;
3810 } else { /* BB improve the check for buffer overruns BB */
3811 name_len = strnlen(searchName, PATH_MAX);
3812 name_len++; /* trailing null */
3813 strncpy(pSMB->RequestFileName, searchName, name_len);
3814 }
3815
Steve French1a4e15a2006-10-12 21:33:51 +00003816 if(ses->server) {
3817 if(ses->server->secMode &
3818 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3819 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3820 }
3821
3822 pSMB->hdr.Uid = ses->Suid;
3823
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 params = 2 /* level */ + name_len /*includes null */ ;
3825 pSMB->TotalDataCount = 0;
3826 pSMB->DataCount = 0;
3827 pSMB->DataOffset = 0;
3828 pSMB->MaxParameterCount = 0;
3829 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3830 pSMB->MaxSetupCount = 0;
3831 pSMB->Reserved = 0;
3832 pSMB->Flags = 0;
3833 pSMB->Timeout = 0;
3834 pSMB->Reserved2 = 0;
3835 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3836 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3837 pSMB->SetupCount = 1;
3838 pSMB->Reserved3 = 0;
3839 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3840 byte_count = params + 3 /* pad */ ;
3841 pSMB->ParameterCount = cpu_to_le16(params);
3842 pSMB->TotalParameterCount = pSMB->ParameterCount;
3843 pSMB->MaxReferralLevel = cpu_to_le16(3);
3844 pSMB->hdr.smb_buf_length += byte_count;
3845 pSMB->ByteCount = cpu_to_le16(byte_count);
3846
3847 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3849 if (rc) {
3850 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3851 } else { /* decode response */
3852/* BB Add logic to parse referrals here */
3853 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3854
3855 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3856 rc = -EIO; /* bad smb */
3857 else {
3858 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3859 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3860
3861 cFYI(1,
3862 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3863 pSMBr->ByteCount, data_offset));
3864 referrals =
3865 (struct dfs_referral_level_3 *)
3866 (8 /* sizeof start of data block */ +
3867 data_offset +
3868 (char *) &pSMBr->hdr.Protocol);
3869 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",
3870 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)));
3871 /* BB This field is actually two bytes in from start of
3872 data block so we could do safety check that DataBlock
3873 begins at address of pSMBr->NumberOfReferrals */
3874 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3875
3876 /* BB Fix below so can return more than one referral */
3877 if(*number_of_UNC_in_array > 1)
3878 *number_of_UNC_in_array = 1;
3879
3880 /* get the length of the strings describing refs */
3881 name_len = 0;
3882 for(i=0;i<*number_of_UNC_in_array;i++) {
3883 /* make sure that DfsPathOffset not past end */
3884 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3885 if (offset > data_count) {
3886 /* if invalid referral, stop here and do
3887 not try to copy any more */
3888 *number_of_UNC_in_array = i;
3889 break;
3890 }
3891 temp = ((char *)referrals) + offset;
3892
3893 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3894 name_len += UniStrnlen((wchar_t *)temp,data_count);
3895 } else {
3896 name_len += strnlen(temp,data_count);
3897 }
3898 referrals++;
3899 /* BB add check that referral pointer does not fall off end PDU */
3900
3901 }
3902 /* BB add check for name_len bigger than bcc */
3903 *targetUNCs =
3904 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3905 if(*targetUNCs == NULL) {
3906 rc = -ENOMEM;
3907 goto GetDFSRefExit;
3908 }
3909 /* copy the ref strings */
3910 referrals =
3911 (struct dfs_referral_level_3 *)
3912 (8 /* sizeof data hdr */ +
3913 data_offset +
3914 (char *) &pSMBr->hdr.Protocol);
3915
3916 for(i=0;i<*number_of_UNC_in_array;i++) {
3917 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3918 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3919 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003920 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 } else {
3922 strncpy(*targetUNCs,temp,name_len);
3923 }
3924 /* BB update target_uncs pointers */
3925 referrals++;
3926 }
3927 temp = *targetUNCs;
3928 temp[name_len] = 0;
3929 }
3930
3931 }
3932GetDFSRefExit:
3933 if (pSMB)
3934 cifs_buf_release(pSMB);
3935
3936 if (rc == -EAGAIN)
3937 goto getDFSRetry;
3938
3939 return rc;
3940}
3941
Steve French20962432005-09-21 22:05:57 -07003942/* Query File System Info such as free space to old servers such as Win 9x */
3943int
3944SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3945{
3946/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3947 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3948 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3949 FILE_SYSTEM_ALLOC_INFO *response_data;
3950 int rc = 0;
3951 int bytes_returned = 0;
3952 __u16 params, byte_count;
3953
3954 cFYI(1, ("OldQFSInfo"));
3955oldQFSInfoRetry:
3956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3957 (void **) &pSMBr);
3958 if (rc)
3959 return rc;
3960 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3961 (void **) &pSMBr);
3962 if (rc)
3963 return rc;
3964
3965 params = 2; /* level */
3966 pSMB->TotalDataCount = 0;
3967 pSMB->MaxParameterCount = cpu_to_le16(2);
3968 pSMB->MaxDataCount = cpu_to_le16(1000);
3969 pSMB->MaxSetupCount = 0;
3970 pSMB->Reserved = 0;
3971 pSMB->Flags = 0;
3972 pSMB->Timeout = 0;
3973 pSMB->Reserved2 = 0;
3974 byte_count = params + 1 /* pad */ ;
3975 pSMB->TotalParameterCount = cpu_to_le16(params);
3976 pSMB->ParameterCount = pSMB->TotalParameterCount;
3977 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3978 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3979 pSMB->DataCount = 0;
3980 pSMB->DataOffset = 0;
3981 pSMB->SetupCount = 1;
3982 pSMB->Reserved3 = 0;
3983 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3984 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3985 pSMB->hdr.smb_buf_length += byte_count;
3986 pSMB->ByteCount = cpu_to_le16(byte_count);
3987
3988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3990 if (rc) {
3991 cFYI(1, ("Send error in QFSInfo = %d", rc));
3992 } else { /* decode response */
3993 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3994
3995 if (rc || (pSMBr->ByteCount < 18))
3996 rc = -EIO; /* bad smb */
3997 else {
3998 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3999 cFYI(1,("qfsinf resp BCC: %d Offset %d",
4000 pSMBr->ByteCount, data_offset));
4001
4002 response_data =
4003 (FILE_SYSTEM_ALLOC_INFO *)
4004 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4005 FSData->f_bsize =
4006 le16_to_cpu(response_data->BytesPerSector) *
4007 le32_to_cpu(response_data->
4008 SectorsPerAllocationUnit);
4009 FSData->f_blocks =
4010 le32_to_cpu(response_data->TotalAllocationUnits);
4011 FSData->f_bfree = FSData->f_bavail =
4012 le32_to_cpu(response_data->FreeAllocationUnits);
4013 cFYI(1,
4014 ("Blocks: %lld Free: %lld Block size %ld",
4015 (unsigned long long)FSData->f_blocks,
4016 (unsigned long long)FSData->f_bfree,
4017 FSData->f_bsize));
4018 }
4019 }
4020 cifs_buf_release(pSMB);
4021
4022 if (rc == -EAGAIN)
4023 goto oldQFSInfoRetry;
4024
4025 return rc;
4026}
4027
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028int
Steve French737b7582005-04-28 22:41:06 -07004029CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030{
4031/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4032 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4033 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4034 FILE_SYSTEM_INFO *response_data;
4035 int rc = 0;
4036 int bytes_returned = 0;
4037 __u16 params, byte_count;
4038
4039 cFYI(1, ("In QFSInfo"));
4040QFSInfoRetry:
4041 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4042 (void **) &pSMBr);
4043 if (rc)
4044 return rc;
4045
4046 params = 2; /* level */
4047 pSMB->TotalDataCount = 0;
4048 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004049 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 pSMB->MaxSetupCount = 0;
4051 pSMB->Reserved = 0;
4052 pSMB->Flags = 0;
4053 pSMB->Timeout = 0;
4054 pSMB->Reserved2 = 0;
4055 byte_count = params + 1 /* pad */ ;
4056 pSMB->TotalParameterCount = cpu_to_le16(params);
4057 pSMB->ParameterCount = pSMB->TotalParameterCount;
4058 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4059 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4060 pSMB->DataCount = 0;
4061 pSMB->DataOffset = 0;
4062 pSMB->SetupCount = 1;
4063 pSMB->Reserved3 = 0;
4064 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4065 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4066 pSMB->hdr.smb_buf_length += byte_count;
4067 pSMB->ByteCount = cpu_to_le16(byte_count);
4068
4069 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4070 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4071 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004072 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 } else { /* decode response */
4074 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4075
Steve French20962432005-09-21 22:05:57 -07004076 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 rc = -EIO; /* bad smb */
4078 else {
4079 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080
4081 response_data =
4082 (FILE_SYSTEM_INFO
4083 *) (((char *) &pSMBr->hdr.Protocol) +
4084 data_offset);
4085 FSData->f_bsize =
4086 le32_to_cpu(response_data->BytesPerSector) *
4087 le32_to_cpu(response_data->
4088 SectorsPerAllocationUnit);
4089 FSData->f_blocks =
4090 le64_to_cpu(response_data->TotalAllocationUnits);
4091 FSData->f_bfree = FSData->f_bavail =
4092 le64_to_cpu(response_data->FreeAllocationUnits);
4093 cFYI(1,
4094 ("Blocks: %lld Free: %lld Block size %ld",
4095 (unsigned long long)FSData->f_blocks,
4096 (unsigned long long)FSData->f_bfree,
4097 FSData->f_bsize));
4098 }
4099 }
4100 cifs_buf_release(pSMB);
4101
4102 if (rc == -EAGAIN)
4103 goto QFSInfoRetry;
4104
4105 return rc;
4106}
4107
4108int
Steve French737b7582005-04-28 22:41:06 -07004109CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110{
4111/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4112 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4113 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4114 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4115 int rc = 0;
4116 int bytes_returned = 0;
4117 __u16 params, byte_count;
4118
4119 cFYI(1, ("In QFSAttributeInfo"));
4120QFSAttributeRetry:
4121 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4122 (void **) &pSMBr);
4123 if (rc)
4124 return rc;
4125
4126 params = 2; /* level */
4127 pSMB->TotalDataCount = 0;
4128 pSMB->MaxParameterCount = cpu_to_le16(2);
4129 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4130 pSMB->MaxSetupCount = 0;
4131 pSMB->Reserved = 0;
4132 pSMB->Flags = 0;
4133 pSMB->Timeout = 0;
4134 pSMB->Reserved2 = 0;
4135 byte_count = params + 1 /* pad */ ;
4136 pSMB->TotalParameterCount = cpu_to_le16(params);
4137 pSMB->ParameterCount = pSMB->TotalParameterCount;
4138 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4139 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4140 pSMB->DataCount = 0;
4141 pSMB->DataOffset = 0;
4142 pSMB->SetupCount = 1;
4143 pSMB->Reserved3 = 0;
4144 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4145 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4146 pSMB->hdr.smb_buf_length += byte_count;
4147 pSMB->ByteCount = cpu_to_le16(byte_count);
4148
4149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4151 if (rc) {
4152 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4153 } else { /* decode response */
4154 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4155
4156 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4157 rc = -EIO; /* bad smb */
4158 } else {
4159 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4160 response_data =
4161 (FILE_SYSTEM_ATTRIBUTE_INFO
4162 *) (((char *) &pSMBr->hdr.Protocol) +
4163 data_offset);
4164 memcpy(&tcon->fsAttrInfo, response_data,
4165 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4166 }
4167 }
4168 cifs_buf_release(pSMB);
4169
4170 if (rc == -EAGAIN)
4171 goto QFSAttributeRetry;
4172
4173 return rc;
4174}
4175
4176int
Steve French737b7582005-04-28 22:41:06 -07004177CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178{
4179/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4180 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4181 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4182 FILE_SYSTEM_DEVICE_INFO *response_data;
4183 int rc = 0;
4184 int bytes_returned = 0;
4185 __u16 params, byte_count;
4186
4187 cFYI(1, ("In QFSDeviceInfo"));
4188QFSDeviceRetry:
4189 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4190 (void **) &pSMBr);
4191 if (rc)
4192 return rc;
4193
4194 params = 2; /* level */
4195 pSMB->TotalDataCount = 0;
4196 pSMB->MaxParameterCount = cpu_to_le16(2);
4197 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4198 pSMB->MaxSetupCount = 0;
4199 pSMB->Reserved = 0;
4200 pSMB->Flags = 0;
4201 pSMB->Timeout = 0;
4202 pSMB->Reserved2 = 0;
4203 byte_count = params + 1 /* pad */ ;
4204 pSMB->TotalParameterCount = cpu_to_le16(params);
4205 pSMB->ParameterCount = pSMB->TotalParameterCount;
4206 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4207 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4208
4209 pSMB->DataCount = 0;
4210 pSMB->DataOffset = 0;
4211 pSMB->SetupCount = 1;
4212 pSMB->Reserved3 = 0;
4213 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4214 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4215 pSMB->hdr.smb_buf_length += byte_count;
4216 pSMB->ByteCount = cpu_to_le16(byte_count);
4217
4218 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4219 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4220 if (rc) {
4221 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4222 } else { /* decode response */
4223 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4224
4225 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4226 rc = -EIO; /* bad smb */
4227 else {
4228 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4229 response_data =
Steve French737b7582005-04-28 22:41:06 -07004230 (FILE_SYSTEM_DEVICE_INFO *)
4231 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 data_offset);
4233 memcpy(&tcon->fsDevInfo, response_data,
4234 sizeof (FILE_SYSTEM_DEVICE_INFO));
4235 }
4236 }
4237 cifs_buf_release(pSMB);
4238
4239 if (rc == -EAGAIN)
4240 goto QFSDeviceRetry;
4241
4242 return rc;
4243}
4244
4245int
Steve French737b7582005-04-28 22:41:06 -07004246CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247{
4248/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4249 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4250 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4251 FILE_SYSTEM_UNIX_INFO *response_data;
4252 int rc = 0;
4253 int bytes_returned = 0;
4254 __u16 params, byte_count;
4255
4256 cFYI(1, ("In QFSUnixInfo"));
4257QFSUnixRetry:
4258 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4259 (void **) &pSMBr);
4260 if (rc)
4261 return rc;
4262
4263 params = 2; /* level */
4264 pSMB->TotalDataCount = 0;
4265 pSMB->DataCount = 0;
4266 pSMB->DataOffset = 0;
4267 pSMB->MaxParameterCount = cpu_to_le16(2);
4268 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4269 pSMB->MaxSetupCount = 0;
4270 pSMB->Reserved = 0;
4271 pSMB->Flags = 0;
4272 pSMB->Timeout = 0;
4273 pSMB->Reserved2 = 0;
4274 byte_count = params + 1 /* pad */ ;
4275 pSMB->ParameterCount = cpu_to_le16(params);
4276 pSMB->TotalParameterCount = pSMB->ParameterCount;
4277 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4278 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4279 pSMB->SetupCount = 1;
4280 pSMB->Reserved3 = 0;
4281 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4282 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4283 pSMB->hdr.smb_buf_length += byte_count;
4284 pSMB->ByteCount = cpu_to_le16(byte_count);
4285
4286 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4287 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4288 if (rc) {
4289 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4290 } else { /* decode response */
4291 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4292
4293 if (rc || (pSMBr->ByteCount < 13)) {
4294 rc = -EIO; /* bad smb */
4295 } else {
4296 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4297 response_data =
4298 (FILE_SYSTEM_UNIX_INFO
4299 *) (((char *) &pSMBr->hdr.Protocol) +
4300 data_offset);
4301 memcpy(&tcon->fsUnixInfo, response_data,
4302 sizeof (FILE_SYSTEM_UNIX_INFO));
4303 }
4304 }
4305 cifs_buf_release(pSMB);
4306
4307 if (rc == -EAGAIN)
4308 goto QFSUnixRetry;
4309
4310
4311 return rc;
4312}
4313
Jeremy Allisonac670552005-06-22 17:26:35 -07004314int
Steve French45abc6e2005-06-23 13:42:03 -05004315CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004316{
4317/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4318 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4319 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4320 int rc = 0;
4321 int bytes_returned = 0;
4322 __u16 params, param_offset, offset, byte_count;
4323
4324 cFYI(1, ("In SETFSUnixInfo"));
4325SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004326 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004327 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4328 (void **) &pSMBr);
4329 if (rc)
4330 return rc;
4331
4332 params = 4; /* 2 bytes zero followed by info level. */
4333 pSMB->MaxSetupCount = 0;
4334 pSMB->Reserved = 0;
4335 pSMB->Flags = 0;
4336 pSMB->Timeout = 0;
4337 pSMB->Reserved2 = 0;
4338 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4339 offset = param_offset + params;
4340
4341 pSMB->MaxParameterCount = cpu_to_le16(4);
4342 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4343 pSMB->SetupCount = 1;
4344 pSMB->Reserved3 = 0;
4345 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4346 byte_count = 1 /* pad */ + params + 12;
4347
4348 pSMB->DataCount = cpu_to_le16(12);
4349 pSMB->ParameterCount = cpu_to_le16(params);
4350 pSMB->TotalDataCount = pSMB->DataCount;
4351 pSMB->TotalParameterCount = pSMB->ParameterCount;
4352 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4353 pSMB->DataOffset = cpu_to_le16(offset);
4354
4355 /* Params. */
4356 pSMB->FileNum = 0;
4357 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4358
4359 /* Data. */
4360 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4361 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4362 pSMB->ClientUnixCap = cpu_to_le64(cap);
4363
4364 pSMB->hdr.smb_buf_length += byte_count;
4365 pSMB->ByteCount = cpu_to_le16(byte_count);
4366
4367 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4368 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4369 if (rc) {
4370 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4371 } else { /* decode response */
4372 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4373 if (rc) {
4374 rc = -EIO; /* bad smb */
4375 }
4376 }
4377 cifs_buf_release(pSMB);
4378
4379 if (rc == -EAGAIN)
4380 goto SETFSUnixRetry;
4381
4382 return rc;
4383}
4384
4385
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386
4387int
4388CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004389 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390{
4391/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4392 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4393 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4394 FILE_SYSTEM_POSIX_INFO *response_data;
4395 int rc = 0;
4396 int bytes_returned = 0;
4397 __u16 params, byte_count;
4398
4399 cFYI(1, ("In QFSPosixInfo"));
4400QFSPosixRetry:
4401 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4402 (void **) &pSMBr);
4403 if (rc)
4404 return rc;
4405
4406 params = 2; /* level */
4407 pSMB->TotalDataCount = 0;
4408 pSMB->DataCount = 0;
4409 pSMB->DataOffset = 0;
4410 pSMB->MaxParameterCount = cpu_to_le16(2);
4411 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4412 pSMB->MaxSetupCount = 0;
4413 pSMB->Reserved = 0;
4414 pSMB->Flags = 0;
4415 pSMB->Timeout = 0;
4416 pSMB->Reserved2 = 0;
4417 byte_count = params + 1 /* pad */ ;
4418 pSMB->ParameterCount = cpu_to_le16(params);
4419 pSMB->TotalParameterCount = pSMB->ParameterCount;
4420 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4421 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4422 pSMB->SetupCount = 1;
4423 pSMB->Reserved3 = 0;
4424 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4425 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4426 pSMB->hdr.smb_buf_length += byte_count;
4427 pSMB->ByteCount = cpu_to_le16(byte_count);
4428
4429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4431 if (rc) {
4432 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4433 } else { /* decode response */
4434 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4435
4436 if (rc || (pSMBr->ByteCount < 13)) {
4437 rc = -EIO; /* bad smb */
4438 } else {
4439 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4440 response_data =
4441 (FILE_SYSTEM_POSIX_INFO
4442 *) (((char *) &pSMBr->hdr.Protocol) +
4443 data_offset);
4444 FSData->f_bsize =
4445 le32_to_cpu(response_data->BlockSize);
4446 FSData->f_blocks =
4447 le64_to_cpu(response_data->TotalBlocks);
4448 FSData->f_bfree =
4449 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004450 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 FSData->f_bavail = FSData->f_bfree;
4452 } else {
4453 FSData->f_bavail =
4454 le64_to_cpu(response_data->UserBlocksAvail);
4455 }
Steve French70ca7342005-09-22 16:32:06 -07004456 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 FSData->f_files =
4458 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004459 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 FSData->f_ffree =
4461 le64_to_cpu(response_data->FreeFileNodes);
4462 }
4463 }
4464 cifs_buf_release(pSMB);
4465
4466 if (rc == -EAGAIN)
4467 goto QFSPosixRetry;
4468
4469 return rc;
4470}
4471
4472
4473/* We can not use write of zero bytes trick to
4474 set file size due to need for large file support. Also note that
4475 this SetPathInfo is preferred to SetFileInfo based method in next
4476 routine which is only needed to work around a sharing violation bug
4477 in Samba which this routine can run into */
4478
4479int
4480CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004481 __u64 size, int SetAllocation,
4482 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483{
4484 struct smb_com_transaction2_spi_req *pSMB = NULL;
4485 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4486 struct file_end_of_file_info *parm_data;
4487 int name_len;
4488 int rc = 0;
4489 int bytes_returned = 0;
4490 __u16 params, byte_count, data_count, param_offset, offset;
4491
4492 cFYI(1, ("In SetEOF"));
4493SetEOFRetry:
4494 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4495 (void **) &pSMBr);
4496 if (rc)
4497 return rc;
4498
4499 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4500 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004501 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004502 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 name_len++; /* trailing null */
4504 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004505 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 name_len = strnlen(fileName, PATH_MAX);
4507 name_len++; /* trailing null */
4508 strncpy(pSMB->FileName, fileName, name_len);
4509 }
4510 params = 6 + name_len;
4511 data_count = sizeof (struct file_end_of_file_info);
4512 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004513 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 pSMB->MaxSetupCount = 0;
4515 pSMB->Reserved = 0;
4516 pSMB->Flags = 0;
4517 pSMB->Timeout = 0;
4518 pSMB->Reserved2 = 0;
4519 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4520 InformationLevel) - 4;
4521 offset = param_offset + params;
4522 if(SetAllocation) {
4523 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4524 pSMB->InformationLevel =
4525 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4526 else
4527 pSMB->InformationLevel =
4528 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4529 } else /* Set File Size */ {
4530 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4531 pSMB->InformationLevel =
4532 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4533 else
4534 pSMB->InformationLevel =
4535 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4536 }
4537
4538 parm_data =
4539 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4540 offset);
4541 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4542 pSMB->DataOffset = cpu_to_le16(offset);
4543 pSMB->SetupCount = 1;
4544 pSMB->Reserved3 = 0;
4545 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4546 byte_count = 3 /* pad */ + params + data_count;
4547 pSMB->DataCount = cpu_to_le16(data_count);
4548 pSMB->TotalDataCount = pSMB->DataCount;
4549 pSMB->ParameterCount = cpu_to_le16(params);
4550 pSMB->TotalParameterCount = pSMB->ParameterCount;
4551 pSMB->Reserved4 = 0;
4552 pSMB->hdr.smb_buf_length += byte_count;
4553 parm_data->FileSize = cpu_to_le64(size);
4554 pSMB->ByteCount = cpu_to_le16(byte_count);
4555 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4556 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4557 if (rc) {
4558 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4559 }
4560
4561 cifs_buf_release(pSMB);
4562
4563 if (rc == -EAGAIN)
4564 goto SetEOFRetry;
4565
4566 return rc;
4567}
4568
4569int
4570CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4571 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4572{
4573 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4574 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4575 char *data_offset;
4576 struct file_end_of_file_info *parm_data;
4577 int rc = 0;
4578 int bytes_returned = 0;
4579 __u16 params, param_offset, offset, byte_count, count;
4580
4581 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4582 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004583 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4584
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 if (rc)
4586 return rc;
4587
Steve Frenchcd634992005-04-28 22:41:10 -07004588 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4589
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4591 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4592
4593 params = 6;
4594 pSMB->MaxSetupCount = 0;
4595 pSMB->Reserved = 0;
4596 pSMB->Flags = 0;
4597 pSMB->Timeout = 0;
4598 pSMB->Reserved2 = 0;
4599 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4600 offset = param_offset + params;
4601
4602 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4603
4604 count = sizeof(struct file_end_of_file_info);
4605 pSMB->MaxParameterCount = cpu_to_le16(2);
4606 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4607 pSMB->SetupCount = 1;
4608 pSMB->Reserved3 = 0;
4609 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4610 byte_count = 3 /* pad */ + params + count;
4611 pSMB->DataCount = cpu_to_le16(count);
4612 pSMB->ParameterCount = cpu_to_le16(params);
4613 pSMB->TotalDataCount = pSMB->DataCount;
4614 pSMB->TotalParameterCount = pSMB->ParameterCount;
4615 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4616 parm_data =
4617 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4618 offset);
4619 pSMB->DataOffset = cpu_to_le16(offset);
4620 parm_data->FileSize = cpu_to_le64(size);
4621 pSMB->Fid = fid;
4622 if(SetAllocation) {
4623 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4624 pSMB->InformationLevel =
4625 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4626 else
4627 pSMB->InformationLevel =
4628 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4629 } else /* Set File Size */ {
4630 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4631 pSMB->InformationLevel =
4632 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4633 else
4634 pSMB->InformationLevel =
4635 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4636 }
4637 pSMB->Reserved4 = 0;
4638 pSMB->hdr.smb_buf_length += byte_count;
4639 pSMB->ByteCount = cpu_to_le16(byte_count);
4640 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4641 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4642 if (rc) {
4643 cFYI(1,
4644 ("Send error in SetFileInfo (SetFileSize) = %d",
4645 rc));
4646 }
4647
4648 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004649 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650
4651 /* Note: On -EAGAIN error only caller can retry on handle based calls
4652 since file handle passed in no longer valid */
4653
4654 return rc;
4655}
4656
4657/* Some legacy servers such as NT4 require that the file times be set on
4658 an open handle, rather than by pathname - this is awkward due to
4659 potential access conflicts on the open, but it is unavoidable for these
4660 old servers since the only other choice is to go from 100 nanosecond DCE
4661 time and resort to the original setpathinfo level which takes the ancient
4662 DOS time format with 2 second granularity */
4663int
4664CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4665 __u16 fid)
4666{
4667 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4668 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4669 char *data_offset;
4670 int rc = 0;
4671 int bytes_returned = 0;
4672 __u16 params, param_offset, offset, byte_count, count;
4673
4674 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004675 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4676
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 if (rc)
4678 return rc;
4679
Steve Frenchcd634992005-04-28 22:41:10 -07004680 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4681
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 /* At this point there is no need to override the current pid
4683 with the pid of the opener, but that could change if we someday
4684 use an existing handle (rather than opening one on the fly) */
4685 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4686 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4687
4688 params = 6;
4689 pSMB->MaxSetupCount = 0;
4690 pSMB->Reserved = 0;
4691 pSMB->Flags = 0;
4692 pSMB->Timeout = 0;
4693 pSMB->Reserved2 = 0;
4694 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4695 offset = param_offset + params;
4696
4697 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4698
4699 count = sizeof (FILE_BASIC_INFO);
4700 pSMB->MaxParameterCount = cpu_to_le16(2);
4701 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4702 pSMB->SetupCount = 1;
4703 pSMB->Reserved3 = 0;
4704 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4705 byte_count = 3 /* pad */ + params + count;
4706 pSMB->DataCount = cpu_to_le16(count);
4707 pSMB->ParameterCount = cpu_to_le16(params);
4708 pSMB->TotalDataCount = pSMB->DataCount;
4709 pSMB->TotalParameterCount = pSMB->ParameterCount;
4710 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4711 pSMB->DataOffset = cpu_to_le16(offset);
4712 pSMB->Fid = fid;
4713 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4714 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4715 else
4716 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4717 pSMB->Reserved4 = 0;
4718 pSMB->hdr.smb_buf_length += byte_count;
4719 pSMB->ByteCount = cpu_to_le16(byte_count);
4720 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4721 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4722 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4723 if (rc) {
4724 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4725 }
4726
Steve Frenchcd634992005-04-28 22:41:10 -07004727 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728
4729 /* Note: On -EAGAIN error only caller can retry on handle based calls
4730 since file handle passed in no longer valid */
4731
4732 return rc;
4733}
4734
4735
4736int
4737CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4738 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004739 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740{
4741 TRANSACTION2_SPI_REQ *pSMB = NULL;
4742 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4743 int name_len;
4744 int rc = 0;
4745 int bytes_returned = 0;
4746 char *data_offset;
4747 __u16 params, param_offset, offset, byte_count, count;
4748
4749 cFYI(1, ("In SetTimes"));
4750
4751SetTimesRetry:
4752 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4753 (void **) &pSMBr);
4754 if (rc)
4755 return rc;
4756
4757 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4758 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004759 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004760 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 name_len++; /* trailing null */
4762 name_len *= 2;
4763 } else { /* BB improve the check for buffer overruns BB */
4764 name_len = strnlen(fileName, PATH_MAX);
4765 name_len++; /* trailing null */
4766 strncpy(pSMB->FileName, fileName, name_len);
4767 }
4768
4769 params = 6 + name_len;
4770 count = sizeof (FILE_BASIC_INFO);
4771 pSMB->MaxParameterCount = cpu_to_le16(2);
4772 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4773 pSMB->MaxSetupCount = 0;
4774 pSMB->Reserved = 0;
4775 pSMB->Flags = 0;
4776 pSMB->Timeout = 0;
4777 pSMB->Reserved2 = 0;
4778 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4779 InformationLevel) - 4;
4780 offset = param_offset + params;
4781 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4782 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4783 pSMB->DataOffset = cpu_to_le16(offset);
4784 pSMB->SetupCount = 1;
4785 pSMB->Reserved3 = 0;
4786 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4787 byte_count = 3 /* pad */ + params + count;
4788
4789 pSMB->DataCount = cpu_to_le16(count);
4790 pSMB->ParameterCount = cpu_to_le16(params);
4791 pSMB->TotalDataCount = pSMB->DataCount;
4792 pSMB->TotalParameterCount = pSMB->ParameterCount;
4793 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4794 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4795 else
4796 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4797 pSMB->Reserved4 = 0;
4798 pSMB->hdr.smb_buf_length += byte_count;
4799 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4800 pSMB->ByteCount = cpu_to_le16(byte_count);
4801 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4802 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4803 if (rc) {
4804 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4805 }
4806
4807 cifs_buf_release(pSMB);
4808
4809 if (rc == -EAGAIN)
4810 goto SetTimesRetry;
4811
4812 return rc;
4813}
4814
4815/* Can not be used to set time stamps yet (due to old DOS time format) */
4816/* Can be used to set attributes */
4817#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4818 handling it anyway and NT4 was what we thought it would be needed for
4819 Do not delete it until we prove whether needed for Win9x though */
4820int
4821CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4822 __u16 dos_attrs, const struct nls_table *nls_codepage)
4823{
4824 SETATTR_REQ *pSMB = NULL;
4825 SETATTR_RSP *pSMBr = NULL;
4826 int rc = 0;
4827 int bytes_returned;
4828 int name_len;
4829
4830 cFYI(1, ("In SetAttrLegacy"));
4831
4832SetAttrLgcyRetry:
4833 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4834 (void **) &pSMBr);
4835 if (rc)
4836 return rc;
4837
4838 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4839 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004840 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 PATH_MAX, nls_codepage);
4842 name_len++; /* trailing null */
4843 name_len *= 2;
4844 } else { /* BB improve the check for buffer overruns BB */
4845 name_len = strnlen(fileName, PATH_MAX);
4846 name_len++; /* trailing null */
4847 strncpy(pSMB->fileName, fileName, name_len);
4848 }
4849 pSMB->attr = cpu_to_le16(dos_attrs);
4850 pSMB->BufferFormat = 0x04;
4851 pSMB->hdr.smb_buf_length += name_len + 1;
4852 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4853 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4854 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4855 if (rc) {
4856 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4857 }
4858
4859 cifs_buf_release(pSMB);
4860
4861 if (rc == -EAGAIN)
4862 goto SetAttrLgcyRetry;
4863
4864 return rc;
4865}
4866#endif /* temporarily unneeded SetAttr legacy function */
4867
4868int
4869CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004870 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4871 dev_t device, const struct nls_table *nls_codepage,
4872 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873{
4874 TRANSACTION2_SPI_REQ *pSMB = NULL;
4875 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4876 int name_len;
4877 int rc = 0;
4878 int bytes_returned = 0;
4879 FILE_UNIX_BASIC_INFO *data_offset;
4880 __u16 params, param_offset, offset, count, byte_count;
4881
4882 cFYI(1, ("In SetUID/GID/Mode"));
4883setPermsRetry:
4884 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4885 (void **) &pSMBr);
4886 if (rc)
4887 return rc;
4888
4889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4890 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004891 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004892 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 name_len++; /* trailing null */
4894 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004895 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 name_len = strnlen(fileName, PATH_MAX);
4897 name_len++; /* trailing null */
4898 strncpy(pSMB->FileName, fileName, name_len);
4899 }
4900
4901 params = 6 + name_len;
4902 count = sizeof (FILE_UNIX_BASIC_INFO);
4903 pSMB->MaxParameterCount = cpu_to_le16(2);
4904 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4905 pSMB->MaxSetupCount = 0;
4906 pSMB->Reserved = 0;
4907 pSMB->Flags = 0;
4908 pSMB->Timeout = 0;
4909 pSMB->Reserved2 = 0;
4910 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4911 InformationLevel) - 4;
4912 offset = param_offset + params;
4913 data_offset =
4914 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4915 offset);
4916 memset(data_offset, 0, count);
4917 pSMB->DataOffset = cpu_to_le16(offset);
4918 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4919 pSMB->SetupCount = 1;
4920 pSMB->Reserved3 = 0;
4921 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4922 byte_count = 3 /* pad */ + params + count;
4923 pSMB->ParameterCount = cpu_to_le16(params);
4924 pSMB->DataCount = cpu_to_le16(count);
4925 pSMB->TotalParameterCount = pSMB->ParameterCount;
4926 pSMB->TotalDataCount = pSMB->DataCount;
4927 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4928 pSMB->Reserved4 = 0;
4929 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00004930 /* Samba server ignores set of file size to zero due to bugs in some
4931 older clients, but we should be precise - we use SetFileSize to
4932 set file size and do not want to truncate file size to zero
4933 accidently as happened on one Samba server beta by putting
4934 zero instead of -1 here */
4935 data_offset->EndOfFile = NO_CHANGE_64;
4936 data_offset->NumOfBytes = NO_CHANGE_64;
4937 data_offset->LastStatusChange = NO_CHANGE_64;
4938 data_offset->LastAccessTime = NO_CHANGE_64;
4939 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 data_offset->Uid = cpu_to_le64(uid);
4941 data_offset->Gid = cpu_to_le64(gid);
4942 /* better to leave device as zero when it is */
4943 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4944 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4945 data_offset->Permissions = cpu_to_le64(mode);
4946
4947 if(S_ISREG(mode))
4948 data_offset->Type = cpu_to_le32(UNIX_FILE);
4949 else if(S_ISDIR(mode))
4950 data_offset->Type = cpu_to_le32(UNIX_DIR);
4951 else if(S_ISLNK(mode))
4952 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4953 else if(S_ISCHR(mode))
4954 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4955 else if(S_ISBLK(mode))
4956 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4957 else if(S_ISFIFO(mode))
4958 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4959 else if(S_ISSOCK(mode))
4960 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4961
4962
4963 pSMB->ByteCount = cpu_to_le16(byte_count);
4964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4966 if (rc) {
4967 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4968 }
4969
4970 if (pSMB)
4971 cifs_buf_release(pSMB);
4972 if (rc == -EAGAIN)
4973 goto setPermsRetry;
4974 return rc;
4975}
4976
4977int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004978 const int notify_subdirs, const __u16 netfid,
4979 __u32 filter, struct file * pfile, int multishot,
4980 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981{
4982 int rc = 0;
4983 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004984 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004985 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 int bytes_returned;
4987
4988 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4989 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4990 (void **) &pSMBr);
4991 if (rc)
4992 return rc;
4993
4994 pSMB->TotalParameterCount = 0 ;
4995 pSMB->TotalDataCount = 0;
4996 pSMB->MaxParameterCount = cpu_to_le32(2);
4997 /* BB find exact data count max from sess structure BB */
4998 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004999/* BB VERIFY verify which is correct for above BB */
5000 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5001 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5002
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 pSMB->MaxSetupCount = 4;
5004 pSMB->Reserved = 0;
5005 pSMB->ParameterOffset = 0;
5006 pSMB->DataCount = 0;
5007 pSMB->DataOffset = 0;
5008 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5009 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5010 pSMB->ParameterCount = pSMB->TotalParameterCount;
5011 if(notify_subdirs)
5012 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5013 pSMB->Reserved2 = 0;
5014 pSMB->CompletionFilter = cpu_to_le32(filter);
5015 pSMB->Fid = netfid; /* file handle always le */
5016 pSMB->ByteCount = 0;
5017
5018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5019 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5020 if (rc) {
5021 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005022 } else {
5023 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07005024 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005025 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005026 sizeof(struct dir_notify_req),
5027 GFP_KERNEL);
5028 if(dnotify_req) {
5029 dnotify_req->Pid = pSMB->hdr.Pid;
5030 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5031 dnotify_req->Mid = pSMB->hdr.Mid;
5032 dnotify_req->Tid = pSMB->hdr.Tid;
5033 dnotify_req->Uid = pSMB->hdr.Uid;
5034 dnotify_req->netfid = netfid;
5035 dnotify_req->pfile = pfile;
5036 dnotify_req->filter = filter;
5037 dnotify_req->multishot = multishot;
5038 spin_lock(&GlobalMid_Lock);
5039 list_add_tail(&dnotify_req->lhead,
5040 &GlobalDnotifyReqList);
5041 spin_unlock(&GlobalMid_Lock);
5042 } else
5043 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 }
5045 cifs_buf_release(pSMB);
5046 return rc;
5047}
5048#ifdef CONFIG_CIFS_XATTR
5049ssize_t
5050CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5051 const unsigned char *searchName,
5052 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005053 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054{
5055 /* BB assumes one setup word */
5056 TRANSACTION2_QPI_REQ *pSMB = NULL;
5057 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5058 int rc = 0;
5059 int bytes_returned;
5060 int name_len;
5061 struct fea * temp_fea;
5062 char * temp_ptr;
5063 __u16 params, byte_count;
5064
5065 cFYI(1, ("In Query All EAs path %s", searchName));
5066QAllEAsRetry:
5067 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5068 (void **) &pSMBr);
5069 if (rc)
5070 return rc;
5071
5072 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5073 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005074 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005075 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 name_len++; /* trailing null */
5077 name_len *= 2;
5078 } else { /* BB improve the check for buffer overruns BB */
5079 name_len = strnlen(searchName, PATH_MAX);
5080 name_len++; /* trailing null */
5081 strncpy(pSMB->FileName, searchName, name_len);
5082 }
5083
5084 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5085 pSMB->TotalDataCount = 0;
5086 pSMB->MaxParameterCount = cpu_to_le16(2);
5087 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5088 pSMB->MaxSetupCount = 0;
5089 pSMB->Reserved = 0;
5090 pSMB->Flags = 0;
5091 pSMB->Timeout = 0;
5092 pSMB->Reserved2 = 0;
5093 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5094 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5095 pSMB->DataCount = 0;
5096 pSMB->DataOffset = 0;
5097 pSMB->SetupCount = 1;
5098 pSMB->Reserved3 = 0;
5099 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5100 byte_count = params + 1 /* pad */ ;
5101 pSMB->TotalParameterCount = cpu_to_le16(params);
5102 pSMB->ParameterCount = pSMB->TotalParameterCount;
5103 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5104 pSMB->Reserved4 = 0;
5105 pSMB->hdr.smb_buf_length += byte_count;
5106 pSMB->ByteCount = cpu_to_le16(byte_count);
5107
5108 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5109 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5110 if (rc) {
5111 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5112 } else { /* decode response */
5113 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5114
5115 /* BB also check enough total bytes returned */
5116 /* BB we need to improve the validity checking
5117 of these trans2 responses */
5118 if (rc || (pSMBr->ByteCount < 4))
5119 rc = -EIO; /* bad smb */
5120 /* else if (pFindData){
5121 memcpy((char *) pFindData,
5122 (char *) &pSMBr->hdr.Protocol +
5123 data_offset, kl);
5124 }*/ else {
5125 /* check that length of list is not more than bcc */
5126 /* check that each entry does not go beyond length
5127 of list */
5128 /* check that each element of each entry does not
5129 go beyond end of list */
5130 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5131 struct fealist * ea_response_data;
5132 rc = 0;
5133 /* validate_trans2_offsets() */
5134 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5135 ea_response_data = (struct fealist *)
5136 (((char *) &pSMBr->hdr.Protocol) +
5137 data_offset);
5138 name_len = le32_to_cpu(ea_response_data->list_len);
5139 cFYI(1,("ea length %d", name_len));
5140 if(name_len <= 8) {
5141 /* returned EA size zeroed at top of function */
5142 cFYI(1,("empty EA list returned from server"));
5143 } else {
5144 /* account for ea list len */
5145 name_len -= 4;
5146 temp_fea = ea_response_data->list;
5147 temp_ptr = (char *)temp_fea;
5148 while(name_len > 0) {
5149 __u16 value_len;
5150 name_len -= 4;
5151 temp_ptr += 4;
5152 rc += temp_fea->name_len;
5153 /* account for prefix user. and trailing null */
5154 rc = rc + 5 + 1;
5155 if(rc<(int)buf_size) {
5156 memcpy(EAData,"user.",5);
5157 EAData+=5;
5158 memcpy(EAData,temp_ptr,temp_fea->name_len);
5159 EAData+=temp_fea->name_len;
5160 /* null terminate name */
5161 *EAData = 0;
5162 EAData = EAData + 1;
5163 } else if(buf_size == 0) {
5164 /* skip copy - calc size only */
5165 } else {
5166 /* stop before overrun buffer */
5167 rc = -ERANGE;
5168 break;
5169 }
5170 name_len -= temp_fea->name_len;
5171 temp_ptr += temp_fea->name_len;
5172 /* account for trailing null */
5173 name_len--;
5174 temp_ptr++;
5175 value_len = le16_to_cpu(temp_fea->value_len);
5176 name_len -= value_len;
5177 temp_ptr += value_len;
5178 /* BB check that temp_ptr is still within smb BB*/
5179 /* no trailing null to account for in value len */
5180 /* go on to next EA */
5181 temp_fea = (struct fea *)temp_ptr;
5182 }
5183 }
5184 }
5185 }
5186 if (pSMB)
5187 cifs_buf_release(pSMB);
5188 if (rc == -EAGAIN)
5189 goto QAllEAsRetry;
5190
5191 return (ssize_t)rc;
5192}
5193
5194ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5195 const unsigned char * searchName,const unsigned char * ea_name,
5196 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005197 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198{
5199 TRANSACTION2_QPI_REQ *pSMB = NULL;
5200 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5201 int rc = 0;
5202 int bytes_returned;
5203 int name_len;
5204 struct fea * temp_fea;
5205 char * temp_ptr;
5206 __u16 params, byte_count;
5207
5208 cFYI(1, ("In Query EA path %s", searchName));
5209QEARetry:
5210 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5211 (void **) &pSMBr);
5212 if (rc)
5213 return rc;
5214
5215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5216 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005217 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005218 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 name_len++; /* trailing null */
5220 name_len *= 2;
5221 } else { /* BB improve the check for buffer overruns BB */
5222 name_len = strnlen(searchName, PATH_MAX);
5223 name_len++; /* trailing null */
5224 strncpy(pSMB->FileName, searchName, name_len);
5225 }
5226
5227 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5228 pSMB->TotalDataCount = 0;
5229 pSMB->MaxParameterCount = cpu_to_le16(2);
5230 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5231 pSMB->MaxSetupCount = 0;
5232 pSMB->Reserved = 0;
5233 pSMB->Flags = 0;
5234 pSMB->Timeout = 0;
5235 pSMB->Reserved2 = 0;
5236 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5237 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5238 pSMB->DataCount = 0;
5239 pSMB->DataOffset = 0;
5240 pSMB->SetupCount = 1;
5241 pSMB->Reserved3 = 0;
5242 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5243 byte_count = params + 1 /* pad */ ;
5244 pSMB->TotalParameterCount = cpu_to_le16(params);
5245 pSMB->ParameterCount = pSMB->TotalParameterCount;
5246 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5247 pSMB->Reserved4 = 0;
5248 pSMB->hdr.smb_buf_length += byte_count;
5249 pSMB->ByteCount = cpu_to_le16(byte_count);
5250
5251 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5252 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5253 if (rc) {
5254 cFYI(1, ("Send error in Query EA = %d", rc));
5255 } else { /* decode response */
5256 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5257
5258 /* BB also check enough total bytes returned */
5259 /* BB we need to improve the validity checking
5260 of these trans2 responses */
5261 if (rc || (pSMBr->ByteCount < 4))
5262 rc = -EIO; /* bad smb */
5263 /* else if (pFindData){
5264 memcpy((char *) pFindData,
5265 (char *) &pSMBr->hdr.Protocol +
5266 data_offset, kl);
5267 }*/ else {
5268 /* check that length of list is not more than bcc */
5269 /* check that each entry does not go beyond length
5270 of list */
5271 /* check that each element of each entry does not
5272 go beyond end of list */
5273 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5274 struct fealist * ea_response_data;
5275 rc = -ENODATA;
5276 /* validate_trans2_offsets() */
5277 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5278 ea_response_data = (struct fealist *)
5279 (((char *) &pSMBr->hdr.Protocol) +
5280 data_offset);
5281 name_len = le32_to_cpu(ea_response_data->list_len);
5282 cFYI(1,("ea length %d", name_len));
5283 if(name_len <= 8) {
5284 /* returned EA size zeroed at top of function */
5285 cFYI(1,("empty EA list returned from server"));
5286 } else {
5287 /* account for ea list len */
5288 name_len -= 4;
5289 temp_fea = ea_response_data->list;
5290 temp_ptr = (char *)temp_fea;
5291 /* loop through checking if we have a matching
5292 name and then return the associated value */
5293 while(name_len > 0) {
5294 __u16 value_len;
5295 name_len -= 4;
5296 temp_ptr += 4;
5297 value_len = le16_to_cpu(temp_fea->value_len);
5298 /* BB validate that value_len falls within SMB,
5299 even though maximum for name_len is 255 */
5300 if(memcmp(temp_fea->name,ea_name,
5301 temp_fea->name_len) == 0) {
5302 /* found a match */
5303 rc = value_len;
5304 /* account for prefix user. and trailing null */
5305 if(rc<=(int)buf_size) {
5306 memcpy(ea_value,
5307 temp_fea->name+temp_fea->name_len+1,
5308 rc);
5309 /* ea values, unlike ea names,
5310 are not null terminated */
5311 } else if(buf_size == 0) {
5312 /* skip copy - calc size only */
5313 } else {
5314 /* stop before overrun buffer */
5315 rc = -ERANGE;
5316 }
5317 break;
5318 }
5319 name_len -= temp_fea->name_len;
5320 temp_ptr += temp_fea->name_len;
5321 /* account for trailing null */
5322 name_len--;
5323 temp_ptr++;
5324 name_len -= value_len;
5325 temp_ptr += value_len;
5326 /* no trailing null to account for in value len */
5327 /* go on to next EA */
5328 temp_fea = (struct fea *)temp_ptr;
5329 }
5330 }
5331 }
5332 }
5333 if (pSMB)
5334 cifs_buf_release(pSMB);
5335 if (rc == -EAGAIN)
5336 goto QEARetry;
5337
5338 return (ssize_t)rc;
5339}
5340
5341int
5342CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5343 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005344 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5345 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346{
5347 struct smb_com_transaction2_spi_req *pSMB = NULL;
5348 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5349 struct fealist *parm_data;
5350 int name_len;
5351 int rc = 0;
5352 int bytes_returned = 0;
5353 __u16 params, param_offset, byte_count, offset, count;
5354
5355 cFYI(1, ("In SetEA"));
5356SetEARetry:
5357 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5358 (void **) &pSMBr);
5359 if (rc)
5360 return rc;
5361
5362 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5363 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005364 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005365 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 name_len++; /* trailing null */
5367 name_len *= 2;
5368 } else { /* BB improve the check for buffer overruns BB */
5369 name_len = strnlen(fileName, PATH_MAX);
5370 name_len++; /* trailing null */
5371 strncpy(pSMB->FileName, fileName, name_len);
5372 }
5373
5374 params = 6 + name_len;
5375
5376 /* done calculating parms using name_len of file name,
5377 now use name_len to calculate length of ea name
5378 we are going to create in the inode xattrs */
5379 if(ea_name == NULL)
5380 name_len = 0;
5381 else
5382 name_len = strnlen(ea_name,255);
5383
5384 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5385 pSMB->MaxParameterCount = cpu_to_le16(2);
5386 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5387 pSMB->MaxSetupCount = 0;
5388 pSMB->Reserved = 0;
5389 pSMB->Flags = 0;
5390 pSMB->Timeout = 0;
5391 pSMB->Reserved2 = 0;
5392 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5393 InformationLevel) - 4;
5394 offset = param_offset + params;
5395 pSMB->InformationLevel =
5396 cpu_to_le16(SMB_SET_FILE_EA);
5397
5398 parm_data =
5399 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5400 offset);
5401 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5402 pSMB->DataOffset = cpu_to_le16(offset);
5403 pSMB->SetupCount = 1;
5404 pSMB->Reserved3 = 0;
5405 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5406 byte_count = 3 /* pad */ + params + count;
5407 pSMB->DataCount = cpu_to_le16(count);
5408 parm_data->list_len = cpu_to_le32(count);
5409 parm_data->list[0].EA_flags = 0;
5410 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005411 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 /* EA names are always ASCII */
5413 if(ea_name)
5414 strncpy(parm_data->list[0].name,ea_name,name_len);
5415 parm_data->list[0].name[name_len] = 0;
5416 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5417 /* caller ensures that ea_value_len is less than 64K but
5418 we need to ensure that it fits within the smb */
5419
5420 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5421 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5422 if(ea_value_len)
5423 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5424
5425 pSMB->TotalDataCount = pSMB->DataCount;
5426 pSMB->ParameterCount = cpu_to_le16(params);
5427 pSMB->TotalParameterCount = pSMB->ParameterCount;
5428 pSMB->Reserved4 = 0;
5429 pSMB->hdr.smb_buf_length += byte_count;
5430 pSMB->ByteCount = cpu_to_le16(byte_count);
5431 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5432 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5433 if (rc) {
5434 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5435 }
5436
5437 cifs_buf_release(pSMB);
5438
5439 if (rc == -EAGAIN)
5440 goto SetEARetry;
5441
5442 return rc;
5443}
5444
5445#endif