blob: 5b19ce2e43515282e1bacefa2f7c00704406d0cb [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 */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {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 */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
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) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
97 if (open_file) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 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 */
Steve French790fe572007-07-07 19:25:05 +0000116 if (tcon) {
117 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800118 /* only tree disconnect, open, and write,
119 (and ulogoff which does not have tcon)
120 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000121 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_OPEN_ANDX) &&
123 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000124 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800125 smb_command));
126 return -ENODEV;
127 }
128 }
Steve French790fe572007-07-07 19:25:05 +0000129 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French31ca3bc2005-04-28 22:41:11 -0700130 (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);
Steve French790fe572007-07-07 19:25:05 +0000138 if (tcon->ses->server->tcpStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000140 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 (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);
Steve French790fe572007-07-07 19:25:05 +0000156 if (tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700157 rc = cifs_setup_session(0, tcon->ses,
158 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000159 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 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 */
Steve French790fe572007-07-07 19:25:05 +0000173 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 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 }
Steve French790fe572007-07-07 19:25:05 +0000203 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 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 French790fe572007-07-07 19:25:05 +0000214 if (tcon != NULL)
215 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700216
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 French790fe572007-07-07 19:25:05 +0000228 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000229 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 */
Steve French790fe572007-07-07 19:25:05 +0000257 if (tcon) {
258 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800259 /* only tree disconnect, open, and write,
260 (and ulogoff which does not have tcon)
261 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000262 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800263 (smb_command != SMB_COM_OPEN_ANDX) &&
264 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000265 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800266 smb_command));
267 return -ENODEV;
268 }
269 }
270
Steve French790fe572007-07-07 19:25:05 +0000271 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French31ca3bc2005-04-28 22:41:11 -0700272 (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 French790fe572007-07-07 19:25:05 +0000280 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700281 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000283 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 (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);
Steve French790fe572007-07-07 19:25:05 +0000299 if (tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700300 rc = cifs_setup_session(0, tcon->ses,
301 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000302 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 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 */
Steve French790fe572007-07-07 19:25:05 +0000316 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 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 }
Steve French790fe572007-07-07 19:25:05 +0000346 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 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 French790fe572007-07-07 19:25:05 +0000358 if (response_buf)
Steve French39798772006-05-31 22:40:51 +0000359 *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 French790fe572007-07-07 19:25:05 +0000364 if (tcon != NULL)
365 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700366
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 */
Steve French790fe572007-07-07 19:25:05 +0000378 if (pSMB->hdr.WordCount >= 10) {
379 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 (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);
Steve French790fe572007-07-07 19:25:05 +0000384 if (total_size < 512) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 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;
Steve French790fe572007-07-07 19:25:05 +0000390 if ((total_size <= (*(u16 *)pBCC)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 (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
Steve French790fe572007-07-07 19:25:05 +0000416 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 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 */
Steve French790fe572007-07-07 19:25:05 +0000428 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000429 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000430 else /* if override flags set only sign/seal OR them with global auth */
431 secFlags = extended_security | ses->overrideSecFlg;
432
Steve French762e5ab2007-06-28 18:41:42 +0000433 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000434
Steve French1982c342005-08-17 12:38:22 -0700435 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000436 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
437 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000438 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000439
440 count = 0;
441 for(i=0;i<CIFS_NUM_PROT;i++) {
442 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
443 count += strlen(protocols[i].name) + 1;
444 /* null at end of source and target buffers anyway */
445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 pSMB->hdr.smb_buf_length += count;
447 pSMB->ByteCount = cpu_to_le16(count);
448
449 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000451 if (rc != 0)
452 goto neg_err_exit;
453
Al Viro733f99a2006-10-14 16:48:26 +0100454 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000455 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000456 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000457 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
Steve French790fe572007-07-07 19:25:05 +0000464 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100465 && ((dialect == LANMAN_PROT)
466 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-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 French790fe572007-07-07 19:25:05 +0000470 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000471 (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 */
Steve French790fe572007-07-07 19:25:05 +0000486 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000487 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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-10-02 05:53:29 +0000513 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000514 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000515 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000516 if (val < 0)
Steve Frenchb815f1e2006-10-02 05:53:29 +0000517 result = - result;
518 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000519 } else {
Steve Frenchb815f1e2006-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 French790fe572007-07-07 19:25:05 +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 French790fe572007-07-07 19:25:05 +0000538 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000539 /* 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 French790fe572007-07-07 19:25:05 +0000543 } else if (pSMBr->hdr.WordCount == 13) {
Steve French254e55e2006-06-04 05:53:15 +0000544 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;
Steve French790fe572007-07-07 19:25:05 +0000549 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000550 /* unknown wct */
551 rc = -EOPNOTSUPP;
552 goto neg_err_exit;
553 }
554 /* else wct == 17 NTLM */
555 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000556 if ((server->secMode & SECMODE_USER) == 0)
557 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000558
Steve French790fe572007-07-07 19:25:05 +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 French790fe572007-07-07 19:25:05 +0000566 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000567 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000568 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000569 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000570 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000571 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 Frenchb815f1e2006-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);
Steve French790fe572007-07-07 19:25:05 +0000623 if (rc == 1) {
Steve French254e55e2006-06-04 05:53:15 +0000624 /* BB Need to fill struct for sessetup here */
625 rc = -EOPNOTSUPP;
626 } else {
627 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
Steve French254e55e2006-06-04 05:53:15 +0000630 } else
631 server->capabilities &= ~CAP_EXTENDED_SECURITY;
632
Steve French6344a422006-06-12 04:18:35 +0000633#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000634signing_check:
Steve French6344a422006-06-12 04:18:35 +0000635#endif
Steve French762e5ab2007-06-28 18:41:42 +0000636 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
637 /* MUST_SIGN already includes the MAY_SIGN FLAG
638 so if this is zero it means that signing is disabled */
639 cFYI(1, ("Signing disabled"));
Steve French790fe572007-07-07 19:25:05 +0000640 if (server->secMode & SECMODE_SIGN_REQUIRED)
Steve French762e5ab2007-06-28 18:41:42 +0000641 cERROR(1, ("Server requires "
642 "/proc/fs/cifs/PacketSigningEnabled "
643 "to be on"));
Steve French254e55e2006-06-04 05:53:15 +0000644 server->secMode &=
645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
647 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000648 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000649 if ((server->secMode &
650 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
651 cERROR(1,
652 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000653 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000654 } else
655 server->secMode |= SECMODE_SIGN_REQUIRED;
656 } else {
657 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000658 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French254e55e2006-06-04 05:53:15 +0000659 server->secMode &=
660 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
Steve French762e5ab2007-06-28 18:41:42 +0000662
Steve French39798772006-05-31 22:40:51 +0000663neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700664 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000665
Steve French790fe572007-07-07 19:25:05 +0000666 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 return rc;
668}
669
670int
671CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
672{
673 struct smb_hdr *smb_buffer;
674 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
675 int rc = 0;
676 int length;
677
678 cFYI(1, ("In tree disconnect"));
679 /*
680 * If last user of the connection and
681 * connection alive - disconnect it
682 * If this is the last connection on the server session disconnect it
683 * (and inside session disconnect we should check if tcp socket needs
684 * to be freed and kernel thread woken up).
685 */
686 if (tcon)
687 down(&tcon->tconSem);
688 else
689 return -EIO;
690
691 atomic_dec(&tcon->useCount);
692 if (atomic_read(&tcon->useCount) > 0) {
693 up(&tcon->tconSem);
694 return -EBUSY;
695 }
696
697 /* No need to return error on this operation if tid invalidated and
698 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000699 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 up(&tcon->tconSem);
701 return 0;
702 }
703
Steve French790fe572007-07-07 19:25:05 +0000704 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 up(&tcon->tconSem);
706 return -EIO;
707 }
Steve French09d1db52005-04-28 22:41:08 -0700708 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
709 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 if (rc) {
711 up(&tcon->tconSem);
712 return rc;
713 } else {
714 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
717 &length, 0);
718 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700719 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 if (smb_buffer)
722 cifs_small_buf_release(smb_buffer);
723 up(&tcon->tconSem);
724
725 /* No need to return error on this operation if tid invalidated and
726 closed on server already e.g. due to tcp session crashing */
727 if (rc == -EAGAIN)
728 rc = 0;
729
730 return rc;
731}
732
733int
734CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
735{
736 struct smb_hdr *smb_buffer_response;
737 LOGOFF_ANDX_REQ *pSMB;
738 int rc = 0;
739 int length;
740
741 cFYI(1, ("In SMBLogoff for session disconnect"));
742 if (ses)
743 down(&ses->sesSem);
744 else
745 return -EIO;
746
747 atomic_dec(&ses->inUse);
748 if (atomic_read(&ses->inUse) > 0) {
749 up(&ses->sesSem);
750 return -EBUSY;
751 }
752 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
753 if (rc) {
754 up(&ses->sesSem);
755 return rc;
756 }
757
758 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
759
Steve French790fe572007-07-07 19:25:05 +0000760 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700761 pSMB->hdr.Mid = GetNextMid(ses->server);
762
Steve French790fe572007-07-07 19:25:05 +0000763 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
765 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
766 }
767
768 pSMB->hdr.Uid = ses->Suid;
769
770 pSMB->AndXCommand = 0xFF;
771 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
772 smb_buffer_response, &length, 0);
773 if (ses->server) {
774 atomic_dec(&ses->server->socketUseCount);
775 if (atomic_read(&ses->server->socketUseCount) == 0) {
776 spin_lock(&GlobalMid_Lock);
777 ses->server->tcpStatus = CifsExiting;
778 spin_unlock(&GlobalMid_Lock);
779 rc = -ESHUTDOWN;
780 }
781 }
Steve Frencha59c6582005-08-17 12:12:19 -0700782 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700783 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 /* if session dead then we do not need to do ulogoff,
786 since server closed smb session, no sense reporting
787 error */
788 if (rc == -EAGAIN)
789 rc = 0;
790 return rc;
791}
792
793int
Steve French737b7582005-04-28 22:41:06 -0700794CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
795 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 DELETE_FILE_REQ *pSMB = NULL;
798 DELETE_FILE_RSP *pSMBr = NULL;
799 int rc = 0;
800 int bytes_returned;
801 int name_len;
802
803DelFileRetry:
804 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
805 (void **) &pSMBr);
806 if (rc)
807 return rc;
808
809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
810 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500811 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700812 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 name_len++; /* trailing null */
814 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700815 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 name_len = strnlen(fileName, PATH_MAX);
817 name_len++; /* trailing null */
818 strncpy(pSMB->fileName, fileName, name_len);
819 }
820 pSMB->SearchAttributes =
821 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
822 pSMB->BufferFormat = 0x04;
823 pSMB->hdr.smb_buf_length += name_len + 1;
824 pSMB->ByteCount = cpu_to_le16(name_len + 1);
825 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
826 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700827 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (rc) {
829 cFYI(1, ("Error in RMFile = %d", rc));
830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 cifs_buf_release(pSMB);
833 if (rc == -EAGAIN)
834 goto DelFileRetry;
835
836 return rc;
837}
838
839int
Steve French737b7582005-04-28 22:41:06 -0700840CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
841 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 DELETE_DIRECTORY_REQ *pSMB = NULL;
844 DELETE_DIRECTORY_RSP *pSMBr = NULL;
845 int rc = 0;
846 int bytes_returned;
847 int name_len;
848
849 cFYI(1, ("In CIFSSMBRmDir"));
850RmDirRetry:
851 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
852 (void **) &pSMBr);
853 if (rc)
854 return rc;
855
856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700857 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
858 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 name_len++; /* trailing null */
860 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700861 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 name_len = strnlen(dirName, PATH_MAX);
863 name_len++; /* trailing null */
864 strncpy(pSMB->DirName, dirName, name_len);
865 }
866
867 pSMB->BufferFormat = 0x04;
868 pSMB->hdr.smb_buf_length += name_len + 1;
869 pSMB->ByteCount = cpu_to_le16(name_len + 1);
870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700872 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 if (rc) {
874 cFYI(1, ("Error in RMDir = %d", rc));
875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 cifs_buf_release(pSMB);
878 if (rc == -EAGAIN)
879 goto RmDirRetry;
880 return rc;
881}
882
883int
884CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700885 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
887 int rc = 0;
888 CREATE_DIRECTORY_REQ *pSMB = NULL;
889 CREATE_DIRECTORY_RSP *pSMBr = NULL;
890 int bytes_returned;
891 int name_len;
892
893 cFYI(1, ("In CIFSSMBMkDir"));
894MkDirRetry:
895 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
896 (void **) &pSMBr);
897 if (rc)
898 return rc;
899
900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500901 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700902 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 name_len++; /* trailing null */
904 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700905 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 name_len = strnlen(name, PATH_MAX);
907 name_len++; /* trailing null */
908 strncpy(pSMB->DirName, name, name_len);
909 }
910
911 pSMB->BufferFormat = 0x04;
912 pSMB->hdr.smb_buf_length += name_len + 1;
913 pSMB->ByteCount = cpu_to_le16(name_len + 1);
914 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
915 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700916 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (rc) {
918 cFYI(1, ("Error in Mkdir = %d", rc));
919 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700920
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 cifs_buf_release(pSMB);
922 if (rc == -EAGAIN)
923 goto MkDirRetry;
924 return rc;
925}
926
Steve French2dd29d32007-04-23 22:07:35 +0000927int
928CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
929 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
930 __u32 *pOplock, const char *name,
931 const struct nls_table *nls_codepage, int remap)
932{
933 TRANSACTION2_SPI_REQ *pSMB = NULL;
934 TRANSACTION2_SPI_RSP *pSMBr = NULL;
935 int name_len;
936 int rc = 0;
937 int bytes_returned = 0;
938 char *data_offset;
939 __u16 params, param_offset, offset, byte_count, count;
940 OPEN_PSX_REQ * pdata;
941 OPEN_PSX_RSP * psx_rsp;
942
943 cFYI(1, ("In POSIX Create"));
944PsxCreat:
945 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
946 (void **) &pSMBr);
947 if (rc)
948 return rc;
949
950 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
951 name_len =
952 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
953 PATH_MAX, nls_codepage, remap);
954 name_len++; /* trailing null */
955 name_len *= 2;
956 } else { /* BB improve the check for buffer overruns BB */
957 name_len = strnlen(name, PATH_MAX);
958 name_len++; /* trailing null */
959 strncpy(pSMB->FileName, name, name_len);
960 }
961
962 params = 6 + name_len;
963 count = sizeof(OPEN_PSX_REQ);
964 pSMB->MaxParameterCount = cpu_to_le16(2);
965 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
966 pSMB->MaxSetupCount = 0;
967 pSMB->Reserved = 0;
968 pSMB->Flags = 0;
969 pSMB->Timeout = 0;
970 pSMB->Reserved2 = 0;
971 param_offset = offsetof(struct smb_com_transaction2_spi_req,
972 InformationLevel) - 4;
973 offset = param_offset + params;
974 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
975 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
976 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
977 pdata->Permissions = cpu_to_le64(mode);
978 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
979 pdata->OpenFlags = cpu_to_le32(*pOplock);
980 pSMB->ParameterOffset = cpu_to_le16(param_offset);
981 pSMB->DataOffset = cpu_to_le16(offset);
982 pSMB->SetupCount = 1;
983 pSMB->Reserved3 = 0;
984 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
985 byte_count = 3 /* pad */ + params + count;
986
987 pSMB->DataCount = cpu_to_le16(count);
988 pSMB->ParameterCount = cpu_to_le16(params);
989 pSMB->TotalDataCount = pSMB->DataCount;
990 pSMB->TotalParameterCount = pSMB->ParameterCount;
991 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
992 pSMB->Reserved4 = 0;
993 pSMB->hdr.smb_buf_length += byte_count;
994 pSMB->ByteCount = cpu_to_le16(byte_count);
995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
997 if (rc) {
998 cFYI(1, ("Posix create returned %d", rc));
999 goto psx_create_err;
1000 }
1001
Steve French790fe572007-07-07 19:25:05 +00001002 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001003 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1004
1005 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1006 rc = -EIO; /* bad smb */
1007 goto psx_create_err;
1008 }
1009
1010 /* copy return information to pRetData */
1011 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1012 + le16_to_cpu(pSMBr->t2.DataOffset));
1013
1014 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001015 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001016 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1017 /* Let caller know file was created so we can set the mode. */
1018 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001019 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001020 *pOplock |= CIFS_CREATE_ACTION;
1021 /* check to make sure response data is there */
Steve French790fe572007-07-07 19:25:05 +00001022 if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001023 pRetData->Type = -1; /* unknown */
1024#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001025 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001026#endif
1027 } else {
Steve French790fe572007-07-07 19:25:05 +00001028 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001029 + sizeof(FILE_UNIX_BASIC_INFO)) {
1030 cERROR(1,("Open response data too small"));
1031 pRetData->Type = -1;
1032 goto psx_create_err;
1033 }
1034 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001035 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French2dd29d32007-04-23 22:07:35 +00001036 sizeof (FILE_UNIX_BASIC_INFO));
1037 }
1038
1039
1040psx_create_err:
1041 cifs_buf_release(pSMB);
1042
1043 cifs_stats_inc(&tcon->num_mkdirs);
1044
1045 if (rc == -EAGAIN)
1046 goto PsxCreat;
1047
1048 return rc;
1049}
1050
Steve Frencha9d02ad2005-08-24 23:06:05 -07001051static __u16 convert_disposition(int disposition)
1052{
1053 __u16 ofun = 0;
1054
1055 switch (disposition) {
1056 case FILE_SUPERSEDE:
1057 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1058 break;
1059 case FILE_OPEN:
1060 ofun = SMBOPEN_OAPPEND;
1061 break;
1062 case FILE_CREATE:
1063 ofun = SMBOPEN_OCREATE;
1064 break;
1065 case FILE_OPEN_IF:
1066 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1067 break;
1068 case FILE_OVERWRITE:
1069 ofun = SMBOPEN_OTRUNC;
1070 break;
1071 case FILE_OVERWRITE_IF:
1072 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1073 break;
1074 default:
Steve French790fe572007-07-07 19:25:05 +00001075 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001076 ofun = SMBOPEN_OAPPEND; /* regular open */
1077 }
1078 return ofun;
1079}
1080
1081int
1082SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1083 const char *fileName, const int openDisposition,
1084 const int access_flags, const int create_options, __u16 * netfid,
1085 int *pOplock, FILE_ALL_INFO * pfile_info,
1086 const struct nls_table *nls_codepage, int remap)
1087{
1088 int rc = -EACCES;
1089 OPENX_REQ *pSMB = NULL;
1090 OPENX_RSP *pSMBr = NULL;
1091 int bytes_returned;
1092 int name_len;
1093 __u16 count;
1094
1095OldOpenRetry:
1096 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1097 (void **) &pSMBr);
1098 if (rc)
1099 return rc;
1100
1101 pSMB->AndXCommand = 0xFF; /* none */
1102
1103 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1104 count = 1; /* account for one byte pad to word boundary */
1105 name_len =
1106 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1107 fileName, PATH_MAX, nls_codepage, remap);
1108 name_len++; /* trailing null */
1109 name_len *= 2;
1110 } else { /* BB improve check for buffer overruns BB */
1111 count = 0; /* no pad */
1112 name_len = strnlen(fileName, PATH_MAX);
1113 name_len++; /* trailing null */
1114 strncpy(pSMB->fileName, fileName, name_len);
1115 }
1116 if (*pOplock & REQ_OPLOCK)
1117 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1118 else if (*pOplock & REQ_BATCHOPLOCK) {
1119 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1120 }
1121 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1122 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1123 /* 0 = read
1124 1 = write
1125 2 = rw
1126 3 = execute
1127 */
1128 pSMB->Mode = cpu_to_le16(2);
1129 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1130 /* set file as system file if special file such
1131 as fifo and server expecting SFU style and
1132 no Unix extensions */
1133
Steve French790fe572007-07-07 19:25:05 +00001134 if (create_options & CREATE_OPTION_SPECIAL)
1135 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1136 else
Steve French3e87d802005-09-18 20:49:21 -07001137 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001138
1139 /* if ((omode & S_IWUGO) == 0)
1140 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1141 /* Above line causes problems due to vfs splitting create into two
1142 pieces - need to set mode after file created not while it is
1143 being created */
1144
1145 /* BB FIXME BB */
1146/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
1147 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001148
1149 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001150 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001151 count += name_len;
1152 pSMB->hdr.smb_buf_length += count;
1153
1154 pSMB->ByteCount = cpu_to_le16(count);
1155 /* long_op set to 1 to allow for oplock break timeouts */
1156 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1157 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1158 cifs_stats_inc(&tcon->num_opens);
1159 if (rc) {
1160 cFYI(1, ("Error in Open = %d", rc));
1161 } else {
1162 /* BB verify if wct == 15 */
1163
1164/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1165
1166 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1167 /* Let caller know file was created so we can set the mode. */
1168 /* Do we care about the CreateAction in any other cases? */
1169 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001170/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001171 *pOplock |= CIFS_CREATE_ACTION; */
1172 /* BB FIXME END */
1173
Steve French790fe572007-07-07 19:25:05 +00001174 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1176 pfile_info->LastAccessTime = 0; /* BB fixme */
1177 pfile_info->LastWriteTime = 0; /* BB fixme */
1178 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001179 pfile_info->Attributes =
1180 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001181 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001182 pfile_info->AllocationSize =
1183 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1184 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 pfile_info->NumberOfLinks = cpu_to_le32(1);
1186 }
1187 }
1188
1189 cifs_buf_release(pSMB);
1190 if (rc == -EAGAIN)
1191 goto OldOpenRetry;
1192 return rc;
1193}
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195int
1196CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1197 const char *fileName, const int openDisposition,
1198 const int access_flags, const int create_options, __u16 * netfid,
1199 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001200 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
1202 int rc = -EACCES;
1203 OPEN_REQ *pSMB = NULL;
1204 OPEN_RSP *pSMBr = NULL;
1205 int bytes_returned;
1206 int name_len;
1207 __u16 count;
1208
1209openRetry:
1210 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1211 (void **) &pSMBr);
1212 if (rc)
1213 return rc;
1214
1215 pSMB->AndXCommand = 0xFF; /* none */
1216
1217 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1218 count = 1; /* account for one byte pad to word boundary */
1219 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001220 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001221 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 name_len++; /* trailing null */
1223 name_len *= 2;
1224 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001225 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 count = 0; /* no pad */
1227 name_len = strnlen(fileName, PATH_MAX);
1228 name_len++; /* trailing null */
1229 pSMB->NameLength = cpu_to_le16(name_len);
1230 strncpy(pSMB->fileName, fileName, name_len);
1231 }
1232 if (*pOplock & REQ_OPLOCK)
1233 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1234 else if (*pOplock & REQ_BATCHOPLOCK) {
1235 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1236 }
1237 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1238 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001239 /* set file as system file if special file such
1240 as fifo and server expecting SFU style and
1241 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001242 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001243 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1244 else
1245 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 /* XP does not handle ATTR_POSIX_SEMANTICS */
1247 /* but it helps speed up case sensitive checks for other
1248 servers such as Samba */
1249 if (tcon->ses->capabilities & CAP_UNIX)
1250 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1251
1252 /* if ((omode & S_IWUGO) == 0)
1253 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1254 /* Above line causes problems due to vfs splitting create into two
1255 pieces - need to set mode after file created not while it is
1256 being created */
1257 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1258 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001259 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001260 /* BB Expirement with various impersonation levels and verify */
1261 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 pSMB->SecurityFlags =
1263 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1264
1265 count += name_len;
1266 pSMB->hdr.smb_buf_length += count;
1267
1268 pSMB->ByteCount = cpu_to_le16(count);
1269 /* long_op set to 1 to allow for oplock break timeouts */
1270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1271 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001272 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (rc) {
1274 cFYI(1, ("Error in Open = %d", rc));
1275 } else {
Steve French09d1db52005-04-28 22:41:08 -07001276 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1278 /* Let caller know file was created so we can set the mode. */
1279 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001280 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001282 if (pfile_info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1284 36 /* CreationTime to Attributes */);
1285 /* the file_info buf is endian converted by caller */
1286 pfile_info->AllocationSize = pSMBr->AllocationSize;
1287 pfile_info->EndOfFile = pSMBr->EndOfFile;
1288 pfile_info->NumberOfLinks = cpu_to_le32(1);
1289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 cifs_buf_release(pSMB);
1293 if (rc == -EAGAIN)
1294 goto openRetry;
1295 return rc;
1296}
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298int
1299CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001300 const int netfid, const unsigned int count,
1301 const __u64 lseek, unsigned int *nbytes, char **buf,
1302 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
1304 int rc = -EACCES;
1305 READ_REQ *pSMB = NULL;
1306 READ_RSP *pSMBr = NULL;
1307 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001308 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001309 int resp_buf_type = 0;
1310 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Steve French790fe572007-07-07 19:25:05 +00001312 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1313 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001314 wct = 12;
1315 else
1316 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001319 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 if (rc)
1321 return rc;
1322
1323 /* tcon and ses pointer are checked in smb_init */
1324 if (tcon->ses->server == NULL)
1325 return -ECONNABORTED;
1326
Steve Frenchec637e32005-12-12 20:53:18 -08001327 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 pSMB->Fid = netfid;
1329 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001330 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001331 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001332 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001333 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 pSMB->Remaining = 0;
1336 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1337 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001338 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001339 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1340 else {
1341 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001342 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001343 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001344 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001345 }
Steve Frenchec637e32005-12-12 20:53:18 -08001346
1347 iov[0].iov_base = (char *)pSMB;
1348 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1349 rc = SendReceive2(xid, tcon->ses, iov,
1350 1 /* num iovecs */,
1351 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001352 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001353 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 if (rc) {
1355 cERROR(1, ("Send error in read = %d", rc));
1356 } else {
1357 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1358 data_length = data_length << 16;
1359 data_length += le16_to_cpu(pSMBr->DataLength);
1360 *nbytes = data_length;
1361
1362 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001363 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 || (data_length > count)) {
1365 cFYI(1,("bad length %d for count %d",data_length,count));
1366 rc = -EIO;
1367 *nbytes = 0;
1368 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001369 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 le16_to_cpu(pSMBr->DataOffset);
Steve French790fe572007-07-07 19:25:05 +00001371/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve Frenchec637e32005-12-12 20:53:18 -08001372 cERROR(1,("Faulting on read rc = %d",rc));
1373 rc = -EFAULT;
1374 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001375 if (*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001376 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 }
1378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Steve French4b8f9302006-02-26 16:41:18 +00001380/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001381 if (*buf) {
1382 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001383 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001384 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001385 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001386 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French6cec2ae2006-02-22 17:31:52 -06001387 /* return buffer to caller to free */
1388 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001389 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001390 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001391 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001392 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001393 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001394
1395 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 since file handle passed in no longer valid */
1397 return rc;
1398}
1399
Steve Frenchec637e32005-12-12 20:53:18 -08001400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401int
1402CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1403 const int netfid, const unsigned int count,
1404 const __u64 offset, unsigned int *nbytes, const char *buf,
1405 const char __user * ubuf, const int long_op)
1406{
1407 int rc = -EACCES;
1408 WRITE_REQ *pSMB = NULL;
1409 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001410 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 __u32 bytes_sent;
1412 __u16 byte_count;
1413
1414 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001415 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001416 return -ECONNABORTED;
1417
Steve French790fe572007-07-07 19:25:05 +00001418 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001419 wct = 14;
1420 else
1421 wct = 12;
1422
1423 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 (void **) &pSMBr);
1425 if (rc)
1426 return rc;
1427 /* tcon and ses pointer are checked in smb_init */
1428 if (tcon->ses->server == NULL)
1429 return -ECONNABORTED;
1430
1431 pSMB->AndXCommand = 0xFF; /* none */
1432 pSMB->Fid = netfid;
1433 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001434 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001435 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001436 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001437 return -EIO;
1438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 pSMB->Reserved = 0xFFFFFFFF;
1440 pSMB->WriteMode = 0;
1441 pSMB->Remaining = 0;
1442
1443 /* Can increase buffer size if buffer is big enough in some cases - ie we
1444 can send more if LARGE_WRITE_X capability returned by the server and if
1445 our buffer is big enough or if we convert to iovecs on socket writes
1446 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001447 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1449 } else {
1450 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1451 & ~0xFF;
1452 }
1453
1454 if (bytes_sent > count)
1455 bytes_sent = count;
1456 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001457 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001458 if (buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 memcpy(pSMB->Data,buf,bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001460 else if (ubuf) {
1461 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 cifs_buf_release(pSMB);
1463 return -EFAULT;
1464 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001465 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 /* No buffer */
1467 cifs_buf_release(pSMB);
1468 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001469 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001470 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001471 byte_count = bytes_sent + 1; /* pad */
1472 else /* wct == 12 */ {
1473 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1476 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001477 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001478
Steve French790fe572007-07-07 19:25:05 +00001479 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001480 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001481 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001482 struct smb_com_writex_req * pSMBW =
1483 (struct smb_com_writex_req *)pSMB;
1484 pSMBW->ByteCount = cpu_to_le16(byte_count);
1485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
1487 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1488 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001489 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 if (rc) {
1491 cFYI(1, ("Send error in write = %d", rc));
1492 *nbytes = 0;
1493 } else {
1494 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1495 *nbytes = (*nbytes) << 16;
1496 *nbytes += le16_to_cpu(pSMBr->Count);
1497 }
1498
1499 cifs_buf_release(pSMB);
1500
1501 /* Note: On -EAGAIN error only caller can retry on handle based calls
1502 since file handle passed in no longer valid */
1503
1504 return rc;
1505}
1506
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001507int
1508CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001510 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1511 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512{
1513 int rc = -EACCES;
1514 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001515 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001516 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001517 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
Steve French790fe572007-07-07 19:25:05 +00001519 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001520
Steve French790fe572007-07-07 19:25:05 +00001521 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001522 wct = 14;
1523 else
1524 wct = 12;
1525 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 if (rc)
1527 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 /* tcon and ses pointer are checked in smb_init */
1529 if (tcon->ses->server == NULL)
1530 return -ECONNABORTED;
1531
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001532 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 pSMB->Fid = netfid;
1534 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001535 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001536 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001537 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001538 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 pSMB->Reserved = 0xFFFFFFFF;
1540 pSMB->WriteMode = 0;
1541 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001542
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 pSMB->DataOffset =
1544 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1545
Steve French3e844692005-10-03 13:37:24 -07001546 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1547 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001548 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001549 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001550 pSMB->hdr.smb_buf_length += count+1;
1551 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001552 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1553 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001554 pSMB->ByteCount = cpu_to_le16(count + 1);
1555 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1556 struct smb_com_writex_req * pSMBW =
1557 (struct smb_com_writex_req *)pSMB;
1558 pSMBW->ByteCount = cpu_to_le16(count + 5);
1559 }
Steve French3e844692005-10-03 13:37:24 -07001560 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001561 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001562 iov[0].iov_len = smb_hdr_len + 4;
1563 else /* wct == 12 pad bigger by four bytes */
1564 iov[0].iov_len = smb_hdr_len + 8;
1565
Steve French3e844692005-10-03 13:37:24 -07001566
Steve Frenchec637e32005-12-12 20:53:18 -08001567 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001568 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001569 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001571 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001573 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001574 /* presumably this can not happen, but best to be safe */
1575 rc = -EIO;
1576 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001577 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001578 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001579 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1580 *nbytes = (*nbytes) << 16;
1581 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Steve French4b8f9302006-02-26 16:41:18 +00001584/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001585 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001586 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001587 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001588 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 /* Note: On -EAGAIN error only caller can retry on handle based calls
1591 since file handle passed in no longer valid */
1592
1593 return rc;
1594}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001595
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597int
1598CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1599 const __u16 smb_file_id, const __u64 len,
1600 const __u64 offset, const __u32 numUnlock,
1601 const __u32 numLock, const __u8 lockType, const int waitFlag)
1602{
1603 int rc = 0;
1604 LOCK_REQ *pSMB = NULL;
1605 LOCK_RSP *pSMBr = NULL;
1606 int bytes_returned;
1607 int timeout = 0;
1608 __u16 count;
1609
1610 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001611 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1612
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 if (rc)
1614 return rc;
1615
Steve French46810cb2005-04-28 22:41:09 -07001616 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1617
Steve French790fe572007-07-07 19:25:05 +00001618 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 timeout = -1; /* no response expected */
1620 pSMB->Timeout = 0;
1621 } else if (waitFlag == TRUE) {
1622 timeout = 3; /* blocking operation, no timeout */
1623 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1624 } else {
1625 pSMB->Timeout = 0;
1626 }
1627
1628 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1629 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1630 pSMB->LockType = lockType;
1631 pSMB->AndXCommand = 0xFF; /* none */
1632 pSMB->Fid = smb_file_id; /* netfid stays le */
1633
Steve French790fe572007-07-07 19:25:05 +00001634 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1636 /* BB where to store pid high? */
1637 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1638 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1639 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1640 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1641 count = sizeof(LOCKING_ANDX_RANGE);
1642 } else {
1643 /* oplock break */
1644 count = 0;
1645 }
1646 pSMB->hdr.smb_buf_length += count;
1647 pSMB->ByteCount = cpu_to_le16(count);
1648
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001649 if (waitFlag) {
1650 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1651 (struct smb_hdr *) pSMBr, &bytes_returned);
1652 } else {
1653 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001655 }
Steve Frencha4544342005-08-24 13:59:35 -07001656 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 if (rc) {
1658 cFYI(1, ("Send error in Lock = %d", rc));
1659 }
Steve French46810cb2005-04-28 22:41:09 -07001660 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 /* Note: On -EAGAIN error only caller can retry on handle based calls
1663 since file handle passed in no longer valid */
1664 return rc;
1665}
1666
1667int
Steve French08547b02006-02-28 22:39:25 +00001668CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1669 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001670 struct file_lock *pLockData, const __u16 lock_type,
1671 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001672{
1673 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1674 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1675 char *data_offset;
1676 struct cifs_posix_lock *parm_data;
1677 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001678 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001679 int bytes_returned = 0;
1680 __u16 params, param_offset, offset, byte_count, count;
1681
1682 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001683
Steve French790fe572007-07-07 19:25:05 +00001684 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001685 return EINVAL;
1686
Steve French08547b02006-02-28 22:39:25 +00001687 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1688
1689 if (rc)
1690 return rc;
1691
1692 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1693
1694 params = 6;
1695 pSMB->MaxSetupCount = 0;
1696 pSMB->Reserved = 0;
1697 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001698 pSMB->Reserved2 = 0;
1699 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1700 offset = param_offset + params;
1701
1702 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1703
1704 count = sizeof(struct cifs_posix_lock);
1705 pSMB->MaxParameterCount = cpu_to_le16(2);
1706 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1707 pSMB->SetupCount = 1;
1708 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001709 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001710 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1711 else
1712 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1713 byte_count = 3 /* pad */ + params + count;
1714 pSMB->DataCount = cpu_to_le16(count);
1715 pSMB->ParameterCount = cpu_to_le16(params);
1716 pSMB->TotalDataCount = pSMB->DataCount;
1717 pSMB->TotalParameterCount = pSMB->ParameterCount;
1718 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1719 parm_data = (struct cifs_posix_lock *)
1720 (((char *) &pSMB->hdr.Protocol) + offset);
1721
1722 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001723 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001724 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001725 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001726 pSMB->Timeout = cpu_to_le32(-1);
1727 } else
1728 pSMB->Timeout = 0;
1729
Steve French08547b02006-02-28 22:39:25 +00001730 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001731 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001732 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001733
1734 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001735 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001736 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1737 pSMB->Reserved4 = 0;
1738 pSMB->hdr.smb_buf_length += byte_count;
1739 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001740 if (waitFlag) {
1741 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1742 (struct smb_hdr *) pSMBr, &bytes_returned);
1743 } else {
1744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001745 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001746 }
1747
Steve French08547b02006-02-28 22:39:25 +00001748 if (rc) {
1749 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001750 } else if (get_flag) {
1751 /* lock structure can be returned on get */
1752 __u16 data_offset;
1753 __u16 data_count;
1754 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001755
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001756 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1757 rc = -EIO; /* bad smb */
1758 goto plk_err_exit;
1759 }
Steve French790fe572007-07-07 19:25:05 +00001760 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001761 rc = -EINVAL;
1762 goto plk_err_exit;
1763 }
1764 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1765 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001766 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001767 rc = -EIO;
1768 goto plk_err_exit;
1769 }
1770 parm_data = (struct cifs_posix_lock *)
1771 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001772 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001773 pLockData->fl_type = F_UNLCK;
1774 }
1775
1776plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001777 if (pSMB)
1778 cifs_small_buf_release(pSMB);
1779
1780 /* Note: On -EAGAIN error only caller can retry on handle based calls
1781 since file handle passed in no longer valid */
1782
1783 return rc;
1784}
1785
1786
1787int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1789{
1790 int rc = 0;
1791 CLOSE_REQ *pSMB = NULL;
1792 CLOSE_RSP *pSMBr = NULL;
1793 int bytes_returned;
1794 cFYI(1, ("In CIFSSMBClose"));
1795
1796/* do not retry on dead session on close */
1797 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001798 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 return 0;
1800 if (rc)
1801 return rc;
1802
1803 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1804
1805 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001806 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 pSMB->ByteCount = 0;
1808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001810 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001812 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 /* EINTR is expected when user ctl-c to kill app */
1814 cERROR(1, ("Send error in Close = %d", rc));
1815 }
1816 }
1817
1818 cifs_small_buf_release(pSMB);
1819
1820 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001821 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 rc = 0;
1823
1824 return rc;
1825}
1826
1827int
1828CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1829 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001830 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831{
1832 int rc = 0;
1833 RENAME_REQ *pSMB = NULL;
1834 RENAME_RSP *pSMBr = NULL;
1835 int bytes_returned;
1836 int name_len, name_len2;
1837 __u16 count;
1838
1839 cFYI(1, ("In CIFSSMBRename"));
1840renameRetry:
1841 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1842 (void **) &pSMBr);
1843 if (rc)
1844 return rc;
1845
1846 pSMB->BufferFormat = 0x04;
1847 pSMB->SearchAttributes =
1848 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1849 ATTR_DIRECTORY);
1850
1851 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1852 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001853 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001854 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 name_len++; /* trailing null */
1856 name_len *= 2;
1857 pSMB->OldFileName[name_len] = 0x04; /* pad */
1858 /* protocol requires ASCII signature byte on Unicode string */
1859 pSMB->OldFileName[name_len + 1] = 0x00;
1860 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001861 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001862 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1864 name_len2 *= 2; /* convert to bytes */
1865 } else { /* BB improve the check for buffer overruns BB */
1866 name_len = strnlen(fromName, PATH_MAX);
1867 name_len++; /* trailing null */
1868 strncpy(pSMB->OldFileName, fromName, name_len);
1869 name_len2 = strnlen(toName, PATH_MAX);
1870 name_len2++; /* trailing null */
1871 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1872 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1873 name_len2++; /* trailing null */
1874 name_len2++; /* signature byte */
1875 }
1876
1877 count = 1 /* 1st signature byte */ + name_len + name_len2;
1878 pSMB->hdr.smb_buf_length += count;
1879 pSMB->ByteCount = cpu_to_le16(count);
1880
1881 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1882 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001883 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (rc) {
1885 cFYI(1, ("Send error in rename = %d", rc));
1886 }
1887
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 cifs_buf_release(pSMB);
1889
1890 if (rc == -EAGAIN)
1891 goto renameRetry;
1892
1893 return rc;
1894}
1895
1896int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001897 int netfid, char * target_name,
1898 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899{
1900 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1901 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1902 struct set_file_rename * rename_info;
1903 char *data_offset;
1904 char dummy_string[30];
1905 int rc = 0;
1906 int bytes_returned = 0;
1907 int len_of_str;
1908 __u16 params, param_offset, offset, count, byte_count;
1909
1910 cFYI(1, ("Rename to File by handle"));
1911 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1912 (void **) &pSMBr);
1913 if (rc)
1914 return rc;
1915
1916 params = 6;
1917 pSMB->MaxSetupCount = 0;
1918 pSMB->Reserved = 0;
1919 pSMB->Flags = 0;
1920 pSMB->Timeout = 0;
1921 pSMB->Reserved2 = 0;
1922 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1923 offset = param_offset + params;
1924
1925 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1926 rename_info = (struct set_file_rename *) data_offset;
1927 pSMB->MaxParameterCount = cpu_to_le16(2);
1928 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1929 pSMB->SetupCount = 1;
1930 pSMB->Reserved3 = 0;
1931 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1932 byte_count = 3 /* pad */ + params;
1933 pSMB->ParameterCount = cpu_to_le16(params);
1934 pSMB->TotalParameterCount = pSMB->ParameterCount;
1935 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1936 pSMB->DataOffset = cpu_to_le16(offset);
1937 /* construct random name ".cifs_tmp<inodenum><mid>" */
1938 rename_info->overwrite = cpu_to_le32(1);
1939 rename_info->root_fid = 0;
1940 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00001941 if (target_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001943 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001944 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001946 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001947 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 }
1949 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1950 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1951 byte_count += count;
1952 pSMB->DataCount = cpu_to_le16(count);
1953 pSMB->TotalDataCount = pSMB->DataCount;
1954 pSMB->Fid = netfid;
1955 pSMB->InformationLevel =
1956 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1957 pSMB->Reserved4 = 0;
1958 pSMB->hdr.smb_buf_length += byte_count;
1959 pSMB->ByteCount = cpu_to_le16(byte_count);
1960 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1961 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001962 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001964 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001966
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 cifs_buf_release(pSMB);
1968
1969 /* Note: On -EAGAIN error only caller can retry on handle based calls
1970 since file handle passed in no longer valid */
1971
1972 return rc;
1973}
1974
1975int
1976CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1977 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001978 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
1980 int rc = 0;
1981 COPY_REQ *pSMB = NULL;
1982 COPY_RSP *pSMBr = NULL;
1983 int bytes_returned;
1984 int name_len, name_len2;
1985 __u16 count;
1986
1987 cFYI(1, ("In CIFSSMBCopy"));
1988copyRetry:
1989 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1990 (void **) &pSMBr);
1991 if (rc)
1992 return rc;
1993
1994 pSMB->BufferFormat = 0x04;
1995 pSMB->Tid2 = target_tid;
1996
1997 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1998
1999 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002000 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002001 fromName, PATH_MAX, nls_codepage,
2002 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 name_len++; /* trailing null */
2004 name_len *= 2;
2005 pSMB->OldFileName[name_len] = 0x04; /* pad */
2006 /* protocol requires ASCII signature byte on Unicode string */
2007 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05002008 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002009 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2011 name_len2 *= 2; /* convert to bytes */
2012 } else { /* BB improve the check for buffer overruns BB */
2013 name_len = strnlen(fromName, PATH_MAX);
2014 name_len++; /* trailing null */
2015 strncpy(pSMB->OldFileName, fromName, name_len);
2016 name_len2 = strnlen(toName, PATH_MAX);
2017 name_len2++; /* trailing null */
2018 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2019 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2020 name_len2++; /* trailing null */
2021 name_len2++; /* signature byte */
2022 }
2023
2024 count = 1 /* 1st signature byte */ + name_len + name_len2;
2025 pSMB->hdr.smb_buf_length += count;
2026 pSMB->ByteCount = cpu_to_le16(count);
2027
2028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2030 if (rc) {
2031 cFYI(1, ("Send error in copy = %d with %d files copied",
2032 rc, le16_to_cpu(pSMBr->CopyCount)));
2033 }
2034 if (pSMB)
2035 cifs_buf_release(pSMB);
2036
2037 if (rc == -EAGAIN)
2038 goto copyRetry;
2039
2040 return rc;
2041}
2042
2043int
2044CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2045 const char *fromName, const char *toName,
2046 const struct nls_table *nls_codepage)
2047{
2048 TRANSACTION2_SPI_REQ *pSMB = NULL;
2049 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2050 char *data_offset;
2051 int name_len;
2052 int name_len_target;
2053 int rc = 0;
2054 int bytes_returned = 0;
2055 __u16 params, param_offset, offset, byte_count;
2056
2057 cFYI(1, ("In Symlink Unix style"));
2058createSymLinkRetry:
2059 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2060 (void **) &pSMBr);
2061 if (rc)
2062 return rc;
2063
2064 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2065 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002066 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 /* find define for this maxpathcomponent */
2068 , nls_codepage);
2069 name_len++; /* trailing null */
2070 name_len *= 2;
2071
2072 } else { /* BB improve the check for buffer overruns BB */
2073 name_len = strnlen(fromName, PATH_MAX);
2074 name_len++; /* trailing null */
2075 strncpy(pSMB->FileName, fromName, name_len);
2076 }
2077 params = 6 + name_len;
2078 pSMB->MaxSetupCount = 0;
2079 pSMB->Reserved = 0;
2080 pSMB->Flags = 0;
2081 pSMB->Timeout = 0;
2082 pSMB->Reserved2 = 0;
2083 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2084 InformationLevel) - 4;
2085 offset = param_offset + params;
2086
2087 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2088 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2089 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002090 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 /* find define for this maxpathcomponent */
2092 , nls_codepage);
2093 name_len_target++; /* trailing null */
2094 name_len_target *= 2;
2095 } else { /* BB improve the check for buffer overruns BB */
2096 name_len_target = strnlen(toName, PATH_MAX);
2097 name_len_target++; /* trailing null */
2098 strncpy(data_offset, toName, name_len_target);
2099 }
2100
2101 pSMB->MaxParameterCount = cpu_to_le16(2);
2102 /* BB find exact max on data count below from sess */
2103 pSMB->MaxDataCount = cpu_to_le16(1000);
2104 pSMB->SetupCount = 1;
2105 pSMB->Reserved3 = 0;
2106 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2107 byte_count = 3 /* pad */ + params + name_len_target;
2108 pSMB->DataCount = cpu_to_le16(name_len_target);
2109 pSMB->ParameterCount = cpu_to_le16(params);
2110 pSMB->TotalDataCount = pSMB->DataCount;
2111 pSMB->TotalParameterCount = pSMB->ParameterCount;
2112 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2113 pSMB->DataOffset = cpu_to_le16(offset);
2114 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2115 pSMB->Reserved4 = 0;
2116 pSMB->hdr.smb_buf_length += byte_count;
2117 pSMB->ByteCount = cpu_to_le16(byte_count);
2118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002120 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 if (rc) {
2122 cFYI(1,
2123 ("Send error in SetPathInfo (create symlink) = %d",
2124 rc));
2125 }
2126
2127 if (pSMB)
2128 cifs_buf_release(pSMB);
2129
2130 if (rc == -EAGAIN)
2131 goto createSymLinkRetry;
2132
2133 return rc;
2134}
2135
2136int
2137CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2138 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002139 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140{
2141 TRANSACTION2_SPI_REQ *pSMB = NULL;
2142 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2143 char *data_offset;
2144 int name_len;
2145 int name_len_target;
2146 int rc = 0;
2147 int bytes_returned = 0;
2148 __u16 params, param_offset, offset, byte_count;
2149
2150 cFYI(1, ("In Create Hard link Unix style"));
2151createHardLinkRetry:
2152 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2153 (void **) &pSMBr);
2154 if (rc)
2155 return rc;
2156
2157 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002158 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002159 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 name_len++; /* trailing null */
2161 name_len *= 2;
2162
2163 } else { /* BB improve the check for buffer overruns BB */
2164 name_len = strnlen(toName, PATH_MAX);
2165 name_len++; /* trailing null */
2166 strncpy(pSMB->FileName, toName, name_len);
2167 }
2168 params = 6 + name_len;
2169 pSMB->MaxSetupCount = 0;
2170 pSMB->Reserved = 0;
2171 pSMB->Flags = 0;
2172 pSMB->Timeout = 0;
2173 pSMB->Reserved2 = 0;
2174 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2175 InformationLevel) - 4;
2176 offset = param_offset + params;
2177
2178 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2179 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2180 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002181 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002182 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 name_len_target++; /* trailing null */
2184 name_len_target *= 2;
2185 } else { /* BB improve the check for buffer overruns BB */
2186 name_len_target = strnlen(fromName, PATH_MAX);
2187 name_len_target++; /* trailing null */
2188 strncpy(data_offset, fromName, name_len_target);
2189 }
2190
2191 pSMB->MaxParameterCount = cpu_to_le16(2);
2192 /* BB find exact max on data count below from sess*/
2193 pSMB->MaxDataCount = cpu_to_le16(1000);
2194 pSMB->SetupCount = 1;
2195 pSMB->Reserved3 = 0;
2196 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2197 byte_count = 3 /* pad */ + params + name_len_target;
2198 pSMB->ParameterCount = cpu_to_le16(params);
2199 pSMB->TotalParameterCount = pSMB->ParameterCount;
2200 pSMB->DataCount = cpu_to_le16(name_len_target);
2201 pSMB->TotalDataCount = pSMB->DataCount;
2202 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2203 pSMB->DataOffset = cpu_to_le16(offset);
2204 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2205 pSMB->Reserved4 = 0;
2206 pSMB->hdr.smb_buf_length += byte_count;
2207 pSMB->ByteCount = cpu_to_le16(byte_count);
2208 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2209 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002210 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 if (rc) {
2212 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2213 }
2214
2215 cifs_buf_release(pSMB);
2216 if (rc == -EAGAIN)
2217 goto createHardLinkRetry;
2218
2219 return rc;
2220}
2221
2222int
2223CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2224 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002225 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226{
2227 int rc = 0;
2228 NT_RENAME_REQ *pSMB = NULL;
2229 RENAME_RSP *pSMBr = NULL;
2230 int bytes_returned;
2231 int name_len, name_len2;
2232 __u16 count;
2233
2234 cFYI(1, ("In CIFSCreateHardLink"));
2235winCreateHardLinkRetry:
2236
2237 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2238 (void **) &pSMBr);
2239 if (rc)
2240 return rc;
2241
2242 pSMB->SearchAttributes =
2243 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2244 ATTR_DIRECTORY);
2245 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2246 pSMB->ClusterCount = 0;
2247
2248 pSMB->BufferFormat = 0x04;
2249
2250 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2251 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002252 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002253 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 name_len++; /* trailing null */
2255 name_len *= 2;
2256 pSMB->OldFileName[name_len] = 0; /* pad */
2257 pSMB->OldFileName[name_len + 1] = 0x04;
2258 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002259 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002260 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2262 name_len2 *= 2; /* convert to bytes */
2263 } else { /* BB improve the check for buffer overruns BB */
2264 name_len = strnlen(fromName, PATH_MAX);
2265 name_len++; /* trailing null */
2266 strncpy(pSMB->OldFileName, fromName, name_len);
2267 name_len2 = strnlen(toName, PATH_MAX);
2268 name_len2++; /* trailing null */
2269 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2270 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2271 name_len2++; /* trailing null */
2272 name_len2++; /* signature byte */
2273 }
2274
2275 count = 1 /* string type byte */ + name_len + name_len2;
2276 pSMB->hdr.smb_buf_length += count;
2277 pSMB->ByteCount = cpu_to_le16(count);
2278
2279 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2280 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002281 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 if (rc) {
2283 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2284 }
2285 cifs_buf_release(pSMB);
2286 if (rc == -EAGAIN)
2287 goto winCreateHardLinkRetry;
2288
2289 return rc;
2290}
2291
2292int
2293CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2294 const unsigned char *searchName,
2295 char *symlinkinfo, const int buflen,
2296 const struct nls_table *nls_codepage)
2297{
2298/* SMB_QUERY_FILE_UNIX_LINK */
2299 TRANSACTION2_QPI_REQ *pSMB = NULL;
2300 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2301 int rc = 0;
2302 int bytes_returned;
2303 int name_len;
2304 __u16 params, byte_count;
2305
2306 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2307
2308querySymLinkRetry:
2309 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2310 (void **) &pSMBr);
2311 if (rc)
2312 return rc;
2313
2314 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2315 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002316 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 /* find define for this maxpathcomponent */
2318 , nls_codepage);
2319 name_len++; /* trailing null */
2320 name_len *= 2;
2321 } else { /* BB improve the check for buffer overruns BB */
2322 name_len = strnlen(searchName, PATH_MAX);
2323 name_len++; /* trailing null */
2324 strncpy(pSMB->FileName, searchName, name_len);
2325 }
2326
2327 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2328 pSMB->TotalDataCount = 0;
2329 pSMB->MaxParameterCount = cpu_to_le16(2);
2330 /* BB find exact max data count below from sess structure BB */
2331 pSMB->MaxDataCount = cpu_to_le16(4000);
2332 pSMB->MaxSetupCount = 0;
2333 pSMB->Reserved = 0;
2334 pSMB->Flags = 0;
2335 pSMB->Timeout = 0;
2336 pSMB->Reserved2 = 0;
2337 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2338 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2339 pSMB->DataCount = 0;
2340 pSMB->DataOffset = 0;
2341 pSMB->SetupCount = 1;
2342 pSMB->Reserved3 = 0;
2343 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2344 byte_count = params + 1 /* pad */ ;
2345 pSMB->TotalParameterCount = cpu_to_le16(params);
2346 pSMB->ParameterCount = pSMB->TotalParameterCount;
2347 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2348 pSMB->Reserved4 = 0;
2349 pSMB->hdr.smb_buf_length += byte_count;
2350 pSMB->ByteCount = cpu_to_le16(byte_count);
2351
2352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2354 if (rc) {
2355 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2356 } else {
2357 /* decode response */
2358
2359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2360 if (rc || (pSMBr->ByteCount < 2))
2361 /* BB also check enough total bytes returned */
2362 rc = -EIO; /* bad smb */
2363 else {
2364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2365 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2366
2367 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2368 name_len = UniStrnlen((wchar_t *) ((char *)
2369 &pSMBr->hdr.Protocol +data_offset),
2370 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002371 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002373 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 data_offset),
2375 name_len, nls_codepage);
2376 } else {
2377 strncpy(symlinkinfo,
2378 (char *) &pSMBr->hdr.Protocol +
2379 data_offset,
2380 min_t(const int, buflen, count));
2381 }
2382 symlinkinfo[buflen] = 0;
2383 /* just in case so calling code does not go off the end of buffer */
2384 }
2385 }
2386 cifs_buf_release(pSMB);
2387 if (rc == -EAGAIN)
2388 goto querySymLinkRetry;
2389 return rc;
2390}
2391
Steve French0a4b92c2006-01-12 15:44:21 -08002392/* Initialize NT TRANSACT SMB into small smb request buffer.
2393 This assumes that all NT TRANSACTS that we init here have
2394 total parm and data under about 400 bytes (to fit in small cifs
2395 buffer size), which is the case so far, it easily fits. NB:
2396 Setup words themselves and ByteCount
2397 MaxSetupCount (size of returned setup area) and
2398 MaxParameterCount (returned parms size) must be set by caller */
2399static int
2400smb_init_ntransact(const __u16 sub_command, const int setup_count,
2401 const int parm_len, struct cifsTconInfo *tcon,
2402 void ** ret_buf)
2403{
2404 int rc;
2405 __u32 temp_offset;
2406 struct smb_com_ntransact_req * pSMB;
2407
2408 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2409 (void **)&pSMB);
2410 if (rc)
2411 return rc;
2412 *ret_buf = (void *)pSMB;
2413 pSMB->Reserved = 0;
2414 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2415 pSMB->TotalDataCount = 0;
2416 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2417 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2418 pSMB->ParameterCount = pSMB->TotalParameterCount;
2419 pSMB->DataCount = pSMB->TotalDataCount;
2420 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2421 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2422 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2423 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2424 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2425 pSMB->SubCommand = cpu_to_le16(sub_command);
2426 return 0;
2427}
2428
2429static int
2430validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2431 int * pdatalen, int * pparmlen)
2432{
2433 char * end_of_smb;
2434 __u32 data_count, data_offset, parm_count, parm_offset;
2435 struct smb_com_ntransact_rsp * pSMBr;
2436
Steve French790fe572007-07-07 19:25:05 +00002437 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002438 return -EINVAL;
2439
2440 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2441
2442 /* ByteCount was converted from little endian in SendReceive */
2443 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2444 (char *)&pSMBr->ByteCount;
2445
2446
2447 data_offset = le32_to_cpu(pSMBr->DataOffset);
2448 data_count = le32_to_cpu(pSMBr->DataCount);
2449 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2450 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2451
2452 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2453 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2454
2455 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002456 if (*ppparm > end_of_smb) {
2457 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002458 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002459 } else if (parm_count + *ppparm > end_of_smb) {
2460 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002461 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002462 } else if (*ppdata > end_of_smb) {
2463 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002464 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002465 } else if (data_count + *ppdata > end_of_smb) {
Steve French0a4b92c2006-01-12 15:44:21 -08002466 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2467 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2468 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002469 } else if (parm_count + data_count > pSMBr->ByteCount) {
2470 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002471 return -EINVAL;
2472 }
2473 return 0;
2474}
2475
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476int
2477CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2478 const unsigned char *searchName,
2479 char *symlinkinfo, const int buflen,__u16 fid,
2480 const struct nls_table *nls_codepage)
2481{
2482 int rc = 0;
2483 int bytes_returned;
2484 int name_len;
2485 struct smb_com_transaction_ioctl_req * pSMB;
2486 struct smb_com_transaction_ioctl_rsp * pSMBr;
2487
2488 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2489 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2490 (void **) &pSMBr);
2491 if (rc)
2492 return rc;
2493
2494 pSMB->TotalParameterCount = 0 ;
2495 pSMB->TotalDataCount = 0;
2496 pSMB->MaxParameterCount = cpu_to_le32(2);
2497 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002498 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2499 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 pSMB->MaxSetupCount = 4;
2501 pSMB->Reserved = 0;
2502 pSMB->ParameterOffset = 0;
2503 pSMB->DataCount = 0;
2504 pSMB->DataOffset = 0;
2505 pSMB->SetupCount = 4;
2506 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2507 pSMB->ParameterCount = pSMB->TotalParameterCount;
2508 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2509 pSMB->IsFsctl = 1; /* FSCTL */
2510 pSMB->IsRootFlag = 0;
2511 pSMB->Fid = fid; /* file handle always le */
2512 pSMB->ByteCount = 0;
2513
2514 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2515 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2516 if (rc) {
2517 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2518 } else { /* decode response */
2519 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2520 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2521 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2522 /* BB also check enough total bytes returned */
2523 rc = -EIO; /* bad smb */
2524 else {
Steve French790fe572007-07-07 19:25:05 +00002525 if (data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002526 char * end_of_smb = 2 /* sizeof byte count */ +
2527 pSMBr->ByteCount +
2528 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530 struct reparse_data * reparse_buf = (struct reparse_data *)
2531 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002532 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 rc = -EIO;
2534 goto qreparse_out;
2535 }
Steve French790fe572007-07-07 19:25:05 +00002536 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 reparse_buf->TargetNameOffset +
2538 reparse_buf->TargetNameLen) >
2539 end_of_smb) {
2540 cFYI(1,("reparse buf extended beyond SMB"));
2541 rc = -EIO;
2542 goto qreparse_out;
2543 }
2544
2545 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2546 name_len = UniStrnlen((wchar_t *)
2547 (reparse_buf->LinkNamesBuf +
2548 reparse_buf->TargetNameOffset),
2549 min(buflen/2, reparse_buf->TargetNameLen / 2));
2550 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002551 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 reparse_buf->TargetNameOffset),
2553 name_len, nls_codepage);
2554 } else { /* ASCII names */
2555 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2556 reparse_buf->TargetNameOffset,
2557 min_t(const int, buflen, reparse_buf->TargetNameLen));
2558 }
2559 } else {
2560 rc = -EIO;
2561 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2562 }
2563 symlinkinfo[buflen] = 0; /* just in case so the caller
2564 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002565 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 }
2567 }
2568qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002569 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570
2571 /* Note: On -EAGAIN error only caller can retry on handle based calls
2572 since file handle passed in no longer valid */
2573
2574 return rc;
2575}
2576
2577#ifdef CONFIG_CIFS_POSIX
2578
2579/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2580static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2581{
2582 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002583 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2584 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2585 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2587
2588 return;
2589}
2590
2591/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002592static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2593 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594{
2595 int size = 0;
2596 int i;
2597 __u16 count;
2598 struct cifs_posix_ace * pACE;
2599 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2600 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2601
2602 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2603 return -EOPNOTSUPP;
2604
Steve French790fe572007-07-07 19:25:05 +00002605 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 count = le16_to_cpu(cifs_acl->access_entry_count);
2607 pACE = &cifs_acl->ace_array[0];
2608 size = sizeof(struct cifs_posix_acl);
2609 size += sizeof(struct cifs_posix_ace) * count;
2610 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002611 if (size_of_data_area < size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2613 return -EINVAL;
2614 }
Steve French790fe572007-07-07 19:25:05 +00002615 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 count = le16_to_cpu(cifs_acl->access_entry_count);
2617 size = sizeof(struct cifs_posix_acl);
2618 size += sizeof(struct cifs_posix_ace) * count;
2619/* skip past access ACEs to get to default ACEs */
2620 pACE = &cifs_acl->ace_array[count];
2621 count = le16_to_cpu(cifs_acl->default_entry_count);
2622 size += sizeof(struct cifs_posix_ace) * count;
2623 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002624 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 return -EINVAL;
2626 } else {
2627 /* illegal type */
2628 return -EINVAL;
2629 }
2630
2631 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002632 if ((buflen == 0) || (local_acl == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002634 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 return -ERANGE;
2636 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002637 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 for(i = 0;i < count ;i++) {
2639 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2640 pACE ++;
2641 }
2642 }
2643 return size;
2644}
2645
2646static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2647 const posix_acl_xattr_entry * local_ace)
2648{
2649 __u16 rc = 0; /* 0 = ACL converted ok */
2650
Steve Frenchff7feac2005-11-15 16:45:16 -08002651 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2652 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002654 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 /* Probably no need to le convert -1 on any arch but can not hurt */
2656 cifs_ace->cifs_uid = cpu_to_le64(-1);
2657 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002658 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2660 return rc;
2661}
2662
2663/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2664static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2665 const int acl_type)
2666{
2667 __u16 rc = 0;
2668 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2669 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2670 int count;
2671 int i;
2672
Steve French790fe572007-07-07 19:25:05 +00002673 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 return 0;
2675
2676 count = posix_acl_xattr_count((size_t)buflen);
2677 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002678 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002679 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve Frenchff7feac2005-11-15 16:45:16 -08002680 cFYI(1,("unknown POSIX ACL version %d",
2681 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 return 0;
2683 }
2684 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002685 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002686 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002687 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002688 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 else {
2690 cFYI(1,("unknown ACL type %d",acl_type));
2691 return 0;
2692 }
2693 for(i=0;i<count;i++) {
2694 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2695 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002696 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 /* ACE not converted */
2698 break;
2699 }
2700 }
Steve French790fe572007-07-07 19:25:05 +00002701 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2703 rc += sizeof(struct cifs_posix_acl);
2704 /* BB add check to make sure ACL does not overflow SMB */
2705 }
2706 return rc;
2707}
2708
2709int
2710CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2711 const unsigned char *searchName,
2712 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002713 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714{
2715/* SMB_QUERY_POSIX_ACL */
2716 TRANSACTION2_QPI_REQ *pSMB = NULL;
2717 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2718 int rc = 0;
2719 int bytes_returned;
2720 int name_len;
2721 __u16 params, byte_count;
2722
2723 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2724
2725queryAclRetry:
2726 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2727 (void **) &pSMBr);
2728 if (rc)
2729 return rc;
2730
2731 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2732 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002733 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002734 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 name_len++; /* trailing null */
2736 name_len *= 2;
2737 pSMB->FileName[name_len] = 0;
2738 pSMB->FileName[name_len+1] = 0;
2739 } else { /* BB improve the check for buffer overruns BB */
2740 name_len = strnlen(searchName, PATH_MAX);
2741 name_len++; /* trailing null */
2742 strncpy(pSMB->FileName, searchName, name_len);
2743 }
2744
2745 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2746 pSMB->TotalDataCount = 0;
2747 pSMB->MaxParameterCount = cpu_to_le16(2);
2748 /* BB find exact max data count below from sess structure BB */
2749 pSMB->MaxDataCount = cpu_to_le16(4000);
2750 pSMB->MaxSetupCount = 0;
2751 pSMB->Reserved = 0;
2752 pSMB->Flags = 0;
2753 pSMB->Timeout = 0;
2754 pSMB->Reserved2 = 0;
2755 pSMB->ParameterOffset = cpu_to_le16(
2756 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2757 pSMB->DataCount = 0;
2758 pSMB->DataOffset = 0;
2759 pSMB->SetupCount = 1;
2760 pSMB->Reserved3 = 0;
2761 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2762 byte_count = params + 1 /* pad */ ;
2763 pSMB->TotalParameterCount = cpu_to_le16(params);
2764 pSMB->ParameterCount = pSMB->TotalParameterCount;
2765 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2766 pSMB->Reserved4 = 0;
2767 pSMB->hdr.smb_buf_length += byte_count;
2768 pSMB->ByteCount = cpu_to_le16(byte_count);
2769
2770 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2771 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002772 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 if (rc) {
2774 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2775 } else {
2776 /* decode response */
2777
2778 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2779 if (rc || (pSMBr->ByteCount < 2))
2780 /* BB also check enough total bytes returned */
2781 rc = -EIO; /* bad smb */
2782 else {
2783 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2784 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2785 rc = cifs_copy_posix_acl(acl_inf,
2786 (char *)&pSMBr->hdr.Protocol+data_offset,
2787 buflen,acl_type,count);
2788 }
2789 }
2790 cifs_buf_release(pSMB);
2791 if (rc == -EAGAIN)
2792 goto queryAclRetry;
2793 return rc;
2794}
2795
2796int
2797CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2798 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002799 const char *local_acl, const int buflen,
2800 const int acl_type,
2801 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802{
2803 struct smb_com_transaction2_spi_req *pSMB = NULL;
2804 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2805 char *parm_data;
2806 int name_len;
2807 int rc = 0;
2808 int bytes_returned = 0;
2809 __u16 params, byte_count, data_count, param_offset, offset;
2810
2811 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2812setAclRetry:
2813 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2814 (void **) &pSMBr);
2815 if (rc)
2816 return rc;
2817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2818 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002819 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002820 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 name_len++; /* trailing null */
2822 name_len *= 2;
2823 } else { /* BB improve the check for buffer overruns BB */
2824 name_len = strnlen(fileName, PATH_MAX);
2825 name_len++; /* trailing null */
2826 strncpy(pSMB->FileName, fileName, name_len);
2827 }
2828 params = 6 + name_len;
2829 pSMB->MaxParameterCount = cpu_to_le16(2);
2830 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2831 pSMB->MaxSetupCount = 0;
2832 pSMB->Reserved = 0;
2833 pSMB->Flags = 0;
2834 pSMB->Timeout = 0;
2835 pSMB->Reserved2 = 0;
2836 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2837 InformationLevel) - 4;
2838 offset = param_offset + params;
2839 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2840 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2841
2842 /* convert to on the wire format for POSIX ACL */
2843 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2844
Steve French790fe572007-07-07 19:25:05 +00002845 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 rc = -EOPNOTSUPP;
2847 goto setACLerrorExit;
2848 }
2849 pSMB->DataOffset = cpu_to_le16(offset);
2850 pSMB->SetupCount = 1;
2851 pSMB->Reserved3 = 0;
2852 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2853 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2854 byte_count = 3 /* pad */ + params + data_count;
2855 pSMB->DataCount = cpu_to_le16(data_count);
2856 pSMB->TotalDataCount = pSMB->DataCount;
2857 pSMB->ParameterCount = cpu_to_le16(params);
2858 pSMB->TotalParameterCount = pSMB->ParameterCount;
2859 pSMB->Reserved4 = 0;
2860 pSMB->hdr.smb_buf_length += byte_count;
2861 pSMB->ByteCount = cpu_to_le16(byte_count);
2862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2864 if (rc) {
2865 cFYI(1, ("Set POSIX ACL returned %d", rc));
2866 }
2867
2868setACLerrorExit:
2869 cifs_buf_release(pSMB);
2870 if (rc == -EAGAIN)
2871 goto setAclRetry;
2872 return rc;
2873}
2874
Steve Frenchf654bac2005-04-28 22:41:04 -07002875/* BB fix tabs in this function FIXME BB */
2876int
2877CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2878 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2879{
2880 int rc = 0;
2881 struct smb_t2_qfi_req *pSMB = NULL;
2882 struct smb_t2_qfi_rsp *pSMBr = NULL;
2883 int bytes_returned;
2884 __u16 params, byte_count;
2885
Steve French790fe572007-07-07 19:25:05 +00002886 cFYI(1, ("In GetExtAttr"));
2887 if (tcon == NULL)
2888 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002889
2890GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002891 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2892 (void **) &pSMBr);
2893 if (rc)
2894 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002895
Steve French790fe572007-07-07 19:25:05 +00002896 params = 2 /* level */ +2 /* fid */;
2897 pSMB->t2.TotalDataCount = 0;
2898 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2899 /* BB find exact max data count below from sess structure BB */
2900 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2901 pSMB->t2.MaxSetupCount = 0;
2902 pSMB->t2.Reserved = 0;
2903 pSMB->t2.Flags = 0;
2904 pSMB->t2.Timeout = 0;
2905 pSMB->t2.Reserved2 = 0;
2906 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2907 Fid) - 4);
2908 pSMB->t2.DataCount = 0;
2909 pSMB->t2.DataOffset = 0;
2910 pSMB->t2.SetupCount = 1;
2911 pSMB->t2.Reserved3 = 0;
2912 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2913 byte_count = params + 1 /* pad */ ;
2914 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2915 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2916 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2917 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002918 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002919 pSMB->hdr.smb_buf_length += byte_count;
2920 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002921
Steve French790fe572007-07-07 19:25:05 +00002922 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2923 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2924 if (rc) {
2925 cFYI(1, ("error %d in GetExtAttr", rc));
2926 } else {
2927 /* decode response */
2928 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2929 if (rc || (pSMBr->ByteCount < 2))
2930 /* BB also check enough total bytes returned */
2931 /* If rc should we check for EOPNOSUPP and
2932 disable the srvino flag? or in caller? */
2933 rc = -EIO; /* bad smb */
2934 else {
2935 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2936 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2937 struct file_chattr_info *pfinfo;
2938 /* BB Do we need a cast or hash here ? */
2939 if (count != 16) {
2940 cFYI(1, ("Illegal size ret in GetExtAttr"));
2941 rc = -EIO;
2942 goto GetExtAttrOut;
2943 }
2944 pfinfo = (struct file_chattr_info *)
2945 (data_offset + (char *) &pSMBr->hdr.Protocol);
2946 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07002947 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00002948 }
2949 }
Steve Frenchf654bac2005-04-28 22:41:04 -07002950GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00002951 cifs_buf_release(pSMB);
2952 if (rc == -EAGAIN)
2953 goto GetExtAttrRetry;
2954 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002955}
2956
Steve Frenchf654bac2005-04-28 22:41:04 -07002957#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
Steve Frencheeac8042006-01-13 21:34:58 -08002959
2960/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002961static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00002962 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002963/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002964static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00002965 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002966
Steve French0a4b92c2006-01-12 15:44:21 -08002967/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002968static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002969{
Steve French0a4b92c2006-01-12 15:44:21 -08002970 return 0;
2971}
2972
2973/* Get Security Descriptor (by handle) from remote server for a file or dir */
2974int
2975CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2976 /* BB fix up return info */ char *acl_inf, const int buflen,
2977 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2978{
2979 int rc = 0;
2980 int buf_type = 0;
2981 QUERY_SEC_DESC_REQ * pSMB;
2982 struct kvec iov[1];
2983
2984 cFYI(1, ("GetCifsACL"));
2985
2986 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2987 8 /* parm len */, tcon, (void **) &pSMB);
2988 if (rc)
2989 return rc;
2990
2991 pSMB->MaxParameterCount = cpu_to_le32(4);
2992 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2993 pSMB->MaxSetupCount = 0;
2994 pSMB->Fid = fid; /* file handle always le */
2995 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2996 CIFS_ACL_DACL);
2997 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2998 pSMB->hdr.smb_buf_length += 11;
2999 iov[0].iov_base = (char *)pSMB;
3000 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3001
3002 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3003 cifs_stats_inc(&tcon->num_acl_get);
3004 if (rc) {
3005 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3006 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08003007 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003008 __le32 * parm;
3009 int parm_len;
3010 int data_len;
3011 int acl_len;
3012 struct smb_com_ntransact_rsp * pSMBr;
3013
3014/* validate_nttransact */
3015 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3016 (char **)&psec_desc,
3017 &parm_len, &data_len);
3018
Steve French790fe572007-07-07 19:25:05 +00003019 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003020 goto qsec_out;
3021 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3022
3023 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
3024
3025 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3026 rc = -EIO; /* bad smb */
3027 goto qsec_out;
3028 }
3029
3030/* BB check that data area is minimum length and as big as acl_len */
3031
3032 acl_len = le32_to_cpu(*(__le32 *)parm);
Steve French790fe572007-07-07 19:25:05 +00003033 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003034
3035 parse_sec_desc(psec_desc, acl_len);
3036 }
3037qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003038 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003039 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003040 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003041 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003042/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003043 return rc;
3044}
3045
Steve French6b8edfe2005-08-23 20:26:03 -07003046/* Legacy Query Path Information call for lookup to old servers such
3047 as Win9x/WinME */
3048int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3049 const unsigned char *searchName,
3050 FILE_ALL_INFO * pFinfo,
3051 const struct nls_table *nls_codepage, int remap)
3052{
3053 QUERY_INFORMATION_REQ * pSMB;
3054 QUERY_INFORMATION_RSP * pSMBr;
3055 int rc = 0;
3056 int bytes_returned;
3057 int name_len;
3058
3059 cFYI(1, ("In SMBQPath path %s", searchName));
3060QInfRetry:
3061 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3062 (void **) &pSMBr);
3063 if (rc)
3064 return rc;
3065
3066 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3067 name_len =
3068 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3069 PATH_MAX, nls_codepage, remap);
3070 name_len++; /* trailing null */
3071 name_len *= 2;
3072 } else {
3073 name_len = strnlen(searchName, PATH_MAX);
3074 name_len++; /* trailing null */
3075 strncpy(pSMB->FileName, searchName, name_len);
3076 }
3077 pSMB->BufferFormat = 0x04;
3078 name_len++; /* account for buffer type byte */
3079 pSMB->hdr.smb_buf_length += (__u16) name_len;
3080 pSMB->ByteCount = cpu_to_le16(name_len);
3081
3082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3084 if (rc) {
3085 cFYI(1, ("Send error in QueryInfo = %d", rc));
3086 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003087 struct timespec ts;
3088 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3089 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003090 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003091 ts.tv_nsec = 0;
3092 ts.tv_sec = time;
3093 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003094 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003095 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3096 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003097 pFinfo->AllocationSize =
3098 cpu_to_le64(le32_to_cpu(pSMBr->size));
3099 pFinfo->EndOfFile = pFinfo->AllocationSize;
3100 pFinfo->Attributes =
3101 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003102 } else
3103 rc = -EIO; /* bad buffer passed in */
3104
3105 cifs_buf_release(pSMB);
3106
3107 if (rc == -EAGAIN)
3108 goto QInfRetry;
3109
3110 return rc;
3111}
3112
3113
3114
3115
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116int
3117CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3118 const unsigned char *searchName,
3119 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003120 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003121 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122{
3123/* level 263 SMB_QUERY_FILE_ALL_INFO */
3124 TRANSACTION2_QPI_REQ *pSMB = NULL;
3125 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3126 int rc = 0;
3127 int bytes_returned;
3128 int name_len;
3129 __u16 params, byte_count;
3130
3131/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3132QPathInfoRetry:
3133 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3134 (void **) &pSMBr);
3135 if (rc)
3136 return rc;
3137
3138 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3139 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003140 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003141 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 name_len++; /* trailing null */
3143 name_len *= 2;
3144 } else { /* BB improve the check for buffer overruns BB */
3145 name_len = strnlen(searchName, PATH_MAX);
3146 name_len++; /* trailing null */
3147 strncpy(pSMB->FileName, searchName, name_len);
3148 }
3149
3150 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3151 pSMB->TotalDataCount = 0;
3152 pSMB->MaxParameterCount = cpu_to_le16(2);
3153 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3154 pSMB->MaxSetupCount = 0;
3155 pSMB->Reserved = 0;
3156 pSMB->Flags = 0;
3157 pSMB->Timeout = 0;
3158 pSMB->Reserved2 = 0;
3159 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3160 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3161 pSMB->DataCount = 0;
3162 pSMB->DataOffset = 0;
3163 pSMB->SetupCount = 1;
3164 pSMB->Reserved3 = 0;
3165 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3166 byte_count = params + 1 /* pad */ ;
3167 pSMB->TotalParameterCount = cpu_to_le16(params);
3168 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003169 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003170 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3171 else
3172 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 pSMB->Reserved4 = 0;
3174 pSMB->hdr.smb_buf_length += byte_count;
3175 pSMB->ByteCount = cpu_to_le16(byte_count);
3176
3177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3179 if (rc) {
3180 cFYI(1, ("Send error in QPathInfo = %d", rc));
3181 } else { /* decode response */
3182 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3183
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003184 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3185 rc = -EIO;
3186 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003188 else if (legacy && (pSMBr->ByteCount < 24))
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003189 rc = -EIO; /* 24 or 26 expected but we do not read last field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 else if (pFindData){
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003191 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003193 if (legacy) /* we do not read the last field, EAsize,
3194 fortunately since it varies by subdialect
3195 and on Set vs. Get, is two bytes or 4
3196 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003197 size = sizeof(FILE_INFO_STANDARD);
3198 else
3199 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 memcpy((char *) pFindData,
3201 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003202 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 } else
3204 rc = -ENOMEM;
3205 }
3206 cifs_buf_release(pSMB);
3207 if (rc == -EAGAIN)
3208 goto QPathInfoRetry;
3209
3210 return rc;
3211}
3212
3213int
3214CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3215 const unsigned char *searchName,
3216 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003217 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218{
3219/* SMB_QUERY_FILE_UNIX_BASIC */
3220 TRANSACTION2_QPI_REQ *pSMB = NULL;
3221 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3222 int rc = 0;
3223 int bytes_returned = 0;
3224 int name_len;
3225 __u16 params, byte_count;
3226
3227 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3228UnixQPathInfoRetry:
3229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3230 (void **) &pSMBr);
3231 if (rc)
3232 return rc;
3233
3234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3235 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003236 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003237 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 name_len++; /* trailing null */
3239 name_len *= 2;
3240 } else { /* BB improve the check for buffer overruns BB */
3241 name_len = strnlen(searchName, PATH_MAX);
3242 name_len++; /* trailing null */
3243 strncpy(pSMB->FileName, searchName, name_len);
3244 }
3245
3246 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3247 pSMB->TotalDataCount = 0;
3248 pSMB->MaxParameterCount = cpu_to_le16(2);
3249 /* BB find exact max SMB PDU from sess structure BB */
3250 pSMB->MaxDataCount = cpu_to_le16(4000);
3251 pSMB->MaxSetupCount = 0;
3252 pSMB->Reserved = 0;
3253 pSMB->Flags = 0;
3254 pSMB->Timeout = 0;
3255 pSMB->Reserved2 = 0;
3256 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3257 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3258 pSMB->DataCount = 0;
3259 pSMB->DataOffset = 0;
3260 pSMB->SetupCount = 1;
3261 pSMB->Reserved3 = 0;
3262 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3263 byte_count = params + 1 /* pad */ ;
3264 pSMB->TotalParameterCount = cpu_to_le16(params);
3265 pSMB->ParameterCount = pSMB->TotalParameterCount;
3266 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3267 pSMB->Reserved4 = 0;
3268 pSMB->hdr.smb_buf_length += byte_count;
3269 pSMB->ByteCount = cpu_to_le16(byte_count);
3270
3271 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3272 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3273 if (rc) {
3274 cFYI(1, ("Send error in QPathInfo = %d", rc));
3275 } else { /* decode response */
3276 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3277
3278 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3279 rc = -EIO; /* bad smb */
3280 } else {
3281 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3282 memcpy((char *) pFindData,
3283 (char *) &pSMBr->hdr.Protocol +
3284 data_offset,
3285 sizeof (FILE_UNIX_BASIC_INFO));
3286 }
3287 }
3288 cifs_buf_release(pSMB);
3289 if (rc == -EAGAIN)
3290 goto UnixQPathInfoRetry;
3291
3292 return rc;
3293}
3294
3295#if 0 /* function unused at present */
3296int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3297 const char *searchName, FILE_ALL_INFO * findData,
3298 const struct nls_table *nls_codepage)
3299{
3300/* level 257 SMB_ */
3301 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3302 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3303 int rc = 0;
3304 int bytes_returned;
3305 int name_len;
3306 __u16 params, byte_count;
3307
3308 cFYI(1, ("In FindUnique"));
3309findUniqueRetry:
3310 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3311 (void **) &pSMBr);
3312 if (rc)
3313 return rc;
3314
3315 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3316 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003317 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 /* find define for this maxpathcomponent */
3319 , nls_codepage);
3320 name_len++; /* trailing null */
3321 name_len *= 2;
3322 } else { /* BB improve the check for buffer overruns BB */
3323 name_len = strnlen(searchName, PATH_MAX);
3324 name_len++; /* trailing null */
3325 strncpy(pSMB->FileName, searchName, name_len);
3326 }
3327
3328 params = 12 + name_len /* includes null */ ;
3329 pSMB->TotalDataCount = 0; /* no EAs */
3330 pSMB->MaxParameterCount = cpu_to_le16(2);
3331 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3332 pSMB->MaxSetupCount = 0;
3333 pSMB->Reserved = 0;
3334 pSMB->Flags = 0;
3335 pSMB->Timeout = 0;
3336 pSMB->Reserved2 = 0;
3337 pSMB->ParameterOffset = cpu_to_le16(
3338 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3339 pSMB->DataCount = 0;
3340 pSMB->DataOffset = 0;
3341 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3342 pSMB->Reserved3 = 0;
3343 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3344 byte_count = params + 1 /* pad */ ;
3345 pSMB->TotalParameterCount = cpu_to_le16(params);
3346 pSMB->ParameterCount = pSMB->TotalParameterCount;
3347 pSMB->SearchAttributes =
3348 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3349 ATTR_DIRECTORY);
3350 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3351 pSMB->SearchFlags = cpu_to_le16(1);
3352 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3353 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3354 pSMB->hdr.smb_buf_length += byte_count;
3355 pSMB->ByteCount = cpu_to_le16(byte_count);
3356
3357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3359
3360 if (rc) {
3361 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3362 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003363 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 /* BB fill in */
3365 }
3366
3367 cifs_buf_release(pSMB);
3368 if (rc == -EAGAIN)
3369 goto findUniqueRetry;
3370
3371 return rc;
3372}
3373#endif /* end unused (temporarily) function */
3374
3375/* xid, tcon, searchName and codepage are input parms, rest are returned */
3376int
3377CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3378 const char *searchName,
3379 const struct nls_table *nls_codepage,
3380 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003381 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382{
3383/* level 257 SMB_ */
3384 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3385 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3386 T2_FFIRST_RSP_PARMS * parms;
3387 int rc = 0;
3388 int bytes_returned = 0;
3389 int name_len;
3390 __u16 params, byte_count;
3391
Steve French737b7582005-04-28 22:41:06 -07003392 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393
3394findFirstRetry:
3395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3396 (void **) &pSMBr);
3397 if (rc)
3398 return rc;
3399
3400 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3401 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003402 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003403 PATH_MAX, nls_codepage, remap);
3404 /* We can not add the asterik earlier in case
3405 it got remapped to 0xF03A as if it were part of the
3406 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003408 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003409 pSMB->FileName[name_len+1] = 0;
3410 pSMB->FileName[name_len+2] = '*';
3411 pSMB->FileName[name_len+3] = 0;
3412 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3414 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003415 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 } else { /* BB add check for overrun of SMB buf BB */
3417 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003419 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 free buffer exit; BB */
3421 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003422 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003423 pSMB->FileName[name_len+1] = '*';
3424 pSMB->FileName[name_len+2] = 0;
3425 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 }
3427
3428 params = 12 + name_len /* includes null */ ;
3429 pSMB->TotalDataCount = 0; /* no EAs */
3430 pSMB->MaxParameterCount = cpu_to_le16(10);
3431 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3432 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3433 pSMB->MaxSetupCount = 0;
3434 pSMB->Reserved = 0;
3435 pSMB->Flags = 0;
3436 pSMB->Timeout = 0;
3437 pSMB->Reserved2 = 0;
3438 byte_count = params + 1 /* pad */ ;
3439 pSMB->TotalParameterCount = cpu_to_le16(params);
3440 pSMB->ParameterCount = pSMB->TotalParameterCount;
3441 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003442 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3443 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 pSMB->DataCount = 0;
3445 pSMB->DataOffset = 0;
3446 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3447 pSMB->Reserved3 = 0;
3448 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3449 pSMB->SearchAttributes =
3450 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3451 ATTR_DIRECTORY);
3452 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3453 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3454 CIFS_SEARCH_RETURN_RESUME);
3455 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3456
3457 /* BB what should we set StorageType to? Does it matter? BB */
3458 pSMB->SearchStorageType = 0;
3459 pSMB->hdr.smb_buf_length += byte_count;
3460 pSMB->ByteCount = cpu_to_le16(byte_count);
3461
3462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003464 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465
Steve French88274812006-03-09 22:21:45 +00003466 if (rc) {/* BB add logic to retry regular search if Unix search
3467 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 /* BB Add code to handle unsupported level rc */
3469 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003470
Steve French88274812006-03-09 22:21:45 +00003471 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472
3473 /* BB eventually could optimize out free and realloc of buf */
3474 /* for this case */
3475 if (rc == -EAGAIN)
3476 goto findFirstRetry;
3477 } else { /* decode response */
3478 /* BB remember to free buffer if error BB */
3479 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003480 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3482 psrch_inf->unicode = TRUE;
3483 else
3484 psrch_inf->unicode = FALSE;
3485
3486 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003487 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 psrch_inf->srch_entries_start =
3489 (char *) &pSMBr->hdr.Protocol +
3490 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3492 le16_to_cpu(pSMBr->t2.ParameterOffset));
3493
Steve French790fe572007-07-07 19:25:05 +00003494 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 psrch_inf->endOfSearch = TRUE;
3496 else
3497 psrch_inf->endOfSearch = FALSE;
3498
3499 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003500 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 *pnetfid = parms->SearchHandle;
3503 } else {
3504 cifs_buf_release(pSMB);
3505 }
3506 }
3507
3508 return rc;
3509}
3510
3511int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3512 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3513{
3514 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3515 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3516 T2_FNEXT_RSP_PARMS * parms;
3517 char *response_data;
3518 int rc = 0;
3519 int bytes_returned, name_len;
3520 __u16 params, byte_count;
3521
3522 cFYI(1, ("In FindNext"));
3523
Steve French790fe572007-07-07 19:25:05 +00003524 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 return -ENOENT;
3526
3527 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3528 (void **) &pSMBr);
3529 if (rc)
3530 return rc;
3531
3532 params = 14; /* includes 2 bytes of null string, converted to LE below */
3533 byte_count = 0;
3534 pSMB->TotalDataCount = 0; /* no EAs */
3535 pSMB->MaxParameterCount = cpu_to_le16(8);
3536 pSMB->MaxDataCount =
3537 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3538 pSMB->MaxSetupCount = 0;
3539 pSMB->Reserved = 0;
3540 pSMB->Flags = 0;
3541 pSMB->Timeout = 0;
3542 pSMB->Reserved2 = 0;
3543 pSMB->ParameterOffset = cpu_to_le16(
3544 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3545 pSMB->DataCount = 0;
3546 pSMB->DataOffset = 0;
3547 pSMB->SetupCount = 1;
3548 pSMB->Reserved3 = 0;
3549 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3550 pSMB->SearchHandle = searchHandle; /* always kept as le */
3551 pSMB->SearchCount =
3552 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3553 /* test for Unix extensions */
3554/* if (tcon->ses->capabilities & CAP_UNIX) {
3555 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3556 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3557 } else {
3558 pSMB->InformationLevel =
3559 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3560 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3561 } */
3562 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3563 pSMB->ResumeKey = psrch_inf->resume_key;
3564 pSMB->SearchFlags =
3565 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3566
3567 name_len = psrch_inf->resume_name_len;
3568 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003569 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3571 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003572 /* 14 byte parm len above enough for 2 byte null terminator */
3573 pSMB->ResumeFileName[name_len] = 0;
3574 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 } else {
3576 rc = -EINVAL;
3577 goto FNext2_err_exit;
3578 }
3579 byte_count = params + 1 /* pad */ ;
3580 pSMB->TotalParameterCount = cpu_to_le16(params);
3581 pSMB->ParameterCount = pSMB->TotalParameterCount;
3582 pSMB->hdr.smb_buf_length += byte_count;
3583 pSMB->ByteCount = cpu_to_le16(byte_count);
3584
3585 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3586 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003587 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 if (rc) {
3589 if (rc == -EBADF) {
3590 psrch_inf->endOfSearch = TRUE;
3591 rc = 0; /* search probably was closed at end of search above */
3592 } else
3593 cFYI(1, ("FindNext returned = %d", rc));
3594 } else { /* decode response */
3595 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3596
Steve French790fe572007-07-07 19:25:05 +00003597 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 /* BB fixme add lock for file (srch_info) struct here */
3599 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3600 psrch_inf->unicode = TRUE;
3601 else
3602 psrch_inf->unicode = FALSE;
3603 response_data = (char *) &pSMBr->hdr.Protocol +
3604 le16_to_cpu(pSMBr->t2.ParameterOffset);
3605 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3606 response_data = (char *)&pSMBr->hdr.Protocol +
3607 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003608 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003609 cifs_small_buf_release(
3610 psrch_inf->ntwrk_buf_start);
3611 else
3612 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 psrch_inf->srch_entries_start = response_data;
3614 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003615 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003616 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 psrch_inf->endOfSearch = TRUE;
3618 else
3619 psrch_inf->endOfSearch = FALSE;
3620
3621 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3622 psrch_inf->index_of_last_entry +=
3623 psrch_inf->entries_in_buffer;
3624/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3625
3626 /* BB fixme add unlock here */
3627 }
3628
3629 }
3630
3631 /* BB On error, should we leave previous search buf (and count and
3632 last entry fields) intact or free the previous one? */
3633
3634 /* Note: On -EAGAIN error only caller can retry on handle based calls
3635 since file handle passed in no longer valid */
3636FNext2_err_exit:
3637 if (rc != 0)
3638 cifs_buf_release(pSMB);
3639
3640 return rc;
3641}
3642
3643int
3644CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3645{
3646 int rc = 0;
3647 FINDCLOSE_REQ *pSMB = NULL;
3648 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3649 int bytes_returned;
3650
3651 cFYI(1, ("In CIFSSMBFindClose"));
3652 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3653
3654 /* no sense returning error if session restarted
3655 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003656 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 return 0;
3658 if (rc)
3659 return rc;
3660
3661 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3662 pSMB->FileID = searchHandle;
3663 pSMB->ByteCount = 0;
3664 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3665 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3666 if (rc) {
3667 cERROR(1, ("Send error in FindClose = %d", rc));
3668 }
Steve Frencha4544342005-08-24 13:59:35 -07003669 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 cifs_small_buf_release(pSMB);
3671
3672 /* Since session is dead, search handle closed on server already */
3673 if (rc == -EAGAIN)
3674 rc = 0;
3675
3676 return rc;
3677}
3678
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679int
3680CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3681 const unsigned char *searchName,
3682 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003683 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684{
3685 int rc = 0;
3686 TRANSACTION2_QPI_REQ *pSMB = NULL;
3687 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3688 int name_len, bytes_returned;
3689 __u16 params, byte_count;
3690
3691 cFYI(1,("In GetSrvInodeNum for %s",searchName));
Steve French790fe572007-07-07 19:25:05 +00003692 if (tcon == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 return -ENODEV;
3694
3695GetInodeNumberRetry:
3696 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3697 (void **) &pSMBr);
3698 if (rc)
3699 return rc;
3700
3701
3702 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3703 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003704 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003705 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 name_len++; /* trailing null */
3707 name_len *= 2;
3708 } else { /* BB improve the check for buffer overruns BB */
3709 name_len = strnlen(searchName, PATH_MAX);
3710 name_len++; /* trailing null */
3711 strncpy(pSMB->FileName, searchName, name_len);
3712 }
3713
3714 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3715 pSMB->TotalDataCount = 0;
3716 pSMB->MaxParameterCount = cpu_to_le16(2);
3717 /* BB find exact max data count below from sess structure BB */
3718 pSMB->MaxDataCount = cpu_to_le16(4000);
3719 pSMB->MaxSetupCount = 0;
3720 pSMB->Reserved = 0;
3721 pSMB->Flags = 0;
3722 pSMB->Timeout = 0;
3723 pSMB->Reserved2 = 0;
3724 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3725 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3726 pSMB->DataCount = 0;
3727 pSMB->DataOffset = 0;
3728 pSMB->SetupCount = 1;
3729 pSMB->Reserved3 = 0;
3730 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3731 byte_count = params + 1 /* pad */ ;
3732 pSMB->TotalParameterCount = cpu_to_le16(params);
3733 pSMB->ParameterCount = pSMB->TotalParameterCount;
3734 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3735 pSMB->Reserved4 = 0;
3736 pSMB->hdr.smb_buf_length += byte_count;
3737 pSMB->ByteCount = cpu_to_le16(byte_count);
3738
3739 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3740 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3741 if (rc) {
3742 cFYI(1, ("error %d in QueryInternalInfo", rc));
3743 } else {
3744 /* decode response */
3745 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3746 if (rc || (pSMBr->ByteCount < 2))
3747 /* BB also check enough total bytes returned */
3748 /* If rc should we check for EOPNOSUPP and
3749 disable the srvino flag? or in caller? */
3750 rc = -EIO; /* bad smb */
3751 else {
3752 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3753 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3754 struct file_internal_info * pfinfo;
3755 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003756 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3758 rc = -EIO;
3759 goto GetInodeNumOut;
3760 }
3761 pfinfo = (struct file_internal_info *)
3762 (data_offset + (char *) &pSMBr->hdr.Protocol);
3763 *inode_number = pfinfo->UniqueId;
3764 }
3765 }
3766GetInodeNumOut:
3767 cifs_buf_release(pSMB);
3768 if (rc == -EAGAIN)
3769 goto GetInodeNumberRetry;
3770 return rc;
3771}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772
3773int
3774CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3775 const unsigned char *searchName,
3776 unsigned char **targetUNCs,
3777 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003778 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779{
3780/* TRANS2_GET_DFS_REFERRAL */
3781 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3782 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3783 struct dfs_referral_level_3 * referrals = NULL;
3784 int rc = 0;
3785 int bytes_returned;
3786 int name_len;
3787 unsigned int i;
3788 char * temp;
3789 __u16 params, byte_count;
3790 *number_of_UNC_in_array = 0;
3791 *targetUNCs = NULL;
3792
3793 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3794 if (ses == NULL)
3795 return -ENODEV;
3796getDFSRetry:
3797 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3798 (void **) &pSMBr);
3799 if (rc)
3800 return rc;
Steve French1982c342005-08-17 12:38:22 -07003801
3802 /* server pointer checked in called function,
3803 but should never be null here anyway */
3804 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 pSMB->hdr.Tid = ses->ipc_tid;
3806 pSMB->hdr.Uid = ses->Suid;
3807 if (ses->capabilities & CAP_STATUS32) {
3808 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3809 }
3810 if (ses->capabilities & CAP_DFS) {
3811 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3812 }
3813
3814 if (ses->capabilities & CAP_UNICODE) {
3815 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3816 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003817 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003818 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 name_len++; /* trailing null */
3820 name_len *= 2;
3821 } else { /* BB improve the check for buffer overruns BB */
3822 name_len = strnlen(searchName, PATH_MAX);
3823 name_len++; /* trailing null */
3824 strncpy(pSMB->RequestFileName, searchName, name_len);
3825 }
3826
Steve French790fe572007-07-07 19:25:05 +00003827 if (ses->server) {
3828 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003829 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3830 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3831 }
3832
3833 pSMB->hdr.Uid = ses->Suid;
3834
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 params = 2 /* level */ + name_len /*includes null */ ;
3836 pSMB->TotalDataCount = 0;
3837 pSMB->DataCount = 0;
3838 pSMB->DataOffset = 0;
3839 pSMB->MaxParameterCount = 0;
3840 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3841 pSMB->MaxSetupCount = 0;
3842 pSMB->Reserved = 0;
3843 pSMB->Flags = 0;
3844 pSMB->Timeout = 0;
3845 pSMB->Reserved2 = 0;
3846 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3847 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3848 pSMB->SetupCount = 1;
3849 pSMB->Reserved3 = 0;
3850 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3851 byte_count = params + 3 /* pad */ ;
3852 pSMB->ParameterCount = cpu_to_le16(params);
3853 pSMB->TotalParameterCount = pSMB->ParameterCount;
3854 pSMB->MaxReferralLevel = cpu_to_le16(3);
3855 pSMB->hdr.smb_buf_length += byte_count;
3856 pSMB->ByteCount = cpu_to_le16(byte_count);
3857
3858 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3860 if (rc) {
3861 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3862 } else { /* decode response */
3863/* BB Add logic to parse referrals here */
3864 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3865
3866 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3867 rc = -EIO; /* bad smb */
3868 else {
3869 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3870 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3871
3872 cFYI(1,
3873 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3874 pSMBr->ByteCount, data_offset));
3875 referrals =
3876 (struct dfs_referral_level_3 *)
3877 (8 /* sizeof start of data block */ +
3878 data_offset +
3879 (char *) &pSMBr->hdr.Protocol);
3880 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",
3881 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)));
3882 /* BB This field is actually two bytes in from start of
3883 data block so we could do safety check that DataBlock
3884 begins at address of pSMBr->NumberOfReferrals */
3885 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3886
3887 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003888 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 *number_of_UNC_in_array = 1;
3890
3891 /* get the length of the strings describing refs */
3892 name_len = 0;
3893 for(i=0;i<*number_of_UNC_in_array;i++) {
3894 /* make sure that DfsPathOffset not past end */
3895 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3896 if (offset > data_count) {
3897 /* if invalid referral, stop here and do
3898 not try to copy any more */
3899 *number_of_UNC_in_array = i;
3900 break;
3901 }
3902 temp = ((char *)referrals) + offset;
3903
3904 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3905 name_len += UniStrnlen((wchar_t *)temp,data_count);
3906 } else {
3907 name_len += strnlen(temp,data_count);
3908 }
3909 referrals++;
3910 /* BB add check that referral pointer does not fall off end PDU */
3911
3912 }
3913 /* BB add check for name_len bigger than bcc */
3914 *targetUNCs =
3915 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00003916 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 rc = -ENOMEM;
3918 goto GetDFSRefExit;
3919 }
3920 /* copy the ref strings */
3921 referrals =
3922 (struct dfs_referral_level_3 *)
3923 (8 /* sizeof data hdr */ +
3924 data_offset +
3925 (char *) &pSMBr->hdr.Protocol);
3926
3927 for(i=0;i<*number_of_UNC_in_array;i++) {
3928 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3929 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3930 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003931 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 } else {
3933 strncpy(*targetUNCs,temp,name_len);
3934 }
3935 /* BB update target_uncs pointers */
3936 referrals++;
3937 }
3938 temp = *targetUNCs;
3939 temp[name_len] = 0;
3940 }
3941
3942 }
3943GetDFSRefExit:
3944 if (pSMB)
3945 cifs_buf_release(pSMB);
3946
3947 if (rc == -EAGAIN)
3948 goto getDFSRetry;
3949
3950 return rc;
3951}
3952
Steve French20962432005-09-21 22:05:57 -07003953/* Query File System Info such as free space to old servers such as Win 9x */
3954int
3955SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3956{
3957/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3958 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3959 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3960 FILE_SYSTEM_ALLOC_INFO *response_data;
3961 int rc = 0;
3962 int bytes_returned = 0;
3963 __u16 params, byte_count;
3964
3965 cFYI(1, ("OldQFSInfo"));
3966oldQFSInfoRetry:
3967 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3968 (void **) &pSMBr);
3969 if (rc)
3970 return rc;
3971 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3972 (void **) &pSMBr);
3973 if (rc)
3974 return rc;
3975
3976 params = 2; /* level */
3977 pSMB->TotalDataCount = 0;
3978 pSMB->MaxParameterCount = cpu_to_le16(2);
3979 pSMB->MaxDataCount = cpu_to_le16(1000);
3980 pSMB->MaxSetupCount = 0;
3981 pSMB->Reserved = 0;
3982 pSMB->Flags = 0;
3983 pSMB->Timeout = 0;
3984 pSMB->Reserved2 = 0;
3985 byte_count = params + 1 /* pad */ ;
3986 pSMB->TotalParameterCount = cpu_to_le16(params);
3987 pSMB->ParameterCount = pSMB->TotalParameterCount;
3988 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3989 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3990 pSMB->DataCount = 0;
3991 pSMB->DataOffset = 0;
3992 pSMB->SetupCount = 1;
3993 pSMB->Reserved3 = 0;
3994 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3995 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3996 pSMB->hdr.smb_buf_length += byte_count;
3997 pSMB->ByteCount = cpu_to_le16(byte_count);
3998
3999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4001 if (rc) {
4002 cFYI(1, ("Send error in QFSInfo = %d", rc));
4003 } else { /* decode response */
4004 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4005
4006 if (rc || (pSMBr->ByteCount < 18))
4007 rc = -EIO; /* bad smb */
4008 else {
4009 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4010 cFYI(1,("qfsinf resp BCC: %d Offset %d",
4011 pSMBr->ByteCount, data_offset));
4012
4013 response_data =
4014 (FILE_SYSTEM_ALLOC_INFO *)
4015 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4016 FSData->f_bsize =
4017 le16_to_cpu(response_data->BytesPerSector) *
4018 le32_to_cpu(response_data->
4019 SectorsPerAllocationUnit);
4020 FSData->f_blocks =
4021 le32_to_cpu(response_data->TotalAllocationUnits);
4022 FSData->f_bfree = FSData->f_bavail =
4023 le32_to_cpu(response_data->FreeAllocationUnits);
4024 cFYI(1,
4025 ("Blocks: %lld Free: %lld Block size %ld",
4026 (unsigned long long)FSData->f_blocks,
4027 (unsigned long long)FSData->f_bfree,
4028 FSData->f_bsize));
4029 }
4030 }
4031 cifs_buf_release(pSMB);
4032
4033 if (rc == -EAGAIN)
4034 goto oldQFSInfoRetry;
4035
4036 return rc;
4037}
4038
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039int
Steve French737b7582005-04-28 22:41:06 -07004040CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041{
4042/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4043 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4044 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4045 FILE_SYSTEM_INFO *response_data;
4046 int rc = 0;
4047 int bytes_returned = 0;
4048 __u16 params, byte_count;
4049
4050 cFYI(1, ("In QFSInfo"));
4051QFSInfoRetry:
4052 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4053 (void **) &pSMBr);
4054 if (rc)
4055 return rc;
4056
4057 params = 2; /* level */
4058 pSMB->TotalDataCount = 0;
4059 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004060 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 pSMB->MaxSetupCount = 0;
4062 pSMB->Reserved = 0;
4063 pSMB->Flags = 0;
4064 pSMB->Timeout = 0;
4065 pSMB->Reserved2 = 0;
4066 byte_count = params + 1 /* pad */ ;
4067 pSMB->TotalParameterCount = cpu_to_le16(params);
4068 pSMB->ParameterCount = pSMB->TotalParameterCount;
4069 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4070 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4071 pSMB->DataCount = 0;
4072 pSMB->DataOffset = 0;
4073 pSMB->SetupCount = 1;
4074 pSMB->Reserved3 = 0;
4075 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4076 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4077 pSMB->hdr.smb_buf_length += byte_count;
4078 pSMB->ByteCount = cpu_to_le16(byte_count);
4079
4080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4081 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4082 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004083 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 } else { /* decode response */
4085 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4086
Steve French20962432005-09-21 22:05:57 -07004087 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 rc = -EIO; /* bad smb */
4089 else {
4090 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
4092 response_data =
4093 (FILE_SYSTEM_INFO
4094 *) (((char *) &pSMBr->hdr.Protocol) +
4095 data_offset);
4096 FSData->f_bsize =
4097 le32_to_cpu(response_data->BytesPerSector) *
4098 le32_to_cpu(response_data->
4099 SectorsPerAllocationUnit);
4100 FSData->f_blocks =
4101 le64_to_cpu(response_data->TotalAllocationUnits);
4102 FSData->f_bfree = FSData->f_bavail =
4103 le64_to_cpu(response_data->FreeAllocationUnits);
4104 cFYI(1,
4105 ("Blocks: %lld Free: %lld Block size %ld",
4106 (unsigned long long)FSData->f_blocks,
4107 (unsigned long long)FSData->f_bfree,
4108 FSData->f_bsize));
4109 }
4110 }
4111 cifs_buf_release(pSMB);
4112
4113 if (rc == -EAGAIN)
4114 goto QFSInfoRetry;
4115
4116 return rc;
4117}
4118
4119int
Steve French737b7582005-04-28 22:41:06 -07004120CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121{
4122/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4123 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4124 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4125 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4126 int rc = 0;
4127 int bytes_returned = 0;
4128 __u16 params, byte_count;
4129
4130 cFYI(1, ("In QFSAttributeInfo"));
4131QFSAttributeRetry:
4132 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4133 (void **) &pSMBr);
4134 if (rc)
4135 return rc;
4136
4137 params = 2; /* level */
4138 pSMB->TotalDataCount = 0;
4139 pSMB->MaxParameterCount = cpu_to_le16(2);
4140 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4141 pSMB->MaxSetupCount = 0;
4142 pSMB->Reserved = 0;
4143 pSMB->Flags = 0;
4144 pSMB->Timeout = 0;
4145 pSMB->Reserved2 = 0;
4146 byte_count = params + 1 /* pad */ ;
4147 pSMB->TotalParameterCount = cpu_to_le16(params);
4148 pSMB->ParameterCount = pSMB->TotalParameterCount;
4149 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4150 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4151 pSMB->DataCount = 0;
4152 pSMB->DataOffset = 0;
4153 pSMB->SetupCount = 1;
4154 pSMB->Reserved3 = 0;
4155 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4156 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4157 pSMB->hdr.smb_buf_length += byte_count;
4158 pSMB->ByteCount = cpu_to_le16(byte_count);
4159
4160 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4161 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4162 if (rc) {
4163 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4164 } else { /* decode response */
4165 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4166
4167 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4168 rc = -EIO; /* bad smb */
4169 } else {
4170 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4171 response_data =
4172 (FILE_SYSTEM_ATTRIBUTE_INFO
4173 *) (((char *) &pSMBr->hdr.Protocol) +
4174 data_offset);
4175 memcpy(&tcon->fsAttrInfo, response_data,
4176 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4177 }
4178 }
4179 cifs_buf_release(pSMB);
4180
4181 if (rc == -EAGAIN)
4182 goto QFSAttributeRetry;
4183
4184 return rc;
4185}
4186
4187int
Steve French737b7582005-04-28 22:41:06 -07004188CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189{
4190/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4191 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4192 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4193 FILE_SYSTEM_DEVICE_INFO *response_data;
4194 int rc = 0;
4195 int bytes_returned = 0;
4196 __u16 params, byte_count;
4197
4198 cFYI(1, ("In QFSDeviceInfo"));
4199QFSDeviceRetry:
4200 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4201 (void **) &pSMBr);
4202 if (rc)
4203 return rc;
4204
4205 params = 2; /* level */
4206 pSMB->TotalDataCount = 0;
4207 pSMB->MaxParameterCount = cpu_to_le16(2);
4208 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4209 pSMB->MaxSetupCount = 0;
4210 pSMB->Reserved = 0;
4211 pSMB->Flags = 0;
4212 pSMB->Timeout = 0;
4213 pSMB->Reserved2 = 0;
4214 byte_count = params + 1 /* pad */ ;
4215 pSMB->TotalParameterCount = cpu_to_le16(params);
4216 pSMB->ParameterCount = pSMB->TotalParameterCount;
4217 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4218 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4219
4220 pSMB->DataCount = 0;
4221 pSMB->DataOffset = 0;
4222 pSMB->SetupCount = 1;
4223 pSMB->Reserved3 = 0;
4224 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4225 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4226 pSMB->hdr.smb_buf_length += byte_count;
4227 pSMB->ByteCount = cpu_to_le16(byte_count);
4228
4229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4231 if (rc) {
4232 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4233 } else { /* decode response */
4234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4235
4236 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4237 rc = -EIO; /* bad smb */
4238 else {
4239 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4240 response_data =
Steve French737b7582005-04-28 22:41:06 -07004241 (FILE_SYSTEM_DEVICE_INFO *)
4242 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 data_offset);
4244 memcpy(&tcon->fsDevInfo, response_data,
4245 sizeof (FILE_SYSTEM_DEVICE_INFO));
4246 }
4247 }
4248 cifs_buf_release(pSMB);
4249
4250 if (rc == -EAGAIN)
4251 goto QFSDeviceRetry;
4252
4253 return rc;
4254}
4255
4256int
Steve French737b7582005-04-28 22:41:06 -07004257CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258{
4259/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4260 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4261 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4262 FILE_SYSTEM_UNIX_INFO *response_data;
4263 int rc = 0;
4264 int bytes_returned = 0;
4265 __u16 params, byte_count;
4266
4267 cFYI(1, ("In QFSUnixInfo"));
4268QFSUnixRetry:
4269 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4270 (void **) &pSMBr);
4271 if (rc)
4272 return rc;
4273
4274 params = 2; /* level */
4275 pSMB->TotalDataCount = 0;
4276 pSMB->DataCount = 0;
4277 pSMB->DataOffset = 0;
4278 pSMB->MaxParameterCount = cpu_to_le16(2);
4279 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4280 pSMB->MaxSetupCount = 0;
4281 pSMB->Reserved = 0;
4282 pSMB->Flags = 0;
4283 pSMB->Timeout = 0;
4284 pSMB->Reserved2 = 0;
4285 byte_count = params + 1 /* pad */ ;
4286 pSMB->ParameterCount = cpu_to_le16(params);
4287 pSMB->TotalParameterCount = pSMB->ParameterCount;
4288 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4289 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4290 pSMB->SetupCount = 1;
4291 pSMB->Reserved3 = 0;
4292 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4293 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4294 pSMB->hdr.smb_buf_length += byte_count;
4295 pSMB->ByteCount = cpu_to_le16(byte_count);
4296
4297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4299 if (rc) {
4300 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4301 } else { /* decode response */
4302 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4303
4304 if (rc || (pSMBr->ByteCount < 13)) {
4305 rc = -EIO; /* bad smb */
4306 } else {
4307 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4308 response_data =
4309 (FILE_SYSTEM_UNIX_INFO
4310 *) (((char *) &pSMBr->hdr.Protocol) +
4311 data_offset);
4312 memcpy(&tcon->fsUnixInfo, response_data,
4313 sizeof (FILE_SYSTEM_UNIX_INFO));
4314 }
4315 }
4316 cifs_buf_release(pSMB);
4317
4318 if (rc == -EAGAIN)
4319 goto QFSUnixRetry;
4320
4321
4322 return rc;
4323}
4324
Jeremy Allisonac670552005-06-22 17:26:35 -07004325int
Steve French45abc6e2005-06-23 13:42:03 -05004326CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004327{
4328/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4329 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4330 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4331 int rc = 0;
4332 int bytes_returned = 0;
4333 __u16 params, param_offset, offset, byte_count;
4334
4335 cFYI(1, ("In SETFSUnixInfo"));
4336SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004337 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004338 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4339 (void **) &pSMBr);
4340 if (rc)
4341 return rc;
4342
4343 params = 4; /* 2 bytes zero followed by info level. */
4344 pSMB->MaxSetupCount = 0;
4345 pSMB->Reserved = 0;
4346 pSMB->Flags = 0;
4347 pSMB->Timeout = 0;
4348 pSMB->Reserved2 = 0;
4349 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4350 offset = param_offset + params;
4351
4352 pSMB->MaxParameterCount = cpu_to_le16(4);
4353 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4354 pSMB->SetupCount = 1;
4355 pSMB->Reserved3 = 0;
4356 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4357 byte_count = 1 /* pad */ + params + 12;
4358
4359 pSMB->DataCount = cpu_to_le16(12);
4360 pSMB->ParameterCount = cpu_to_le16(params);
4361 pSMB->TotalDataCount = pSMB->DataCount;
4362 pSMB->TotalParameterCount = pSMB->ParameterCount;
4363 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4364 pSMB->DataOffset = cpu_to_le16(offset);
4365
4366 /* Params. */
4367 pSMB->FileNum = 0;
4368 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4369
4370 /* Data. */
4371 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4372 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4373 pSMB->ClientUnixCap = cpu_to_le64(cap);
4374
4375 pSMB->hdr.smb_buf_length += byte_count;
4376 pSMB->ByteCount = cpu_to_le16(byte_count);
4377
4378 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4379 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4380 if (rc) {
4381 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4382 } else { /* decode response */
4383 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4384 if (rc) {
4385 rc = -EIO; /* bad smb */
4386 }
4387 }
4388 cifs_buf_release(pSMB);
4389
4390 if (rc == -EAGAIN)
4391 goto SETFSUnixRetry;
4392
4393 return rc;
4394}
4395
4396
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397
4398int
4399CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004400 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401{
4402/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4403 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4404 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4405 FILE_SYSTEM_POSIX_INFO *response_data;
4406 int rc = 0;
4407 int bytes_returned = 0;
4408 __u16 params, byte_count;
4409
4410 cFYI(1, ("In QFSPosixInfo"));
4411QFSPosixRetry:
4412 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4413 (void **) &pSMBr);
4414 if (rc)
4415 return rc;
4416
4417 params = 2; /* level */
4418 pSMB->TotalDataCount = 0;
4419 pSMB->DataCount = 0;
4420 pSMB->DataOffset = 0;
4421 pSMB->MaxParameterCount = cpu_to_le16(2);
4422 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4423 pSMB->MaxSetupCount = 0;
4424 pSMB->Reserved = 0;
4425 pSMB->Flags = 0;
4426 pSMB->Timeout = 0;
4427 pSMB->Reserved2 = 0;
4428 byte_count = params + 1 /* pad */ ;
4429 pSMB->ParameterCount = cpu_to_le16(params);
4430 pSMB->TotalParameterCount = pSMB->ParameterCount;
4431 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4432 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4433 pSMB->SetupCount = 1;
4434 pSMB->Reserved3 = 0;
4435 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4436 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4437 pSMB->hdr.smb_buf_length += byte_count;
4438 pSMB->ByteCount = cpu_to_le16(byte_count);
4439
4440 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4441 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4442 if (rc) {
4443 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4444 } else { /* decode response */
4445 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4446
4447 if (rc || (pSMBr->ByteCount < 13)) {
4448 rc = -EIO; /* bad smb */
4449 } else {
4450 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4451 response_data =
4452 (FILE_SYSTEM_POSIX_INFO
4453 *) (((char *) &pSMBr->hdr.Protocol) +
4454 data_offset);
4455 FSData->f_bsize =
4456 le32_to_cpu(response_data->BlockSize);
4457 FSData->f_blocks =
4458 le64_to_cpu(response_data->TotalBlocks);
4459 FSData->f_bfree =
4460 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004461 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 FSData->f_bavail = FSData->f_bfree;
4463 } else {
4464 FSData->f_bavail =
4465 le64_to_cpu(response_data->UserBlocksAvail);
4466 }
Steve French790fe572007-07-07 19:25:05 +00004467 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 FSData->f_files =
4469 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004470 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 FSData->f_ffree =
4472 le64_to_cpu(response_data->FreeFileNodes);
4473 }
4474 }
4475 cifs_buf_release(pSMB);
4476
4477 if (rc == -EAGAIN)
4478 goto QFSPosixRetry;
4479
4480 return rc;
4481}
4482
4483
4484/* We can not use write of zero bytes trick to
4485 set file size due to need for large file support. Also note that
4486 this SetPathInfo is preferred to SetFileInfo based method in next
4487 routine which is only needed to work around a sharing violation bug
4488 in Samba which this routine can run into */
4489
4490int
4491CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004492 __u64 size, int SetAllocation,
4493 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494{
4495 struct smb_com_transaction2_spi_req *pSMB = NULL;
4496 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4497 struct file_end_of_file_info *parm_data;
4498 int name_len;
4499 int rc = 0;
4500 int bytes_returned = 0;
4501 __u16 params, byte_count, data_count, param_offset, offset;
4502
4503 cFYI(1, ("In SetEOF"));
4504SetEOFRetry:
4505 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4506 (void **) &pSMBr);
4507 if (rc)
4508 return rc;
4509
4510 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4511 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004512 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004513 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 name_len++; /* trailing null */
4515 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004516 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 name_len = strnlen(fileName, PATH_MAX);
4518 name_len++; /* trailing null */
4519 strncpy(pSMB->FileName, fileName, name_len);
4520 }
4521 params = 6 + name_len;
4522 data_count = sizeof (struct file_end_of_file_info);
4523 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004524 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 pSMB->MaxSetupCount = 0;
4526 pSMB->Reserved = 0;
4527 pSMB->Flags = 0;
4528 pSMB->Timeout = 0;
4529 pSMB->Reserved2 = 0;
4530 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4531 InformationLevel) - 4;
4532 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004533 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4535 pSMB->InformationLevel =
4536 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4537 else
4538 pSMB->InformationLevel =
4539 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4540 } else /* Set File Size */ {
4541 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4542 pSMB->InformationLevel =
4543 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4544 else
4545 pSMB->InformationLevel =
4546 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4547 }
4548
4549 parm_data =
4550 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4551 offset);
4552 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4553 pSMB->DataOffset = cpu_to_le16(offset);
4554 pSMB->SetupCount = 1;
4555 pSMB->Reserved3 = 0;
4556 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4557 byte_count = 3 /* pad */ + params + data_count;
4558 pSMB->DataCount = cpu_to_le16(data_count);
4559 pSMB->TotalDataCount = pSMB->DataCount;
4560 pSMB->ParameterCount = cpu_to_le16(params);
4561 pSMB->TotalParameterCount = pSMB->ParameterCount;
4562 pSMB->Reserved4 = 0;
4563 pSMB->hdr.smb_buf_length += byte_count;
4564 parm_data->FileSize = cpu_to_le64(size);
4565 pSMB->ByteCount = cpu_to_le16(byte_count);
4566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4568 if (rc) {
4569 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4570 }
4571
4572 cifs_buf_release(pSMB);
4573
4574 if (rc == -EAGAIN)
4575 goto SetEOFRetry;
4576
4577 return rc;
4578}
4579
4580int
4581CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4582 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4583{
4584 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4585 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4586 char *data_offset;
4587 struct file_end_of_file_info *parm_data;
4588 int rc = 0;
4589 int bytes_returned = 0;
4590 __u16 params, param_offset, offset, byte_count, count;
4591
4592 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4593 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004594 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4595
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 if (rc)
4597 return rc;
4598
Steve Frenchcd634992005-04-28 22:41:10 -07004599 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4600
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4602 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4603
4604 params = 6;
4605 pSMB->MaxSetupCount = 0;
4606 pSMB->Reserved = 0;
4607 pSMB->Flags = 0;
4608 pSMB->Timeout = 0;
4609 pSMB->Reserved2 = 0;
4610 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4611 offset = param_offset + params;
4612
4613 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4614
4615 count = sizeof(struct file_end_of_file_info);
4616 pSMB->MaxParameterCount = cpu_to_le16(2);
4617 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4618 pSMB->SetupCount = 1;
4619 pSMB->Reserved3 = 0;
4620 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4621 byte_count = 3 /* pad */ + params + count;
4622 pSMB->DataCount = cpu_to_le16(count);
4623 pSMB->ParameterCount = cpu_to_le16(params);
4624 pSMB->TotalDataCount = pSMB->DataCount;
4625 pSMB->TotalParameterCount = pSMB->ParameterCount;
4626 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4627 parm_data =
4628 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4629 offset);
4630 pSMB->DataOffset = cpu_to_le16(offset);
4631 parm_data->FileSize = cpu_to_le64(size);
4632 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004633 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4635 pSMB->InformationLevel =
4636 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4637 else
4638 pSMB->InformationLevel =
4639 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4640 } else /* Set File Size */ {
4641 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4642 pSMB->InformationLevel =
4643 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4644 else
4645 pSMB->InformationLevel =
4646 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4647 }
4648 pSMB->Reserved4 = 0;
4649 pSMB->hdr.smb_buf_length += byte_count;
4650 pSMB->ByteCount = cpu_to_le16(byte_count);
4651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4653 if (rc) {
4654 cFYI(1,
4655 ("Send error in SetFileInfo (SetFileSize) = %d",
4656 rc));
4657 }
4658
4659 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004660 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661
4662 /* Note: On -EAGAIN error only caller can retry on handle based calls
4663 since file handle passed in no longer valid */
4664
4665 return rc;
4666}
4667
4668/* Some legacy servers such as NT4 require that the file times be set on
4669 an open handle, rather than by pathname - this is awkward due to
4670 potential access conflicts on the open, but it is unavoidable for these
4671 old servers since the only other choice is to go from 100 nanosecond DCE
4672 time and resort to the original setpathinfo level which takes the ancient
4673 DOS time format with 2 second granularity */
4674int
4675CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4676 __u16 fid)
4677{
4678 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4679 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4680 char *data_offset;
4681 int rc = 0;
4682 int bytes_returned = 0;
4683 __u16 params, param_offset, offset, byte_count, count;
4684
4685 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4687
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 if (rc)
4689 return rc;
4690
Steve Frenchcd634992005-04-28 22:41:10 -07004691 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4692
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 /* At this point there is no need to override the current pid
4694 with the pid of the opener, but that could change if we someday
4695 use an existing handle (rather than opening one on the fly) */
4696 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4697 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4698
4699 params = 6;
4700 pSMB->MaxSetupCount = 0;
4701 pSMB->Reserved = 0;
4702 pSMB->Flags = 0;
4703 pSMB->Timeout = 0;
4704 pSMB->Reserved2 = 0;
4705 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4706 offset = param_offset + params;
4707
4708 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4709
4710 count = sizeof (FILE_BASIC_INFO);
4711 pSMB->MaxParameterCount = cpu_to_le16(2);
4712 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4713 pSMB->SetupCount = 1;
4714 pSMB->Reserved3 = 0;
4715 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4716 byte_count = 3 /* pad */ + params + count;
4717 pSMB->DataCount = cpu_to_le16(count);
4718 pSMB->ParameterCount = cpu_to_le16(params);
4719 pSMB->TotalDataCount = pSMB->DataCount;
4720 pSMB->TotalParameterCount = pSMB->ParameterCount;
4721 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4722 pSMB->DataOffset = cpu_to_le16(offset);
4723 pSMB->Fid = fid;
4724 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4725 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4726 else
4727 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4728 pSMB->Reserved4 = 0;
4729 pSMB->hdr.smb_buf_length += byte_count;
4730 pSMB->ByteCount = cpu_to_le16(byte_count);
4731 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4732 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4733 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4734 if (rc) {
4735 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4736 }
4737
Steve Frenchcd634992005-04-28 22:41:10 -07004738 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739
4740 /* Note: On -EAGAIN error only caller can retry on handle based calls
4741 since file handle passed in no longer valid */
4742
4743 return rc;
4744}
4745
4746
4747int
4748CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4749 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004750 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751{
4752 TRANSACTION2_SPI_REQ *pSMB = NULL;
4753 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4754 int name_len;
4755 int rc = 0;
4756 int bytes_returned = 0;
4757 char *data_offset;
4758 __u16 params, param_offset, offset, byte_count, count;
4759
4760 cFYI(1, ("In SetTimes"));
4761
4762SetTimesRetry:
4763 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4764 (void **) &pSMBr);
4765 if (rc)
4766 return rc;
4767
4768 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4769 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004770 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004771 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 name_len++; /* trailing null */
4773 name_len *= 2;
4774 } else { /* BB improve the check for buffer overruns BB */
4775 name_len = strnlen(fileName, PATH_MAX);
4776 name_len++; /* trailing null */
4777 strncpy(pSMB->FileName, fileName, name_len);
4778 }
4779
4780 params = 6 + name_len;
4781 count = sizeof (FILE_BASIC_INFO);
4782 pSMB->MaxParameterCount = cpu_to_le16(2);
4783 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4784 pSMB->MaxSetupCount = 0;
4785 pSMB->Reserved = 0;
4786 pSMB->Flags = 0;
4787 pSMB->Timeout = 0;
4788 pSMB->Reserved2 = 0;
4789 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4790 InformationLevel) - 4;
4791 offset = param_offset + params;
4792 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4793 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4794 pSMB->DataOffset = cpu_to_le16(offset);
4795 pSMB->SetupCount = 1;
4796 pSMB->Reserved3 = 0;
4797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4798 byte_count = 3 /* pad */ + params + count;
4799
4800 pSMB->DataCount = cpu_to_le16(count);
4801 pSMB->ParameterCount = cpu_to_le16(params);
4802 pSMB->TotalDataCount = pSMB->DataCount;
4803 pSMB->TotalParameterCount = pSMB->ParameterCount;
4804 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4805 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4806 else
4807 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4808 pSMB->Reserved4 = 0;
4809 pSMB->hdr.smb_buf_length += byte_count;
4810 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4811 pSMB->ByteCount = cpu_to_le16(byte_count);
4812 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4813 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4814 if (rc) {
4815 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4816 }
4817
4818 cifs_buf_release(pSMB);
4819
4820 if (rc == -EAGAIN)
4821 goto SetTimesRetry;
4822
4823 return rc;
4824}
4825
4826/* Can not be used to set time stamps yet (due to old DOS time format) */
4827/* Can be used to set attributes */
4828#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4829 handling it anyway and NT4 was what we thought it would be needed for
4830 Do not delete it until we prove whether needed for Win9x though */
4831int
4832CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4833 __u16 dos_attrs, const struct nls_table *nls_codepage)
4834{
4835 SETATTR_REQ *pSMB = NULL;
4836 SETATTR_RSP *pSMBr = NULL;
4837 int rc = 0;
4838 int bytes_returned;
4839 int name_len;
4840
4841 cFYI(1, ("In SetAttrLegacy"));
4842
4843SetAttrLgcyRetry:
4844 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4845 (void **) &pSMBr);
4846 if (rc)
4847 return rc;
4848
4849 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4850 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004851 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 PATH_MAX, nls_codepage);
4853 name_len++; /* trailing null */
4854 name_len *= 2;
4855 } else { /* BB improve the check for buffer overruns BB */
4856 name_len = strnlen(fileName, PATH_MAX);
4857 name_len++; /* trailing null */
4858 strncpy(pSMB->fileName, fileName, name_len);
4859 }
4860 pSMB->attr = cpu_to_le16(dos_attrs);
4861 pSMB->BufferFormat = 0x04;
4862 pSMB->hdr.smb_buf_length += name_len + 1;
4863 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4866 if (rc) {
4867 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4868 }
4869
4870 cifs_buf_release(pSMB);
4871
4872 if (rc == -EAGAIN)
4873 goto SetAttrLgcyRetry;
4874
4875 return rc;
4876}
4877#endif /* temporarily unneeded SetAttr legacy function */
4878
4879int
4880CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004881 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4882 dev_t device, const struct nls_table *nls_codepage,
4883 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884{
4885 TRANSACTION2_SPI_REQ *pSMB = NULL;
4886 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4887 int name_len;
4888 int rc = 0;
4889 int bytes_returned = 0;
4890 FILE_UNIX_BASIC_INFO *data_offset;
4891 __u16 params, param_offset, offset, count, byte_count;
4892
4893 cFYI(1, ("In SetUID/GID/Mode"));
4894setPermsRetry:
4895 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4896 (void **) &pSMBr);
4897 if (rc)
4898 return rc;
4899
4900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4901 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004902 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004903 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 name_len++; /* trailing null */
4905 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004906 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 name_len = strnlen(fileName, PATH_MAX);
4908 name_len++; /* trailing null */
4909 strncpy(pSMB->FileName, fileName, name_len);
4910 }
4911
4912 params = 6 + name_len;
4913 count = sizeof (FILE_UNIX_BASIC_INFO);
4914 pSMB->MaxParameterCount = cpu_to_le16(2);
4915 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4916 pSMB->MaxSetupCount = 0;
4917 pSMB->Reserved = 0;
4918 pSMB->Flags = 0;
4919 pSMB->Timeout = 0;
4920 pSMB->Reserved2 = 0;
4921 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4922 InformationLevel) - 4;
4923 offset = param_offset + params;
4924 data_offset =
4925 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4926 offset);
4927 memset(data_offset, 0, count);
4928 pSMB->DataOffset = cpu_to_le16(offset);
4929 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4930 pSMB->SetupCount = 1;
4931 pSMB->Reserved3 = 0;
4932 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4933 byte_count = 3 /* pad */ + params + count;
4934 pSMB->ParameterCount = cpu_to_le16(params);
4935 pSMB->DataCount = cpu_to_le16(count);
4936 pSMB->TotalParameterCount = pSMB->ParameterCount;
4937 pSMB->TotalDataCount = pSMB->DataCount;
4938 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4939 pSMB->Reserved4 = 0;
4940 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00004941 /* Samba server ignores set of file size to zero due to bugs in some
4942 older clients, but we should be precise - we use SetFileSize to
4943 set file size and do not want to truncate file size to zero
4944 accidently as happened on one Samba server beta by putting
4945 zero instead of -1 here */
4946 data_offset->EndOfFile = NO_CHANGE_64;
4947 data_offset->NumOfBytes = NO_CHANGE_64;
4948 data_offset->LastStatusChange = NO_CHANGE_64;
4949 data_offset->LastAccessTime = NO_CHANGE_64;
4950 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 data_offset->Uid = cpu_to_le64(uid);
4952 data_offset->Gid = cpu_to_le64(gid);
4953 /* better to leave device as zero when it is */
4954 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4955 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4956 data_offset->Permissions = cpu_to_le64(mode);
4957
Steve French790fe572007-07-07 19:25:05 +00004958 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00004960 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00004962 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00004964 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00004966 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00004968 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00004970 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4972
4973
4974 pSMB->ByteCount = cpu_to_le16(byte_count);
4975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4977 if (rc) {
4978 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4979 }
4980
4981 if (pSMB)
4982 cifs_buf_release(pSMB);
4983 if (rc == -EAGAIN)
4984 goto setPermsRetry;
4985 return rc;
4986}
4987
4988int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004989 const int notify_subdirs, const __u16 netfid,
4990 __u32 filter, struct file * pfile, int multishot,
4991 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992{
4993 int rc = 0;
4994 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004995 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004996 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 int bytes_returned;
4998
4999 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
5000 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5001 (void **) &pSMBr);
5002 if (rc)
5003 return rc;
5004
5005 pSMB->TotalParameterCount = 0 ;
5006 pSMB->TotalDataCount = 0;
5007 pSMB->MaxParameterCount = cpu_to_le32(2);
5008 /* BB find exact data count max from sess structure BB */
5009 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005010/* BB VERIFY verify which is correct for above BB */
5011 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5012 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5013
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 pSMB->MaxSetupCount = 4;
5015 pSMB->Reserved = 0;
5016 pSMB->ParameterOffset = 0;
5017 pSMB->DataCount = 0;
5018 pSMB->DataOffset = 0;
5019 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5020 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5021 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005022 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5024 pSMB->Reserved2 = 0;
5025 pSMB->CompletionFilter = cpu_to_le32(filter);
5026 pSMB->Fid = netfid; /* file handle always le */
5027 pSMB->ByteCount = 0;
5028
5029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5030 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5031 if (rc) {
5032 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005033 } else {
5034 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07005035 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005036 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005037 sizeof(struct dir_notify_req),
5038 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005039 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005040 dnotify_req->Pid = pSMB->hdr.Pid;
5041 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5042 dnotify_req->Mid = pSMB->hdr.Mid;
5043 dnotify_req->Tid = pSMB->hdr.Tid;
5044 dnotify_req->Uid = pSMB->hdr.Uid;
5045 dnotify_req->netfid = netfid;
5046 dnotify_req->pfile = pfile;
5047 dnotify_req->filter = filter;
5048 dnotify_req->multishot = multishot;
5049 spin_lock(&GlobalMid_Lock);
5050 list_add_tail(&dnotify_req->lhead,
5051 &GlobalDnotifyReqList);
5052 spin_unlock(&GlobalMid_Lock);
5053 } else
5054 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 }
5056 cifs_buf_release(pSMB);
5057 return rc;
5058}
5059#ifdef CONFIG_CIFS_XATTR
5060ssize_t
5061CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5062 const unsigned char *searchName,
5063 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005064 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065{
5066 /* BB assumes one setup word */
5067 TRANSACTION2_QPI_REQ *pSMB = NULL;
5068 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5069 int rc = 0;
5070 int bytes_returned;
5071 int name_len;
5072 struct fea * temp_fea;
5073 char * temp_ptr;
5074 __u16 params, byte_count;
5075
5076 cFYI(1, ("In Query All EAs path %s", searchName));
5077QAllEAsRetry:
5078 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5079 (void **) &pSMBr);
5080 if (rc)
5081 return rc;
5082
5083 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5084 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005085 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005086 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 name_len++; /* trailing null */
5088 name_len *= 2;
5089 } else { /* BB improve the check for buffer overruns BB */
5090 name_len = strnlen(searchName, PATH_MAX);
5091 name_len++; /* trailing null */
5092 strncpy(pSMB->FileName, searchName, name_len);
5093 }
5094
5095 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5096 pSMB->TotalDataCount = 0;
5097 pSMB->MaxParameterCount = cpu_to_le16(2);
5098 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5099 pSMB->MaxSetupCount = 0;
5100 pSMB->Reserved = 0;
5101 pSMB->Flags = 0;
5102 pSMB->Timeout = 0;
5103 pSMB->Reserved2 = 0;
5104 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5105 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5106 pSMB->DataCount = 0;
5107 pSMB->DataOffset = 0;
5108 pSMB->SetupCount = 1;
5109 pSMB->Reserved3 = 0;
5110 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5111 byte_count = params + 1 /* pad */ ;
5112 pSMB->TotalParameterCount = cpu_to_le16(params);
5113 pSMB->ParameterCount = pSMB->TotalParameterCount;
5114 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5115 pSMB->Reserved4 = 0;
5116 pSMB->hdr.smb_buf_length += byte_count;
5117 pSMB->ByteCount = cpu_to_le16(byte_count);
5118
5119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5121 if (rc) {
5122 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5123 } else { /* decode response */
5124 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5125
5126 /* BB also check enough total bytes returned */
5127 /* BB we need to improve the validity checking
5128 of these trans2 responses */
5129 if (rc || (pSMBr->ByteCount < 4))
5130 rc = -EIO; /* bad smb */
5131 /* else if (pFindData){
5132 memcpy((char *) pFindData,
5133 (char *) &pSMBr->hdr.Protocol +
5134 data_offset, kl);
5135 }*/ else {
5136 /* check that length of list is not more than bcc */
5137 /* check that each entry does not go beyond length
5138 of list */
5139 /* check that each element of each entry does not
5140 go beyond end of list */
5141 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5142 struct fealist * ea_response_data;
5143 rc = 0;
5144 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005145 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 ea_response_data = (struct fealist *)
5147 (((char *) &pSMBr->hdr.Protocol) +
5148 data_offset);
5149 name_len = le32_to_cpu(ea_response_data->list_len);
5150 cFYI(1,("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005151 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 /* returned EA size zeroed at top of function */
5153 cFYI(1,("empty EA list returned from server"));
5154 } else {
5155 /* account for ea list len */
5156 name_len -= 4;
5157 temp_fea = ea_response_data->list;
5158 temp_ptr = (char *)temp_fea;
5159 while(name_len > 0) {
5160 __u16 value_len;
5161 name_len -= 4;
5162 temp_ptr += 4;
5163 rc += temp_fea->name_len;
5164 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005165 rc = rc + 5 + 1;
5166 if (rc < (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 memcpy(EAData,"user.",5);
5168 EAData+=5;
5169 memcpy(EAData,temp_ptr,temp_fea->name_len);
5170 EAData+=temp_fea->name_len;
5171 /* null terminate name */
5172 *EAData = 0;
5173 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005174 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 /* skip copy - calc size only */
5176 } else {
5177 /* stop before overrun buffer */
5178 rc = -ERANGE;
5179 break;
5180 }
5181 name_len -= temp_fea->name_len;
5182 temp_ptr += temp_fea->name_len;
5183 /* account for trailing null */
5184 name_len--;
5185 temp_ptr++;
5186 value_len = le16_to_cpu(temp_fea->value_len);
5187 name_len -= value_len;
5188 temp_ptr += value_len;
5189 /* BB check that temp_ptr is still within smb BB*/
5190 /* no trailing null to account for in value len */
5191 /* go on to next EA */
5192 temp_fea = (struct fea *)temp_ptr;
5193 }
5194 }
5195 }
5196 }
5197 if (pSMB)
5198 cifs_buf_release(pSMB);
5199 if (rc == -EAGAIN)
5200 goto QAllEAsRetry;
5201
5202 return (ssize_t)rc;
5203}
5204
5205ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5206 const unsigned char * searchName,const unsigned char * ea_name,
5207 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005208 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209{
5210 TRANSACTION2_QPI_REQ *pSMB = NULL;
5211 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5212 int rc = 0;
5213 int bytes_returned;
5214 int name_len;
5215 struct fea * temp_fea;
5216 char * temp_ptr;
5217 __u16 params, byte_count;
5218
5219 cFYI(1, ("In Query EA path %s", searchName));
5220QEARetry:
5221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5222 (void **) &pSMBr);
5223 if (rc)
5224 return rc;
5225
5226 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5227 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005228 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005229 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 name_len++; /* trailing null */
5231 name_len *= 2;
5232 } else { /* BB improve the check for buffer overruns BB */
5233 name_len = strnlen(searchName, PATH_MAX);
5234 name_len++; /* trailing null */
5235 strncpy(pSMB->FileName, searchName, name_len);
5236 }
5237
5238 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5239 pSMB->TotalDataCount = 0;
5240 pSMB->MaxParameterCount = cpu_to_le16(2);
5241 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5242 pSMB->MaxSetupCount = 0;
5243 pSMB->Reserved = 0;
5244 pSMB->Flags = 0;
5245 pSMB->Timeout = 0;
5246 pSMB->Reserved2 = 0;
5247 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5248 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5249 pSMB->DataCount = 0;
5250 pSMB->DataOffset = 0;
5251 pSMB->SetupCount = 1;
5252 pSMB->Reserved3 = 0;
5253 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5254 byte_count = params + 1 /* pad */ ;
5255 pSMB->TotalParameterCount = cpu_to_le16(params);
5256 pSMB->ParameterCount = pSMB->TotalParameterCount;
5257 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5258 pSMB->Reserved4 = 0;
5259 pSMB->hdr.smb_buf_length += byte_count;
5260 pSMB->ByteCount = cpu_to_le16(byte_count);
5261
5262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5264 if (rc) {
5265 cFYI(1, ("Send error in Query EA = %d", rc));
5266 } else { /* decode response */
5267 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5268
5269 /* BB also check enough total bytes returned */
5270 /* BB we need to improve the validity checking
5271 of these trans2 responses */
5272 if (rc || (pSMBr->ByteCount < 4))
5273 rc = -EIO; /* bad smb */
5274 /* else if (pFindData){
5275 memcpy((char *) pFindData,
5276 (char *) &pSMBr->hdr.Protocol +
5277 data_offset, kl);
5278 }*/ else {
5279 /* check that length of list is not more than bcc */
5280 /* check that each entry does not go beyond length
5281 of list */
5282 /* check that each element of each entry does not
5283 go beyond end of list */
5284 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5285 struct fealist * ea_response_data;
5286 rc = -ENODATA;
5287 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005288 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 ea_response_data = (struct fealist *)
5290 (((char *) &pSMBr->hdr.Protocol) +
5291 data_offset);
5292 name_len = le32_to_cpu(ea_response_data->list_len);
5293 cFYI(1,("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005294 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 /* returned EA size zeroed at top of function */
5296 cFYI(1,("empty EA list returned from server"));
5297 } else {
5298 /* account for ea list len */
5299 name_len -= 4;
5300 temp_fea = ea_response_data->list;
5301 temp_ptr = (char *)temp_fea;
5302 /* loop through checking if we have a matching
5303 name and then return the associated value */
5304 while(name_len > 0) {
5305 __u16 value_len;
5306 name_len -= 4;
5307 temp_ptr += 4;
5308 value_len = le16_to_cpu(temp_fea->value_len);
5309 /* BB validate that value_len falls within SMB,
5310 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005311 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 temp_fea->name_len) == 0) {
5313 /* found a match */
5314 rc = value_len;
5315 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005316 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 memcpy(ea_value,
5318 temp_fea->name+temp_fea->name_len+1,
5319 rc);
5320 /* ea values, unlike ea names,
5321 are not null terminated */
Steve French790fe572007-07-07 19:25:05 +00005322 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 /* skip copy - calc size only */
5324 } else {
5325 /* stop before overrun buffer */
5326 rc = -ERANGE;
5327 }
5328 break;
5329 }
5330 name_len -= temp_fea->name_len;
5331 temp_ptr += temp_fea->name_len;
5332 /* account for trailing null */
5333 name_len--;
5334 temp_ptr++;
5335 name_len -= value_len;
5336 temp_ptr += value_len;
5337 /* no trailing null to account for in value len */
5338 /* go on to next EA */
5339 temp_fea = (struct fea *)temp_ptr;
5340 }
5341 }
5342 }
5343 }
5344 if (pSMB)
5345 cifs_buf_release(pSMB);
5346 if (rc == -EAGAIN)
5347 goto QEARetry;
5348
5349 return (ssize_t)rc;
5350}
5351
5352int
5353CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5354 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005355 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5356 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357{
5358 struct smb_com_transaction2_spi_req *pSMB = NULL;
5359 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5360 struct fealist *parm_data;
5361 int name_len;
5362 int rc = 0;
5363 int bytes_returned = 0;
5364 __u16 params, param_offset, byte_count, offset, count;
5365
5366 cFYI(1, ("In SetEA"));
5367SetEARetry:
5368 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5369 (void **) &pSMBr);
5370 if (rc)
5371 return rc;
5372
5373 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5374 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005375 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005376 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 name_len++; /* trailing null */
5378 name_len *= 2;
5379 } else { /* BB improve the check for buffer overruns BB */
5380 name_len = strnlen(fileName, PATH_MAX);
5381 name_len++; /* trailing null */
5382 strncpy(pSMB->FileName, fileName, name_len);
5383 }
5384
5385 params = 6 + name_len;
5386
5387 /* done calculating parms using name_len of file name,
5388 now use name_len to calculate length of ea name
5389 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005390 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 name_len = 0;
5392 else
5393 name_len = strnlen(ea_name,255);
5394
5395 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5396 pSMB->MaxParameterCount = cpu_to_le16(2);
5397 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5398 pSMB->MaxSetupCount = 0;
5399 pSMB->Reserved = 0;
5400 pSMB->Flags = 0;
5401 pSMB->Timeout = 0;
5402 pSMB->Reserved2 = 0;
5403 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5404 InformationLevel) - 4;
5405 offset = param_offset + params;
5406 pSMB->InformationLevel =
5407 cpu_to_le16(SMB_SET_FILE_EA);
5408
5409 parm_data =
5410 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5411 offset);
5412 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5413 pSMB->DataOffset = cpu_to_le16(offset);
5414 pSMB->SetupCount = 1;
5415 pSMB->Reserved3 = 0;
5416 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5417 byte_count = 3 /* pad */ + params + count;
5418 pSMB->DataCount = cpu_to_le16(count);
5419 parm_data->list_len = cpu_to_le32(count);
5420 parm_data->list[0].EA_flags = 0;
5421 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005422 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005424 if (ea_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 strncpy(parm_data->list[0].name,ea_name,name_len);
5426 parm_data->list[0].name[name_len] = 0;
5427 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5428 /* caller ensures that ea_value_len is less than 64K but
5429 we need to ensure that it fits within the smb */
5430
5431 /*BB add length check that it would fit in negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005432 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5433 if (ea_value_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5435
5436 pSMB->TotalDataCount = pSMB->DataCount;
5437 pSMB->ParameterCount = cpu_to_le16(params);
5438 pSMB->TotalParameterCount = pSMB->ParameterCount;
5439 pSMB->Reserved4 = 0;
5440 pSMB->hdr.smb_buf_length += byte_count;
5441 pSMB->ByteCount = cpu_to_le16(byte_count);
5442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5444 if (rc) {
5445 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5446 }
5447
5448 cifs_buf_release(pSMB);
5449
5450 if (rc == -EAGAIN)
5451 goto SetEARetry;
5452
5453 return rc;
5454}
5455
5456#endif