blob: b339f5f128daec487f7e2ac57af75ae3cc8b1fb2 [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 */
Steve French50c2f752007-07-13 00:33:32 +000051 {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 French50c2f752007-07-13 00:33:32 +0000122 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800123 (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 French50c2f752007-07-13 00:33:32 +0000130 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000132 /* 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)) {
Steve French50c2f752007-07-13 00:33:32 +0000142 cFYI(1, ("gave up waiting on "
143 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700145 } /* else "hard" mount - keep retrying
146 until process is killed or server
147 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 } else /* TCP session is reestablished now */
149 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 }
Steve French50c2f752007-07-13 00:33:32 +0000151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 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 French50c2f752007-07-13 00:33:32 +0000157 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700158 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 French50c2f752007-07-13 00:33:32 +0000161 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000162 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 */,
Steve French50c2f752007-07-13 00:33:32 +0000167 tcon,
Steve French8af18972007-02-14 04:42:51 +0000168 NULL /* we do not know sb */,
Steve French50c2f752007-07-13 00:33:32 +0000169 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));
Steve French50c2f752007-07-13 00:33:32 +0000177 /* Removed call to reopen open files here.
178 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700179 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Steve French50c2f752007-07-13 00:33:32 +0000181 /* 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 */
Steve French50c2f752007-07-13 00:33:32 +0000184 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 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 French50c2f752007-07-13 00:33:32 +0000221small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000222 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000223{
224 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000225 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000226
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
Steve French50c2f752007-07-13 00:33:32 +0000240 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000241 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 French50c2f752007-07-13 00:33:32 +0000272 (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)) {
Steve French50c2f752007-07-13 00:33:32 +0000285 cFYI(1, ("gave up waiting on "
286 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700288 } /* else "hard" mount - keep retrying
289 until process is killed or server
290 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 } else /* TCP session is reestablished now */
292 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 nls_codepage = load_nls_default();
295 /* need to prevent multiple threads trying to
296 simultaneously reconnect the same SMB session */
297 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000298 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000299 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700300 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000301 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700303 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
304 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000306 /* tell server which Unix caps we support */
307 if (tcon->ses->capabilities & CAP_UNIX)
308 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000309 tcon,
Steve French8af18972007-02-14 04:42:51 +0000310 NULL /* do not know sb */,
311 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700312 /* BB FIXME add code to check if wsize needs
313 update due to negotiated smb buffer size
314 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000315 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 atomic_inc(&tconInfoReconnectCount);
317
318 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000319 /* Removed call to reopen open files here.
320 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700321 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Steve French50c2f752007-07-13 00:33:32 +0000323 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700324 know whether we can continue or not without
325 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000326 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 case SMB_COM_READ_ANDX:
328 case SMB_COM_WRITE_ANDX:
329 case SMB_COM_CLOSE:
330 case SMB_COM_FIND_CLOSE2:
331 case SMB_COM_LOCKING_ANDX: {
332 unload_nls(nls_codepage);
333 return -EAGAIN;
334 }
335 }
336 } else {
337 up(&tcon->ses->sesSem);
338 }
339 unload_nls(nls_codepage);
340
341 } else {
342 return -EIO;
343 }
344 }
Steve French790fe572007-07-07 19:25:05 +0000345 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 return rc;
347
348 *request_buf = cifs_buf_get();
349 if (*request_buf == NULL) {
350 /* BB should we add a retry in here if not a writepage? */
351 return -ENOMEM;
352 }
353 /* Although the original thought was we needed the response buf for */
354 /* potential retries of smb operations it turns out we can determine */
355 /* from the mid flags when the request buffer can be resent without */
356 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000357 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000358 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
361 wct /*wct */ );
362
Steve French790fe572007-07-07 19:25:05 +0000363 if (tcon != NULL)
364 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 return rc;
367}
368
Steve French50c2f752007-07-13 00:33:32 +0000369static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370{
371 int rc = -EINVAL;
372 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000373 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 /* check for plausible wct, bcc and t2 data and parm sizes */
376 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000377 if (pSMB->hdr.WordCount >= 10) {
378 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
380 /* check that bcc is at least as big as parms + data */
381 /* check that bcc is less than negotiated smb buffer */
382 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000383 if (total_size < 512) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
385 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000386 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700387 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000389 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000390 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
392 return 0;
393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
395 }
396 }
Steve French50c2f752007-07-13 00:33:32 +0000397 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 sizeof(struct smb_t2_rsp) + 16);
399 return rc;
400}
401int
402CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
403{
404 NEGOTIATE_REQ *pSMB;
405 NEGOTIATE_RSP *pSMBr;
406 int rc = 0;
407 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000408 int i;
Steve French50c2f752007-07-13 00:33:32 +0000409 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000411 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100412 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Steve French790fe572007-07-07 19:25:05 +0000414 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 server = ses->server;
416 else {
417 rc = -EIO;
418 return rc;
419 }
420 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
421 (void **) &pSMB, (void **) &pSMBr);
422 if (rc)
423 return rc;
Steve French750d1152006-06-27 06:28:30 +0000424
425 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000426 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000427 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000428 else /* if override flags set only sign/seal OR them with global auth */
429 secFlags = extended_security | ses->overrideSecFlg;
430
Steve French762e5ab2007-06-28 18:41:42 +0000431 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000432
Steve French1982c342005-08-17 12:38:22 -0700433 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000434 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
435 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000436 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French50c2f752007-07-13 00:33:32 +0000437
Steve French39798772006-05-31 22:40:51 +0000438 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000439 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000440 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
441 count += strlen(protocols[i].name) + 1;
442 /* null at end of source and target buffers anyway */
443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 pSMB->hdr.smb_buf_length += count;
445 pSMB->ByteCount = cpu_to_le16(count);
446
447 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000449 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000450 goto neg_err_exit;
451
Al Viro733f99a2006-10-14 16:48:26 +0100452 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000453 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000454 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000455 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000456 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000457 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000458 could not negotiate a common dialect */
459 rc = -EOPNOTSUPP;
460 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000461#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000462 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100463 && ((dialect == LANMAN_PROT)
464 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000465 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000466 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000467
Steve French790fe572007-07-07 19:25:05 +0000468 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000469 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000470 server->secType = LANMAN;
471 else {
472 cERROR(1, ("mount failed weak security disabled"
473 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000474 rc = -EOPNOTSUPP;
475 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000476 }
Steve French254e55e2006-06-04 05:53:15 +0000477 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
478 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
479 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000480 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000481 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
482 /* even though we do not use raw we might as well set this
483 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000484 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000485 server->maxRw = 0xFF00;
486 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
487 } else {
488 server->maxRw = 0;/* we do not need to use raw anyway */
489 server->capabilities = CAP_MPX_MODE;
490 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000491 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000492 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000493 /* OS/2 often does not set timezone therefore
494 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000495 * Could deviate slightly from the right zone.
496 * Smallest defined timezone difference is 15 minutes
497 * (i.e. Nepal). Rounding up/down is done to match
498 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000499 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000500 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000501 struct timespec ts, utc;
502 utc = CURRENT_TIME;
503 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
504 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000505 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
506 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000507 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000508 val = (int)(utc.tv_sec - ts.tv_sec);
509 seconds = val < 0 ? -val : val;
Steve French947a5062006-10-02 05:55:25 +0000510 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000511 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000512 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000513 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000514 if (val < 0)
Steve Frenchb815f1e2006-10-02 05:53:29 +0000515 result = - result;
516 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000517 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000518 server->timeAdj = (int)tmp;
519 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000520 }
Steve French790fe572007-07-07 19:25:05 +0000521 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000522
Steve French39798772006-05-31 22:40:51 +0000523
Steve French254e55e2006-06-04 05:53:15 +0000524 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000525 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000526
Steve French50c2f752007-07-13 00:33:32 +0000527 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000528 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000529 memcpy(server->cryptKey, rsp->EncryptionKey,
530 CIFS_CRYPTO_KEY_SIZE);
531 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
532 rc = -EIO; /* need cryptkey unless plain text */
533 goto neg_err_exit;
534 }
Steve French39798772006-05-31 22:40:51 +0000535
Steve French790fe572007-07-07 19:25:05 +0000536 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000537 /* we will not end up setting signing flags - as no signing
538 was in LANMAN and server did not return the flags on */
539 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000540#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000541 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000542 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000543 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000544 rc = -EOPNOTSUPP;
545#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000546 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000547 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000548 /* unknown wct */
549 rc = -EOPNOTSUPP;
550 goto neg_err_exit;
551 }
552 /* else wct == 17 NTLM */
553 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000554 if ((server->secMode & SECMODE_USER) == 0)
555 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000556
Steve French790fe572007-07-07 19:25:05 +0000557 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000558#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000559 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000560#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000561 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000562 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000563
Steve French790fe572007-07-07 19:25:05 +0000564 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000565 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000566 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000567 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000568 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000569 server->secType = NTLMv2;
570 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000571
Steve French254e55e2006-06-04 05:53:15 +0000572 /* one byte, so no need to convert this or EncryptionKeyLen from
573 little endian */
574 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
575 /* probably no need to store and check maxvcs */
576 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000578 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
579 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
580 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
581 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000582 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
583 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000584 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
585 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
586 CIFS_CRYPTO_KEY_SIZE);
587 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
588 && (pSMBr->EncryptionKeyLength == 0)) {
589 /* decode security blob */
590 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
591 rc = -EIO; /* no crypt key only if plain text pwd */
592 goto neg_err_exit;
593 }
594
595 /* BB might be helpful to save off the domain of server here */
596
Steve French50c2f752007-07-13 00:33:32 +0000597 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000598 (server->capabilities & CAP_EXTENDED_SECURITY)) {
599 count = pSMBr->ByteCount;
600 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000602 else if (count == 16) {
603 server->secType = RawNTLMSSP;
604 if (server->socketUseCount.counter > 1) {
605 if (memcmp(server->server_GUID,
606 pSMBr->u.extended_response.
607 GUID, 16) != 0) {
608 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000610 pSMBr->u.extended_response.GUID,
611 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 }
Steve French254e55e2006-06-04 05:53:15 +0000613 } else
614 memcpy(server->server_GUID,
615 pSMBr->u.extended_response.GUID, 16);
616 } else {
617 rc = decode_negTokenInit(pSMBr->u.extended_response.
618 SecurityBlob,
619 count - 16,
620 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000621 if (rc == 1) {
Steve French254e55e2006-06-04 05:53:15 +0000622 /* BB Need to fill struct for sessetup here */
623 rc = -EOPNOTSUPP;
624 } else {
625 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
Steve French254e55e2006-06-04 05:53:15 +0000628 } else
629 server->capabilities &= ~CAP_EXTENDED_SECURITY;
630
Steve French6344a422006-06-12 04:18:35 +0000631#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000632signing_check:
Steve French6344a422006-06-12 04:18:35 +0000633#endif
Steve French762e5ab2007-06-28 18:41:42 +0000634 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
635 /* MUST_SIGN already includes the MAY_SIGN FLAG
636 so if this is zero it means that signing is disabled */
637 cFYI(1, ("Signing disabled"));
Steve French790fe572007-07-07 19:25:05 +0000638 if (server->secMode & SECMODE_SIGN_REQUIRED)
Steve French762e5ab2007-06-28 18:41:42 +0000639 cERROR(1, ("Server requires "
640 "/proc/fs/cifs/PacketSigningEnabled "
641 "to be on"));
Steve French50c2f752007-07-13 00:33:32 +0000642 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000643 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000644 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
645 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000646 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000647 if ((server->secMode &
648 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
649 cERROR(1,
650 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000651 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000652 } else
653 server->secMode |= SECMODE_SIGN_REQUIRED;
654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000656 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000657 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Steve French50c2f752007-07-13 00:33:32 +0000660
661neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700662 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000663
Steve French790fe572007-07-07 19:25:05 +0000664 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return rc;
666}
667
668int
669CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
670{
671 struct smb_hdr *smb_buffer;
672 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
673 int rc = 0;
674 int length;
675
676 cFYI(1, ("In tree disconnect"));
677 /*
678 * If last user of the connection and
679 * connection alive - disconnect it
680 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000681 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 * to be freed and kernel thread woken up).
683 */
684 if (tcon)
685 down(&tcon->tconSem);
686 else
687 return -EIO;
688
689 atomic_dec(&tcon->useCount);
690 if (atomic_read(&tcon->useCount) > 0) {
691 up(&tcon->tconSem);
692 return -EBUSY;
693 }
694
Steve French50c2f752007-07-13 00:33:32 +0000695 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000697 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000699 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 }
701
Steve French790fe572007-07-07 19:25:05 +0000702 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 up(&tcon->tconSem);
704 return -EIO;
705 }
Steve French50c2f752007-07-13 00:33:32 +0000706 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700707 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 if (rc) {
709 up(&tcon->tconSem);
710 return rc;
711 } else {
712 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
715 &length, 0);
716 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700717 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 if (smb_buffer)
720 cifs_small_buf_release(smb_buffer);
721 up(&tcon->tconSem);
722
Steve French50c2f752007-07-13 00:33:32 +0000723 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 closed on server already e.g. due to tcp session crashing */
725 if (rc == -EAGAIN)
726 rc = 0;
727
728 return rc;
729}
730
731int
732CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
733{
734 struct smb_hdr *smb_buffer_response;
735 LOGOFF_ANDX_REQ *pSMB;
736 int rc = 0;
737 int length;
738
739 cFYI(1, ("In SMBLogoff for session disconnect"));
740 if (ses)
741 down(&ses->sesSem);
742 else
743 return -EIO;
744
745 atomic_dec(&ses->inUse);
746 if (atomic_read(&ses->inUse) > 0) {
747 up(&ses->sesSem);
748 return -EBUSY;
749 }
750 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
751 if (rc) {
752 up(&ses->sesSem);
753 return rc;
754 }
755
756 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000757
Steve French790fe572007-07-07 19:25:05 +0000758 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700759 pSMB->hdr.Mid = GetNextMid(ses->server);
760
Steve French790fe572007-07-07 19:25:05 +0000761 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
763 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
764 }
765
766 pSMB->hdr.Uid = ses->Suid;
767
768 pSMB->AndXCommand = 0xFF;
769 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
770 smb_buffer_response, &length, 0);
771 if (ses->server) {
772 atomic_dec(&ses->server->socketUseCount);
773 if (atomic_read(&ses->server->socketUseCount) == 0) {
774 spin_lock(&GlobalMid_Lock);
775 ses->server->tcpStatus = CifsExiting;
776 spin_unlock(&GlobalMid_Lock);
777 rc = -ESHUTDOWN;
778 }
779 }
Steve Frencha59c6582005-08-17 12:12:19 -0700780 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700781 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000784 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 error */
786 if (rc == -EAGAIN)
787 rc = 0;
788 return rc;
789}
790
791int
Steve French2d785a52007-07-15 01:48:57 +0000792CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
793 __u16 type, const struct nls_table *nls_codepage, int remap)
794{
795 TRANSACTION2_SPI_REQ *pSMB = NULL;
796 TRANSACTION2_SPI_RSP *pSMBr = NULL;
797 struct unlink_psx_rq *pRqD;
798 int name_len;
799 int rc = 0;
800 int bytes_returned = 0;
801 __u16 params, param_offset, offset, byte_count;
802
803 cFYI(1, ("In POSIX delete"));
804PsxDelete:
805 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
806 (void **) &pSMBr);
807 if (rc)
808 return rc;
809
810 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
811 name_len =
812 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
813 PATH_MAX, nls_codepage, remap);
814 name_len++; /* trailing null */
815 name_len *= 2;
816 } else { /* BB add path length overrun check */
817 name_len = strnlen(fileName, PATH_MAX);
818 name_len++; /* trailing null */
819 strncpy(pSMB->FileName, fileName, name_len);
820 }
821
822 params = 6 + name_len;
823 pSMB->MaxParameterCount = cpu_to_le16(2);
824 pSMB->MaxDataCount = 0; /* BB double check this with jra */
825 pSMB->MaxSetupCount = 0;
826 pSMB->Reserved = 0;
827 pSMB->Flags = 0;
828 pSMB->Timeout = 0;
829 pSMB->Reserved2 = 0;
830 param_offset = offsetof(struct smb_com_transaction2_spi_req,
831 InformationLevel) - 4;
832 offset = param_offset + params;
833
834 /* Setup pointer to Request Data (inode type) */
835 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
836 pRqD->type = cpu_to_le16(type);
837 pSMB->ParameterOffset = cpu_to_le16(param_offset);
838 pSMB->DataOffset = cpu_to_le16(offset);
839 pSMB->SetupCount = 1;
840 pSMB->Reserved3 = 0;
841 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
842 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
843
844 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
845 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
846 pSMB->ParameterCount = cpu_to_le16(params);
847 pSMB->TotalParameterCount = pSMB->ParameterCount;
848 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
849 pSMB->Reserved4 = 0;
850 pSMB->hdr.smb_buf_length += byte_count;
851 pSMB->ByteCount = cpu_to_le16(byte_count);
852 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
853 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
854 if (rc) {
855 cFYI(1, ("Posix delete returned %d", rc));
856 }
857 cifs_buf_release(pSMB);
858
859 cifs_stats_inc(&tcon->num_deletes);
860
861 if (rc == -EAGAIN)
862 goto PsxDelete;
863
864 return rc;
865}
866
867int
Steve French737b7582005-04-28 22:41:06 -0700868CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
869 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
871 DELETE_FILE_REQ *pSMB = NULL;
872 DELETE_FILE_RSP *pSMBr = NULL;
873 int rc = 0;
874 int bytes_returned;
875 int name_len;
876
877DelFileRetry:
878 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
879 (void **) &pSMBr);
880 if (rc)
881 return rc;
882
883 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
884 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000885 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700886 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 name_len++; /* trailing null */
888 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700889 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 name_len = strnlen(fileName, PATH_MAX);
891 name_len++; /* trailing null */
892 strncpy(pSMB->fileName, fileName, name_len);
893 }
894 pSMB->SearchAttributes =
895 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
896 pSMB->BufferFormat = 0x04;
897 pSMB->hdr.smb_buf_length += name_len + 1;
898 pSMB->ByteCount = cpu_to_le16(name_len + 1);
899 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
900 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700901 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 if (rc) {
903 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 cifs_buf_release(pSMB);
907 if (rc == -EAGAIN)
908 goto DelFileRetry;
909
910 return rc;
911}
912
913int
Steve French50c2f752007-07-13 00:33:32 +0000914CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700915 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
917 DELETE_DIRECTORY_REQ *pSMB = NULL;
918 DELETE_DIRECTORY_RSP *pSMBr = NULL;
919 int rc = 0;
920 int bytes_returned;
921 int name_len;
922
923 cFYI(1, ("In CIFSSMBRmDir"));
924RmDirRetry:
925 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
926 (void **) &pSMBr);
927 if (rc)
928 return rc;
929
930 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700931 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
932 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 name_len++; /* trailing null */
934 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700935 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 name_len = strnlen(dirName, PATH_MAX);
937 name_len++; /* trailing null */
938 strncpy(pSMB->DirName, dirName, name_len);
939 }
940
941 pSMB->BufferFormat = 0x04;
942 pSMB->hdr.smb_buf_length += name_len + 1;
943 pSMB->ByteCount = cpu_to_le16(name_len + 1);
944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700946 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 if (rc) {
948 cFYI(1, ("Error in RMDir = %d", rc));
949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 cifs_buf_release(pSMB);
952 if (rc == -EAGAIN)
953 goto RmDirRetry;
954 return rc;
955}
956
957int
958CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700959 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960{
961 int rc = 0;
962 CREATE_DIRECTORY_REQ *pSMB = NULL;
963 CREATE_DIRECTORY_RSP *pSMBr = NULL;
964 int bytes_returned;
965 int name_len;
966
967 cFYI(1, ("In CIFSSMBMkDir"));
968MkDirRetry:
969 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
970 (void **) &pSMBr);
971 if (rc)
972 return rc;
973
974 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000975 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700976 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 name_len++; /* trailing null */
978 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700979 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 name_len = strnlen(name, PATH_MAX);
981 name_len++; /* trailing null */
982 strncpy(pSMB->DirName, name, name_len);
983 }
984
985 pSMB->BufferFormat = 0x04;
986 pSMB->hdr.smb_buf_length += name_len + 1;
987 pSMB->ByteCount = cpu_to_le16(name_len + 1);
988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700990 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (rc) {
992 cFYI(1, ("Error in Mkdir = %d", rc));
993 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700994
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 cifs_buf_release(pSMB);
996 if (rc == -EAGAIN)
997 goto MkDirRetry;
998 return rc;
999}
1000
Steve French2dd29d32007-04-23 22:07:35 +00001001int
1002CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1003 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001004 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001005 const struct nls_table *nls_codepage, int remap)
1006{
1007 TRANSACTION2_SPI_REQ *pSMB = NULL;
1008 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1009 int name_len;
1010 int rc = 0;
1011 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001012 __u16 params, param_offset, offset, byte_count, count;
1013 OPEN_PSX_REQ * pdata;
1014 OPEN_PSX_RSP * psx_rsp;
1015
1016 cFYI(1, ("In POSIX Create"));
1017PsxCreat:
1018 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1019 (void **) &pSMBr);
1020 if (rc)
1021 return rc;
1022
1023 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1024 name_len =
1025 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1026 PATH_MAX, nls_codepage, remap);
1027 name_len++; /* trailing null */
1028 name_len *= 2;
1029 } else { /* BB improve the check for buffer overruns BB */
1030 name_len = strnlen(name, PATH_MAX);
1031 name_len++; /* trailing null */
1032 strncpy(pSMB->FileName, name, name_len);
1033 }
1034
1035 params = 6 + name_len;
1036 count = sizeof(OPEN_PSX_REQ);
1037 pSMB->MaxParameterCount = cpu_to_le16(2);
1038 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1039 pSMB->MaxSetupCount = 0;
1040 pSMB->Reserved = 0;
1041 pSMB->Flags = 0;
1042 pSMB->Timeout = 0;
1043 pSMB->Reserved2 = 0;
1044 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001045 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001046 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001047 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1048 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
1049 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001050 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001051 pdata->OpenFlags = cpu_to_le32(*pOplock);
1052 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1053 pSMB->DataOffset = cpu_to_le16(offset);
1054 pSMB->SetupCount = 1;
1055 pSMB->Reserved3 = 0;
1056 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1057 byte_count = 3 /* pad */ + params + count;
1058
1059 pSMB->DataCount = cpu_to_le16(count);
1060 pSMB->ParameterCount = cpu_to_le16(params);
1061 pSMB->TotalDataCount = pSMB->DataCount;
1062 pSMB->TotalParameterCount = pSMB->ParameterCount;
1063 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1064 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001065 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001066 pSMB->ByteCount = cpu_to_le16(byte_count);
1067 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1068 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1069 if (rc) {
1070 cFYI(1, ("Posix create returned %d", rc));
1071 goto psx_create_err;
1072 }
1073
Steve French790fe572007-07-07 19:25:05 +00001074 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001075 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1076
1077 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1078 rc = -EIO; /* bad smb */
1079 goto psx_create_err;
1080 }
1081
1082 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001083 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001084 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001085
Steve French2dd29d32007-04-23 22:07:35 +00001086 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001087 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001088 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1089 /* Let caller know file was created so we can set the mode. */
1090 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001091 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001092 *pOplock |= CIFS_CREATE_ACTION;
1093 /* check to make sure response data is there */
Steve French790fe572007-07-07 19:25:05 +00001094 if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001095 pRetData->Type = -1; /* unknown */
1096#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001097 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001098#endif
1099 } else {
Steve French790fe572007-07-07 19:25:05 +00001100 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001101 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001102 cERROR(1, ("Open response data too small"));
Steve French2dd29d32007-04-23 22:07:35 +00001103 pRetData->Type = -1;
1104 goto psx_create_err;
1105 }
Steve French50c2f752007-07-13 00:33:32 +00001106 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001107 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French2dd29d32007-04-23 22:07:35 +00001108 sizeof (FILE_UNIX_BASIC_INFO));
1109 }
Steve French2dd29d32007-04-23 22:07:35 +00001110
1111psx_create_err:
1112 cifs_buf_release(pSMB);
1113
1114 cifs_stats_inc(&tcon->num_mkdirs);
1115
1116 if (rc == -EAGAIN)
1117 goto PsxCreat;
1118
Steve French50c2f752007-07-13 00:33:32 +00001119 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001120}
1121
Steve Frencha9d02ad2005-08-24 23:06:05 -07001122static __u16 convert_disposition(int disposition)
1123{
1124 __u16 ofun = 0;
1125
1126 switch (disposition) {
1127 case FILE_SUPERSEDE:
1128 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1129 break;
1130 case FILE_OPEN:
1131 ofun = SMBOPEN_OAPPEND;
1132 break;
1133 case FILE_CREATE:
1134 ofun = SMBOPEN_OCREATE;
1135 break;
1136 case FILE_OPEN_IF:
1137 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1138 break;
1139 case FILE_OVERWRITE:
1140 ofun = SMBOPEN_OTRUNC;
1141 break;
1142 case FILE_OVERWRITE_IF:
1143 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1144 break;
1145 default:
Steve French790fe572007-07-07 19:25:05 +00001146 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001147 ofun = SMBOPEN_OAPPEND; /* regular open */
1148 }
1149 return ofun;
1150}
1151
1152int
1153SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1154 const char *fileName, const int openDisposition,
1155 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001156 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001157 const struct nls_table *nls_codepage, int remap)
1158{
1159 int rc = -EACCES;
1160 OPENX_REQ *pSMB = NULL;
1161 OPENX_RSP *pSMBr = NULL;
1162 int bytes_returned;
1163 int name_len;
1164 __u16 count;
1165
1166OldOpenRetry:
1167 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1168 (void **) &pSMBr);
1169 if (rc)
1170 return rc;
1171
1172 pSMB->AndXCommand = 0xFF; /* none */
1173
1174 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1175 count = 1; /* account for one byte pad to word boundary */
1176 name_len =
1177 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1178 fileName, PATH_MAX, nls_codepage, remap);
1179 name_len++; /* trailing null */
1180 name_len *= 2;
1181 } else { /* BB improve check for buffer overruns BB */
1182 count = 0; /* no pad */
1183 name_len = strnlen(fileName, PATH_MAX);
1184 name_len++; /* trailing null */
1185 strncpy(pSMB->fileName, fileName, name_len);
1186 }
1187 if (*pOplock & REQ_OPLOCK)
1188 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1189 else if (*pOplock & REQ_BATCHOPLOCK) {
1190 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1191 }
1192 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1193 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1194 /* 0 = read
1195 1 = write
1196 2 = rw
1197 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001198 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001199 pSMB->Mode = cpu_to_le16(2);
1200 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1201 /* set file as system file if special file such
1202 as fifo and server expecting SFU style and
1203 no Unix extensions */
1204
Steve French790fe572007-07-07 19:25:05 +00001205 if (create_options & CREATE_OPTION_SPECIAL)
1206 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1207 else
Steve French3e87d802005-09-18 20:49:21 -07001208 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209
1210 /* if ((omode & S_IWUGO) == 0)
1211 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1212 /* Above line causes problems due to vfs splitting create into two
1213 pieces - need to set mode after file created not while it is
1214 being created */
1215
1216 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001217/* pSMB->CreateOptions = cpu_to_le32(create_options &
1218 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001220
1221 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001222 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 count += name_len;
1224 pSMB->hdr.smb_buf_length += count;
1225
1226 pSMB->ByteCount = cpu_to_le16(count);
1227 /* long_op set to 1 to allow for oplock break timeouts */
1228 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001229 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 cifs_stats_inc(&tcon->num_opens);
1231 if (rc) {
1232 cFYI(1, ("Error in Open = %d", rc));
1233 } else {
1234 /* BB verify if wct == 15 */
1235
1236/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1237
1238 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1239 /* Let caller know file was created so we can set the mode. */
1240 /* Do we care about the CreateAction in any other cases? */
1241 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001242/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 *pOplock |= CIFS_CREATE_ACTION; */
1244 /* BB FIXME END */
1245
Steve French790fe572007-07-07 19:25:05 +00001246 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1248 pfile_info->LastAccessTime = 0; /* BB fixme */
1249 pfile_info->LastWriteTime = 0; /* BB fixme */
1250 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001251 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001252 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001254 pfile_info->AllocationSize =
1255 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1256 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 pfile_info->NumberOfLinks = cpu_to_le32(1);
1258 }
1259 }
1260
1261 cifs_buf_release(pSMB);
1262 if (rc == -EAGAIN)
1263 goto OldOpenRetry;
1264 return rc;
1265}
1266
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267int
1268CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1269 const char *fileName, const int openDisposition,
1270 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001271 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001272 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
1274 int rc = -EACCES;
1275 OPEN_REQ *pSMB = NULL;
1276 OPEN_RSP *pSMBr = NULL;
1277 int bytes_returned;
1278 int name_len;
1279 __u16 count;
1280
1281openRetry:
1282 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1283 (void **) &pSMBr);
1284 if (rc)
1285 return rc;
1286
1287 pSMB->AndXCommand = 0xFF; /* none */
1288
1289 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1290 count = 1; /* account for one byte pad to word boundary */
1291 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001292 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001293 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 name_len++; /* trailing null */
1295 name_len *= 2;
1296 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001297 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 count = 0; /* no pad */
1299 name_len = strnlen(fileName, PATH_MAX);
1300 name_len++; /* trailing null */
1301 pSMB->NameLength = cpu_to_le16(name_len);
1302 strncpy(pSMB->fileName, fileName, name_len);
1303 }
1304 if (*pOplock & REQ_OPLOCK)
1305 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1306 else if (*pOplock & REQ_BATCHOPLOCK) {
1307 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1308 }
1309 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1310 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001311 /* set file as system file if special file such
1312 as fifo and server expecting SFU style and
1313 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001314 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001315 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1316 else
1317 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 /* XP does not handle ATTR_POSIX_SEMANTICS */
1319 /* but it helps speed up case sensitive checks for other
1320 servers such as Samba */
1321 if (tcon->ses->capabilities & CAP_UNIX)
1322 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1323
1324 /* if ((omode & S_IWUGO) == 0)
1325 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1326 /* Above line causes problems due to vfs splitting create into two
1327 pieces - need to set mode after file created not while it is
1328 being created */
1329 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1330 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001331 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001332 /* BB Expirement with various impersonation levels and verify */
1333 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 pSMB->SecurityFlags =
1335 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1336
1337 count += name_len;
1338 pSMB->hdr.smb_buf_length += count;
1339
1340 pSMB->ByteCount = cpu_to_le16(count);
1341 /* long_op set to 1 to allow for oplock break timeouts */
1342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001344 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 if (rc) {
1346 cFYI(1, ("Error in Open = %d", rc));
1347 } else {
Steve French09d1db52005-04-28 22:41:08 -07001348 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1350 /* Let caller know file was created so we can set the mode. */
1351 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001352 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001353 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001354 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001355 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 36 /* CreationTime to Attributes */);
1357 /* the file_info buf is endian converted by caller */
1358 pfile_info->AllocationSize = pSMBr->AllocationSize;
1359 pfile_info->EndOfFile = pSMBr->EndOfFile;
1360 pfile_info->NumberOfLinks = cpu_to_le32(1);
1361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001363
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 cifs_buf_release(pSMB);
1365 if (rc == -EAGAIN)
1366 goto openRetry;
1367 return rc;
1368}
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370int
Steve French50c2f752007-07-13 00:33:32 +00001371CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1372 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1373 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
1375 int rc = -EACCES;
1376 READ_REQ *pSMB = NULL;
1377 READ_RSP *pSMBr = NULL;
1378 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001379 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001380 int resp_buf_type = 0;
1381 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
Steve French790fe572007-07-07 19:25:05 +00001383 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1384 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001385 wct = 12;
1386 else
1387 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001390 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 if (rc)
1392 return rc;
1393
1394 /* tcon and ses pointer are checked in smb_init */
1395 if (tcon->ses->server == NULL)
1396 return -ECONNABORTED;
1397
Steve Frenchec637e32005-12-12 20:53:18 -08001398 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 pSMB->Fid = netfid;
1400 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001401 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001402 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001403 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001404 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001405
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 pSMB->Remaining = 0;
1407 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1408 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001409 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001410 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1411 else {
1412 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001413 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001415 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001416 }
Steve Frenchec637e32005-12-12 20:53:18 -08001417
1418 iov[0].iov_base = (char *)pSMB;
1419 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve French50c2f752007-07-13 00:33:32 +00001420 rc = SendReceive2(xid, tcon->ses, iov,
Steve Frenchec637e32005-12-12 20:53:18 -08001421 1 /* num iovecs */,
Steve French50c2f752007-07-13 00:33:32 +00001422 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001423 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001424 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 if (rc) {
1426 cERROR(1, ("Send error in read = %d", rc));
1427 } else {
1428 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1429 data_length = data_length << 16;
1430 data_length += le16_to_cpu(pSMBr->DataLength);
1431 *nbytes = data_length;
1432
1433 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001434 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001436 cFYI(1, ("bad length %d for count %d",
1437 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 rc = -EIO;
1439 *nbytes = 0;
1440 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001441 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 le16_to_cpu(pSMBr->DataOffset);
Steve French790fe572007-07-07 19:25:05 +00001443/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001444 cERROR(1,("Faulting on read rc = %d",rc));
1445 rc = -EFAULT;
Steve Frenchec637e32005-12-12 20:53:18 -08001446 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001447 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001448 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 }
1450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
Steve French4b8f9302006-02-26 16:41:18 +00001452/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001453 if (*buf) {
1454 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001455 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001456 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001457 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001458 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001459 /* return buffer to caller to free */
1460 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001461 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001462 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001463 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001464 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001465 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001466
1467 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 since file handle passed in no longer valid */
1469 return rc;
1470}
1471
Steve Frenchec637e32005-12-12 20:53:18 -08001472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473int
1474CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1475 const int netfid, const unsigned int count,
1476 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001477 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478{
1479 int rc = -EACCES;
1480 WRITE_REQ *pSMB = NULL;
1481 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001482 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 __u32 bytes_sent;
1484 __u16 byte_count;
1485
1486 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001487 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001488 return -ECONNABORTED;
1489
Steve French790fe572007-07-07 19:25:05 +00001490 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001491 wct = 14;
1492 else
1493 wct = 12;
1494
1495 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 (void **) &pSMBr);
1497 if (rc)
1498 return rc;
1499 /* tcon and ses pointer are checked in smb_init */
1500 if (tcon->ses->server == NULL)
1501 return -ECONNABORTED;
1502
1503 pSMB->AndXCommand = 0xFF; /* none */
1504 pSMB->Fid = netfid;
1505 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001506 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001507 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001508 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001509 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001510
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 pSMB->Reserved = 0xFFFFFFFF;
1512 pSMB->WriteMode = 0;
1513 pSMB->Remaining = 0;
1514
Steve French50c2f752007-07-13 00:33:32 +00001515 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 can send more if LARGE_WRITE_X capability returned by the server and if
1517 our buffer is big enough or if we convert to iovecs on socket writes
1518 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001519 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1521 } else {
1522 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1523 & ~0xFF;
1524 }
1525
1526 if (bytes_sent > count)
1527 bytes_sent = count;
1528 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001529 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001530 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001531 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001532 else if (ubuf) {
1533 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 cifs_buf_release(pSMB);
1535 return -EFAULT;
1536 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001537 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 /* No buffer */
1539 cifs_buf_release(pSMB);
1540 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001541 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001542 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001543 byte_count = bytes_sent + 1; /* pad */
1544 else /* wct == 12 */ {
1545 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1548 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001549 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001550
Steve French790fe572007-07-07 19:25:05 +00001551 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001552 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001553 else { /* old style write has byte count 4 bytes earlier
1554 so 4 bytes pad */
1555 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001556 (struct smb_com_writex_req *)pSMB;
1557 pSMBW->ByteCount = cpu_to_le16(byte_count);
1558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1561 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001562 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 if (rc) {
1564 cFYI(1, ("Send error in write = %d", rc));
1565 *nbytes = 0;
1566 } else {
1567 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1568 *nbytes = (*nbytes) << 16;
1569 *nbytes += le16_to_cpu(pSMBr->Count);
1570 }
1571
1572 cifs_buf_release(pSMB);
1573
Steve French50c2f752007-07-13 00:33:32 +00001574 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 since file handle passed in no longer valid */
1576
1577 return rc;
1578}
1579
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001580int
1581CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001583 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1584 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585{
1586 int rc = -EACCES;
1587 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001588 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001589 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001590 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
Steve French790fe572007-07-07 19:25:05 +00001592 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001593
Steve French790fe572007-07-07 19:25:05 +00001594 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001595 wct = 14;
1596 else
1597 wct = 12;
1598 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 if (rc)
1600 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 /* tcon and ses pointer are checked in smb_init */
1602 if (tcon->ses->server == NULL)
1603 return -ECONNABORTED;
1604
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001605 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 pSMB->Fid = netfid;
1607 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001608 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001609 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001610 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001611 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 pSMB->Reserved = 0xFFFFFFFF;
1613 pSMB->WriteMode = 0;
1614 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001617 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Steve French3e844692005-10-03 13:37:24 -07001619 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1620 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001621 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001622 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001623 pSMB->hdr.smb_buf_length += count+1;
1624 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001625 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1626 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001627 pSMB->ByteCount = cpu_to_le16(count + 1);
1628 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001629 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001630 (struct smb_com_writex_req *)pSMB;
1631 pSMBW->ByteCount = cpu_to_le16(count + 5);
1632 }
Steve French3e844692005-10-03 13:37:24 -07001633 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001634 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001635 iov[0].iov_len = smb_hdr_len + 4;
1636 else /* wct == 12 pad bigger by four bytes */
1637 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001638
Steve French3e844692005-10-03 13:37:24 -07001639
Steve Frenchec637e32005-12-12 20:53:18 -08001640 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001641 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001642 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001644 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001646 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001647 /* presumably this can not happen, but best to be safe */
1648 rc = -EIO;
1649 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001650 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001651 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001652 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1653 *nbytes = (*nbytes) << 16;
1654 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
Steve French4b8f9302006-02-26 16:41:18 +00001657/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001658 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001659 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001660 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001661 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
Steve French50c2f752007-07-13 00:33:32 +00001663 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 since file handle passed in no longer valid */
1665
1666 return rc;
1667}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001668
1669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670int
1671CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1672 const __u16 smb_file_id, const __u64 len,
1673 const __u64 offset, const __u32 numUnlock,
1674 const __u32 numLock, const __u8 lockType, const int waitFlag)
1675{
1676 int rc = 0;
1677 LOCK_REQ *pSMB = NULL;
1678 LOCK_RSP *pSMBr = NULL;
1679 int bytes_returned;
1680 int timeout = 0;
1681 __u16 count;
1682
Steve French50c2f752007-07-13 00:33:32 +00001683 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001684 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 if (rc)
1687 return rc;
1688
Steve French46810cb2005-04-28 22:41:09 -07001689 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1690
Steve French790fe572007-07-07 19:25:05 +00001691 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 timeout = -1; /* no response expected */
1693 pSMB->Timeout = 0;
1694 } else if (waitFlag == TRUE) {
1695 timeout = 3; /* blocking operation, no timeout */
1696 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1697 } else {
1698 pSMB->Timeout = 0;
1699 }
1700
1701 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1702 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1703 pSMB->LockType = lockType;
1704 pSMB->AndXCommand = 0xFF; /* none */
1705 pSMB->Fid = smb_file_id; /* netfid stays le */
1706
Steve French790fe572007-07-07 19:25:05 +00001707 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1709 /* BB where to store pid high? */
1710 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1711 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1712 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1713 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1714 count = sizeof(LOCKING_ANDX_RANGE);
1715 } else {
1716 /* oplock break */
1717 count = 0;
1718 }
1719 pSMB->hdr.smb_buf_length += count;
1720 pSMB->ByteCount = cpu_to_le16(count);
1721
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001722 if (waitFlag) {
1723 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1724 (struct smb_hdr *) pSMBr, &bytes_returned);
1725 } else {
1726 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001728 }
Steve Frencha4544342005-08-24 13:59:35 -07001729 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 if (rc) {
1731 cFYI(1, ("Send error in Lock = %d", rc));
1732 }
Steve French46810cb2005-04-28 22:41:09 -07001733 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
Steve French50c2f752007-07-13 00:33:32 +00001735 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 since file handle passed in no longer valid */
1737 return rc;
1738}
1739
1740int
Steve French08547b02006-02-28 22:39:25 +00001741CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1742 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001743 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001744 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001745{
1746 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1747 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001748 struct cifs_posix_lock *parm_data;
1749 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001750 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001751 int bytes_returned = 0;
1752 __u16 params, param_offset, offset, byte_count, count;
1753
1754 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001755
Steve French790fe572007-07-07 19:25:05 +00001756 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001757 return EINVAL;
1758
Steve French08547b02006-02-28 22:39:25 +00001759 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1760
1761 if (rc)
1762 return rc;
1763
1764 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1765
Steve French50c2f752007-07-13 00:33:32 +00001766 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001767 pSMB->MaxSetupCount = 0;
1768 pSMB->Reserved = 0;
1769 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001770 pSMB->Reserved2 = 0;
1771 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1772 offset = param_offset + params;
1773
Steve French08547b02006-02-28 22:39:25 +00001774 count = sizeof(struct cifs_posix_lock);
1775 pSMB->MaxParameterCount = cpu_to_le16(2);
1776 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1777 pSMB->SetupCount = 1;
1778 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001779 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001780 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1781 else
1782 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1783 byte_count = 3 /* pad */ + params + count;
1784 pSMB->DataCount = cpu_to_le16(count);
1785 pSMB->ParameterCount = cpu_to_le16(params);
1786 pSMB->TotalDataCount = pSMB->DataCount;
1787 pSMB->TotalParameterCount = pSMB->ParameterCount;
1788 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001789 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001790 (((char *) &pSMB->hdr.Protocol) + offset);
1791
1792 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001793 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001794 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001795 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001796 pSMB->Timeout = cpu_to_le32(-1);
1797 } else
1798 pSMB->Timeout = 0;
1799
Steve French08547b02006-02-28 22:39:25 +00001800 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001801 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001802 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001803
1804 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001805 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001806 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1807 pSMB->Reserved4 = 0;
1808 pSMB->hdr.smb_buf_length += byte_count;
1809 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001810 if (waitFlag) {
1811 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1812 (struct smb_hdr *) pSMBr, &bytes_returned);
1813 } else {
1814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001815 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001816 }
1817
Steve French08547b02006-02-28 22:39:25 +00001818 if (rc) {
1819 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001820 } else if (get_flag) {
1821 /* lock structure can be returned on get */
1822 __u16 data_offset;
1823 __u16 data_count;
1824 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001825
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001826 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1827 rc = -EIO; /* bad smb */
1828 goto plk_err_exit;
1829 }
Steve French790fe572007-07-07 19:25:05 +00001830 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001831 rc = -EINVAL;
1832 goto plk_err_exit;
1833 }
1834 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1835 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001836 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001837 rc = -EIO;
1838 goto plk_err_exit;
1839 }
1840 parm_data = (struct cifs_posix_lock *)
1841 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001842 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001843 pLockData->fl_type = F_UNLCK;
1844 }
Steve French50c2f752007-07-13 00:33:32 +00001845
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001846plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001847 if (pSMB)
1848 cifs_small_buf_release(pSMB);
1849
1850 /* Note: On -EAGAIN error only caller can retry on handle based calls
1851 since file handle passed in no longer valid */
1852
1853 return rc;
1854}
1855
1856
1857int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1859{
1860 int rc = 0;
1861 CLOSE_REQ *pSMB = NULL;
1862 CLOSE_RSP *pSMBr = NULL;
1863 int bytes_returned;
1864 cFYI(1, ("In CIFSSMBClose"));
1865
1866/* do not retry on dead session on close */
1867 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001868 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 return 0;
1870 if (rc)
1871 return rc;
1872
1873 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1874
1875 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001876 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 pSMB->ByteCount = 0;
1878 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1879 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001880 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001882 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 /* EINTR is expected when user ctl-c to kill app */
1884 cERROR(1, ("Send error in Close = %d", rc));
1885 }
1886 }
1887
1888 cifs_small_buf_release(pSMB);
1889
1890 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001891 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 rc = 0;
1893
1894 return rc;
1895}
1896
1897int
1898CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1899 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001900 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901{
1902 int rc = 0;
1903 RENAME_REQ *pSMB = NULL;
1904 RENAME_RSP *pSMBr = NULL;
1905 int bytes_returned;
1906 int name_len, name_len2;
1907 __u16 count;
1908
1909 cFYI(1, ("In CIFSSMBRename"));
1910renameRetry:
1911 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1912 (void **) &pSMBr);
1913 if (rc)
1914 return rc;
1915
1916 pSMB->BufferFormat = 0x04;
1917 pSMB->SearchAttributes =
1918 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1919 ATTR_DIRECTORY);
1920
1921 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1922 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001923 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001924 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 name_len++; /* trailing null */
1926 name_len *= 2;
1927 pSMB->OldFileName[name_len] = 0x04; /* pad */
1928 /* protocol requires ASCII signature byte on Unicode string */
1929 pSMB->OldFileName[name_len + 1] = 0x00;
1930 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001931 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001932 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1934 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001935 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 name_len = strnlen(fromName, PATH_MAX);
1937 name_len++; /* trailing null */
1938 strncpy(pSMB->OldFileName, fromName, name_len);
1939 name_len2 = strnlen(toName, PATH_MAX);
1940 name_len2++; /* trailing null */
1941 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1942 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1943 name_len2++; /* trailing null */
1944 name_len2++; /* signature byte */
1945 }
1946
1947 count = 1 /* 1st signature byte */ + name_len + name_len2;
1948 pSMB->hdr.smb_buf_length += count;
1949 pSMB->ByteCount = cpu_to_le16(count);
1950
1951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001953 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 if (rc) {
1955 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 cifs_buf_release(pSMB);
1959
1960 if (rc == -EAGAIN)
1961 goto renameRetry;
1962
1963 return rc;
1964}
1965
Steve French50c2f752007-07-13 00:33:32 +00001966int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1967 int netfid, char *target_name,
1968 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969{
1970 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1971 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001972 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 char *data_offset;
1974 char dummy_string[30];
1975 int rc = 0;
1976 int bytes_returned = 0;
1977 int len_of_str;
1978 __u16 params, param_offset, offset, count, byte_count;
1979
1980 cFYI(1, ("Rename to File by handle"));
1981 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1982 (void **) &pSMBr);
1983 if (rc)
1984 return rc;
1985
1986 params = 6;
1987 pSMB->MaxSetupCount = 0;
1988 pSMB->Reserved = 0;
1989 pSMB->Flags = 0;
1990 pSMB->Timeout = 0;
1991 pSMB->Reserved2 = 0;
1992 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1993 offset = param_offset + params;
1994
1995 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1996 rename_info = (struct set_file_rename *) data_offset;
1997 pSMB->MaxParameterCount = cpu_to_le16(2);
1998 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1999 pSMB->SetupCount = 1;
2000 pSMB->Reserved3 = 0;
2001 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2002 byte_count = 3 /* pad */ + params;
2003 pSMB->ParameterCount = cpu_to_le16(params);
2004 pSMB->TotalParameterCount = pSMB->ParameterCount;
2005 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2006 pSMB->DataOffset = cpu_to_le16(offset);
2007 /* construct random name ".cifs_tmp<inodenum><mid>" */
2008 rename_info->overwrite = cpu_to_le32(1);
2009 rename_info->root_fid = 0;
2010 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002011 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002012 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2013 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002014 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002016 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002017 target_name, PATH_MAX, nls_codepage,
2018 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 }
2020 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2021 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2022 byte_count += count;
2023 pSMB->DataCount = cpu_to_le16(count);
2024 pSMB->TotalDataCount = pSMB->DataCount;
2025 pSMB->Fid = netfid;
2026 pSMB->InformationLevel =
2027 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2028 pSMB->Reserved4 = 0;
2029 pSMB->hdr.smb_buf_length += byte_count;
2030 pSMB->ByteCount = cpu_to_le16(byte_count);
2031 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002033 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002035 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002037
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 cifs_buf_release(pSMB);
2039
2040 /* Note: On -EAGAIN error only caller can retry on handle based calls
2041 since file handle passed in no longer valid */
2042
2043 return rc;
2044}
2045
2046int
Steve French50c2f752007-07-13 00:33:32 +00002047CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2048 const __u16 target_tid, const char *toName, const int flags,
2049 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050{
2051 int rc = 0;
2052 COPY_REQ *pSMB = NULL;
2053 COPY_RSP *pSMBr = NULL;
2054 int bytes_returned;
2055 int name_len, name_len2;
2056 __u16 count;
2057
2058 cFYI(1, ("In CIFSSMBCopy"));
2059copyRetry:
2060 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2061 (void **) &pSMBr);
2062 if (rc)
2063 return rc;
2064
2065 pSMB->BufferFormat = 0x04;
2066 pSMB->Tid2 = target_tid;
2067
2068 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2069
2070 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002071 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002072 fromName, PATH_MAX, nls_codepage,
2073 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 name_len++; /* trailing null */
2075 name_len *= 2;
2076 pSMB->OldFileName[name_len] = 0x04; /* pad */
2077 /* protocol requires ASCII signature byte on Unicode string */
2078 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002079 name_len2 =
2080 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002081 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2083 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002084 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 name_len = strnlen(fromName, PATH_MAX);
2086 name_len++; /* trailing null */
2087 strncpy(pSMB->OldFileName, fromName, name_len);
2088 name_len2 = strnlen(toName, PATH_MAX);
2089 name_len2++; /* trailing null */
2090 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2091 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2092 name_len2++; /* trailing null */
2093 name_len2++; /* signature byte */
2094 }
2095
2096 count = 1 /* 1st signature byte */ + name_len + name_len2;
2097 pSMB->hdr.smb_buf_length += count;
2098 pSMB->ByteCount = cpu_to_le16(count);
2099
2100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2102 if (rc) {
2103 cFYI(1, ("Send error in copy = %d with %d files copied",
2104 rc, le16_to_cpu(pSMBr->CopyCount)));
2105 }
2106 if (pSMB)
2107 cifs_buf_release(pSMB);
2108
2109 if (rc == -EAGAIN)
2110 goto copyRetry;
2111
2112 return rc;
2113}
2114
2115int
2116CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2117 const char *fromName, const char *toName,
2118 const struct nls_table *nls_codepage)
2119{
2120 TRANSACTION2_SPI_REQ *pSMB = NULL;
2121 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2122 char *data_offset;
2123 int name_len;
2124 int name_len_target;
2125 int rc = 0;
2126 int bytes_returned = 0;
2127 __u16 params, param_offset, offset, byte_count;
2128
2129 cFYI(1, ("In Symlink Unix style"));
2130createSymLinkRetry:
2131 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2132 (void **) &pSMBr);
2133 if (rc)
2134 return rc;
2135
2136 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2137 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002138 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 /* find define for this maxpathcomponent */
2140 , nls_codepage);
2141 name_len++; /* trailing null */
2142 name_len *= 2;
2143
Steve French50c2f752007-07-13 00:33:32 +00002144 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 name_len = strnlen(fromName, PATH_MAX);
2146 name_len++; /* trailing null */
2147 strncpy(pSMB->FileName, fromName, name_len);
2148 }
2149 params = 6 + name_len;
2150 pSMB->MaxSetupCount = 0;
2151 pSMB->Reserved = 0;
2152 pSMB->Flags = 0;
2153 pSMB->Timeout = 0;
2154 pSMB->Reserved2 = 0;
2155 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002156 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 offset = param_offset + params;
2158
2159 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2160 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2161 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002162 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 /* find define for this maxpathcomponent */
2164 , nls_codepage);
2165 name_len_target++; /* trailing null */
2166 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002167 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 name_len_target = strnlen(toName, PATH_MAX);
2169 name_len_target++; /* trailing null */
2170 strncpy(data_offset, toName, name_len_target);
2171 }
2172
2173 pSMB->MaxParameterCount = cpu_to_le16(2);
2174 /* BB find exact max on data count below from sess */
2175 pSMB->MaxDataCount = cpu_to_le16(1000);
2176 pSMB->SetupCount = 1;
2177 pSMB->Reserved3 = 0;
2178 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2179 byte_count = 3 /* pad */ + params + name_len_target;
2180 pSMB->DataCount = cpu_to_le16(name_len_target);
2181 pSMB->ParameterCount = cpu_to_le16(params);
2182 pSMB->TotalDataCount = pSMB->DataCount;
2183 pSMB->TotalParameterCount = pSMB->ParameterCount;
2184 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2185 pSMB->DataOffset = cpu_to_le16(offset);
2186 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2187 pSMB->Reserved4 = 0;
2188 pSMB->hdr.smb_buf_length += byte_count;
2189 pSMB->ByteCount = cpu_to_le16(byte_count);
2190 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2191 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002192 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002194 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 }
2196
2197 if (pSMB)
2198 cifs_buf_release(pSMB);
2199
2200 if (rc == -EAGAIN)
2201 goto createSymLinkRetry;
2202
2203 return rc;
2204}
2205
2206int
2207CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2208 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002209 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210{
2211 TRANSACTION2_SPI_REQ *pSMB = NULL;
2212 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2213 char *data_offset;
2214 int name_len;
2215 int name_len_target;
2216 int rc = 0;
2217 int bytes_returned = 0;
2218 __u16 params, param_offset, offset, byte_count;
2219
2220 cFYI(1, ("In Create Hard link Unix style"));
2221createHardLinkRetry:
2222 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2223 (void **) &pSMBr);
2224 if (rc)
2225 return rc;
2226
2227 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002228 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002229 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 name_len++; /* trailing null */
2231 name_len *= 2;
2232
Steve French50c2f752007-07-13 00:33:32 +00002233 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 name_len = strnlen(toName, PATH_MAX);
2235 name_len++; /* trailing null */
2236 strncpy(pSMB->FileName, toName, name_len);
2237 }
2238 params = 6 + name_len;
2239 pSMB->MaxSetupCount = 0;
2240 pSMB->Reserved = 0;
2241 pSMB->Flags = 0;
2242 pSMB->Timeout = 0;
2243 pSMB->Reserved2 = 0;
2244 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002245 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 offset = param_offset + params;
2247
2248 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2249 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2250 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002251 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002252 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 name_len_target++; /* trailing null */
2254 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002255 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 name_len_target = strnlen(fromName, PATH_MAX);
2257 name_len_target++; /* trailing null */
2258 strncpy(data_offset, fromName, name_len_target);
2259 }
2260
2261 pSMB->MaxParameterCount = cpu_to_le16(2);
2262 /* BB find exact max on data count below from sess*/
2263 pSMB->MaxDataCount = cpu_to_le16(1000);
2264 pSMB->SetupCount = 1;
2265 pSMB->Reserved3 = 0;
2266 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2267 byte_count = 3 /* pad */ + params + name_len_target;
2268 pSMB->ParameterCount = cpu_to_le16(params);
2269 pSMB->TotalParameterCount = pSMB->ParameterCount;
2270 pSMB->DataCount = cpu_to_le16(name_len_target);
2271 pSMB->TotalDataCount = pSMB->DataCount;
2272 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2273 pSMB->DataOffset = cpu_to_le16(offset);
2274 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2275 pSMB->Reserved4 = 0;
2276 pSMB->hdr.smb_buf_length += byte_count;
2277 pSMB->ByteCount = cpu_to_le16(byte_count);
2278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2279 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002280 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 if (rc) {
2282 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2283 }
2284
2285 cifs_buf_release(pSMB);
2286 if (rc == -EAGAIN)
2287 goto createHardLinkRetry;
2288
2289 return rc;
2290}
2291
2292int
2293CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2294 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002295 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296{
2297 int rc = 0;
2298 NT_RENAME_REQ *pSMB = NULL;
2299 RENAME_RSP *pSMBr = NULL;
2300 int bytes_returned;
2301 int name_len, name_len2;
2302 __u16 count;
2303
2304 cFYI(1, ("In CIFSCreateHardLink"));
2305winCreateHardLinkRetry:
2306
2307 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2308 (void **) &pSMBr);
2309 if (rc)
2310 return rc;
2311
2312 pSMB->SearchAttributes =
2313 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2314 ATTR_DIRECTORY);
2315 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2316 pSMB->ClusterCount = 0;
2317
2318 pSMB->BufferFormat = 0x04;
2319
2320 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2321 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002322 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002323 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 name_len++; /* trailing null */
2325 name_len *= 2;
2326 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002327 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002329 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002330 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2332 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002333 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 name_len = strnlen(fromName, PATH_MAX);
2335 name_len++; /* trailing null */
2336 strncpy(pSMB->OldFileName, fromName, name_len);
2337 name_len2 = strnlen(toName, PATH_MAX);
2338 name_len2++; /* trailing null */
2339 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2340 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2341 name_len2++; /* trailing null */
2342 name_len2++; /* signature byte */
2343 }
2344
2345 count = 1 /* string type byte */ + name_len + name_len2;
2346 pSMB->hdr.smb_buf_length += count;
2347 pSMB->ByteCount = cpu_to_le16(count);
2348
2349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002351 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 if (rc) {
2353 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2354 }
2355 cifs_buf_release(pSMB);
2356 if (rc == -EAGAIN)
2357 goto winCreateHardLinkRetry;
2358
2359 return rc;
2360}
2361
2362int
2363CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2364 const unsigned char *searchName,
2365 char *symlinkinfo, const int buflen,
2366 const struct nls_table *nls_codepage)
2367{
2368/* SMB_QUERY_FILE_UNIX_LINK */
2369 TRANSACTION2_QPI_REQ *pSMB = NULL;
2370 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2371 int rc = 0;
2372 int bytes_returned;
2373 int name_len;
2374 __u16 params, byte_count;
2375
2376 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2377
2378querySymLinkRetry:
2379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2380 (void **) &pSMBr);
2381 if (rc)
2382 return rc;
2383
2384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2385 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002386 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2387 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 name_len++; /* trailing null */
2389 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002390 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 name_len = strnlen(searchName, PATH_MAX);
2392 name_len++; /* trailing null */
2393 strncpy(pSMB->FileName, searchName, name_len);
2394 }
2395
2396 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2397 pSMB->TotalDataCount = 0;
2398 pSMB->MaxParameterCount = cpu_to_le16(2);
2399 /* BB find exact max data count below from sess structure BB */
2400 pSMB->MaxDataCount = cpu_to_le16(4000);
2401 pSMB->MaxSetupCount = 0;
2402 pSMB->Reserved = 0;
2403 pSMB->Flags = 0;
2404 pSMB->Timeout = 0;
2405 pSMB->Reserved2 = 0;
2406 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002407 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 pSMB->DataCount = 0;
2409 pSMB->DataOffset = 0;
2410 pSMB->SetupCount = 1;
2411 pSMB->Reserved3 = 0;
2412 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2413 byte_count = params + 1 /* pad */ ;
2414 pSMB->TotalParameterCount = cpu_to_le16(params);
2415 pSMB->ParameterCount = pSMB->TotalParameterCount;
2416 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2417 pSMB->Reserved4 = 0;
2418 pSMB->hdr.smb_buf_length += byte_count;
2419 pSMB->ByteCount = cpu_to_le16(byte_count);
2420
2421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2423 if (rc) {
2424 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2425 } else {
2426 /* decode response */
2427
2428 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2429 if (rc || (pSMBr->ByteCount < 2))
2430 /* BB also check enough total bytes returned */
2431 rc = -EIO; /* bad smb */
2432 else {
2433 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2434 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2435
2436 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2437 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002438 &pSMBr->hdr.Protocol + data_offset),
2439 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002440 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002442 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2443 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 name_len, nls_codepage);
2445 } else {
2446 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002447 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 data_offset,
2449 min_t(const int, buflen, count));
2450 }
2451 symlinkinfo[buflen] = 0;
2452 /* just in case so calling code does not go off the end of buffer */
2453 }
2454 }
2455 cifs_buf_release(pSMB);
2456 if (rc == -EAGAIN)
2457 goto querySymLinkRetry;
2458 return rc;
2459}
2460
Steve French0a4b92c2006-01-12 15:44:21 -08002461/* Initialize NT TRANSACT SMB into small smb request buffer.
2462 This assumes that all NT TRANSACTS that we init here have
2463 total parm and data under about 400 bytes (to fit in small cifs
2464 buffer size), which is the case so far, it easily fits. NB:
2465 Setup words themselves and ByteCount
2466 MaxSetupCount (size of returned setup area) and
2467 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002468static int
Steve French0a4b92c2006-01-12 15:44:21 -08002469smb_init_ntransact(const __u16 sub_command, const int setup_count,
2470 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002471 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002472{
2473 int rc;
2474 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002475 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002476
2477 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2478 (void **)&pSMB);
2479 if (rc)
2480 return rc;
2481 *ret_buf = (void *)pSMB;
2482 pSMB->Reserved = 0;
2483 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2484 pSMB->TotalDataCount = 0;
2485 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2486 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2487 pSMB->ParameterCount = pSMB->TotalParameterCount;
2488 pSMB->DataCount = pSMB->TotalDataCount;
2489 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2490 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2491 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2492 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2493 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2494 pSMB->SubCommand = cpu_to_le16(sub_command);
2495 return 0;
2496}
2497
2498static int
Steve French50c2f752007-07-13 00:33:32 +00002499validate_ntransact(char *buf, char **ppparm, char **ppdata,
2500 int *pdatalen, int *pparmlen)
Steve French0a4b92c2006-01-12 15:44:21 -08002501{
Steve French50c2f752007-07-13 00:33:32 +00002502 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002503 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002504 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002505
Steve French790fe572007-07-07 19:25:05 +00002506 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002507 return -EINVAL;
2508
2509 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2510
2511 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002512 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002513 (char *)&pSMBr->ByteCount;
2514
Steve French0a4b92c2006-01-12 15:44:21 -08002515 data_offset = le32_to_cpu(pSMBr->DataOffset);
2516 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002517 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002518 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2519
2520 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2521 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2522
2523 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002524 if (*ppparm > end_of_smb) {
2525 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002526 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002527 } else if (parm_count + *ppparm > end_of_smb) {
2528 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002529 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002530 } else if (*ppdata > end_of_smb) {
2531 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002532 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002533 } else if (data_count + *ppdata > end_of_smb) {
Steve French0a4b92c2006-01-12 15:44:21 -08002534 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002535 *ppdata, data_count, (data_count + *ppdata),
2536 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002537 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002538 } else if (parm_count + data_count > pSMBr->ByteCount) {
2539 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002540 return -EINVAL;
2541 }
2542 return 0;
2543}
2544
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545int
2546CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2547 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002548 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 const struct nls_table *nls_codepage)
2550{
2551 int rc = 0;
2552 int bytes_returned;
2553 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002554 struct smb_com_transaction_ioctl_req *pSMB;
2555 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556
2557 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2558 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2559 (void **) &pSMBr);
2560 if (rc)
2561 return rc;
2562
2563 pSMB->TotalParameterCount = 0 ;
2564 pSMB->TotalDataCount = 0;
2565 pSMB->MaxParameterCount = cpu_to_le32(2);
2566 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002567 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2568 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 pSMB->MaxSetupCount = 4;
2570 pSMB->Reserved = 0;
2571 pSMB->ParameterOffset = 0;
2572 pSMB->DataCount = 0;
2573 pSMB->DataOffset = 0;
2574 pSMB->SetupCount = 4;
2575 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2576 pSMB->ParameterCount = pSMB->TotalParameterCount;
2577 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2578 pSMB->IsFsctl = 1; /* FSCTL */
2579 pSMB->IsRootFlag = 0;
2580 pSMB->Fid = fid; /* file handle always le */
2581 pSMB->ByteCount = 0;
2582
2583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2585 if (rc) {
2586 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2587 } else { /* decode response */
2588 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2589 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2590 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2591 /* BB also check enough total bytes returned */
2592 rc = -EIO; /* bad smb */
2593 else {
Steve French790fe572007-07-07 19:25:05 +00002594 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002595 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002596 pSMBr->ByteCount +
2597 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Steve French50c2f752007-07-13 00:33:32 +00002599 struct reparse_data *reparse_buf =
2600 (struct reparse_data *)
2601 ((char *)&pSMBr->hdr.Protocol
2602 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002603 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 rc = -EIO;
2605 goto qreparse_out;
2606 }
Steve French790fe572007-07-07 19:25:05 +00002607 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 reparse_buf->TargetNameOffset +
2609 reparse_buf->TargetNameLen) >
2610 end_of_smb) {
2611 cFYI(1,("reparse buf extended beyond SMB"));
2612 rc = -EIO;
2613 goto qreparse_out;
2614 }
Steve French50c2f752007-07-13 00:33:32 +00002615
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2617 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002618 (reparse_buf->LinkNamesBuf +
2619 reparse_buf->TargetNameOffset),
2620 min(buflen/2,
2621 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002623 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 reparse_buf->TargetNameOffset),
2625 name_len, nls_codepage);
2626 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002627 strncpy(symlinkinfo,
2628 reparse_buf->LinkNamesBuf +
2629 reparse_buf->TargetNameOffset,
2630 min_t(const int, buflen,
2631 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 }
2633 } else {
2634 rc = -EIO;
2635 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2636 }
2637 symlinkinfo[buflen] = 0; /* just in case so the caller
2638 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002639 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
2641 }
2642qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002643 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 /* Note: On -EAGAIN error only caller can retry on handle based calls
2646 since file handle passed in no longer valid */
2647
2648 return rc;
2649}
2650
2651#ifdef CONFIG_CIFS_POSIX
2652
2653/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002654static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2655 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656{
2657 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002658 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2659 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2660 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2662
2663 return;
2664}
2665
2666/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002667static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2668 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
2670 int size = 0;
2671 int i;
2672 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002673 struct cifs_posix_ace *pACE;
2674 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2675 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676
2677 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2678 return -EOPNOTSUPP;
2679
Steve French790fe572007-07-07 19:25:05 +00002680 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 count = le16_to_cpu(cifs_acl->access_entry_count);
2682 pACE = &cifs_acl->ace_array[0];
2683 size = sizeof(struct cifs_posix_acl);
2684 size += sizeof(struct cifs_posix_ace) * count;
2685 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002686 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002687 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2688 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 return -EINVAL;
2690 }
Steve French790fe572007-07-07 19:25:05 +00002691 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 count = le16_to_cpu(cifs_acl->access_entry_count);
2693 size = sizeof(struct cifs_posix_acl);
2694 size += sizeof(struct cifs_posix_ace) * count;
2695/* skip past access ACEs to get to default ACEs */
2696 pACE = &cifs_acl->ace_array[count];
2697 count = le16_to_cpu(cifs_acl->default_entry_count);
2698 size += sizeof(struct cifs_posix_ace) * count;
2699 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002700 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 return -EINVAL;
2702 } else {
2703 /* illegal type */
2704 return -EINVAL;
2705 }
2706
2707 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002708 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002709 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002710 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 return -ERANGE;
2712 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002713 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002714 for (i = 0; i < count ; i++) {
2715 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2716 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 }
2718 }
2719 return size;
2720}
2721
Steve French50c2f752007-07-13 00:33:32 +00002722static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2723 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724{
2725 __u16 rc = 0; /* 0 = ACL converted ok */
2726
Steve Frenchff7feac2005-11-15 16:45:16 -08002727 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2728 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002730 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 /* Probably no need to le convert -1 on any arch but can not hurt */
2732 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002733 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002734 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002735 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 return rc;
2737}
2738
2739/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002740static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2741 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742{
2743 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002744 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2745 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 int count;
2747 int i;
2748
Steve French790fe572007-07-07 19:25:05 +00002749 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 return 0;
2751
2752 count = posix_acl_xattr_count((size_t)buflen);
2753 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002754 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002755 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002756 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002757 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 return 0;
2759 }
2760 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002761 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002762 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002763 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002764 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 else {
Steve French50c2f752007-07-13 00:33:32 +00002766 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 return 0;
2768 }
Steve French50c2f752007-07-13 00:33:32 +00002769 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2771 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002772 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 /* ACE not converted */
2774 break;
2775 }
2776 }
Steve French790fe572007-07-07 19:25:05 +00002777 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2779 rc += sizeof(struct cifs_posix_acl);
2780 /* BB add check to make sure ACL does not overflow SMB */
2781 }
2782 return rc;
2783}
2784
2785int
2786CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002787 const unsigned char *searchName,
2788 char *acl_inf, const int buflen, const int acl_type,
2789 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790{
2791/* SMB_QUERY_POSIX_ACL */
2792 TRANSACTION2_QPI_REQ *pSMB = NULL;
2793 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2794 int rc = 0;
2795 int bytes_returned;
2796 int name_len;
2797 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002798
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2800
2801queryAclRetry:
2802 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2803 (void **) &pSMBr);
2804 if (rc)
2805 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002806
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2808 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002809 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002810 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 name_len++; /* trailing null */
2812 name_len *= 2;
2813 pSMB->FileName[name_len] = 0;
2814 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002815 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 name_len = strnlen(searchName, PATH_MAX);
2817 name_len++; /* trailing null */
2818 strncpy(pSMB->FileName, searchName, name_len);
2819 }
2820
2821 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2822 pSMB->TotalDataCount = 0;
2823 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002824 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 pSMB->MaxDataCount = cpu_to_le16(4000);
2826 pSMB->MaxSetupCount = 0;
2827 pSMB->Reserved = 0;
2828 pSMB->Flags = 0;
2829 pSMB->Timeout = 0;
2830 pSMB->Reserved2 = 0;
2831 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002832 offsetof(struct smb_com_transaction2_qpi_req,
2833 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 pSMB->DataCount = 0;
2835 pSMB->DataOffset = 0;
2836 pSMB->SetupCount = 1;
2837 pSMB->Reserved3 = 0;
2838 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2839 byte_count = params + 1 /* pad */ ;
2840 pSMB->TotalParameterCount = cpu_to_le16(params);
2841 pSMB->ParameterCount = pSMB->TotalParameterCount;
2842 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2843 pSMB->Reserved4 = 0;
2844 pSMB->hdr.smb_buf_length += byte_count;
2845 pSMB->ByteCount = cpu_to_le16(byte_count);
2846
2847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002849 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 if (rc) {
2851 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2852 } else {
2853 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002854
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2856 if (rc || (pSMBr->ByteCount < 2))
2857 /* BB also check enough total bytes returned */
2858 rc = -EIO; /* bad smb */
2859 else {
2860 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2861 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2862 rc = cifs_copy_posix_acl(acl_inf,
2863 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002864 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 }
2866 }
2867 cifs_buf_release(pSMB);
2868 if (rc == -EAGAIN)
2869 goto queryAclRetry;
2870 return rc;
2871}
2872
2873int
2874CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002875 const unsigned char *fileName,
2876 const char *local_acl, const int buflen,
2877 const int acl_type,
2878 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879{
2880 struct smb_com_transaction2_spi_req *pSMB = NULL;
2881 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2882 char *parm_data;
2883 int name_len;
2884 int rc = 0;
2885 int bytes_returned = 0;
2886 __u16 params, byte_count, data_count, param_offset, offset;
2887
2888 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2889setAclRetry:
2890 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002891 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 if (rc)
2893 return rc;
2894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2895 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002896 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002897 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 name_len++; /* trailing null */
2899 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002900 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 name_len = strnlen(fileName, PATH_MAX);
2902 name_len++; /* trailing null */
2903 strncpy(pSMB->FileName, fileName, name_len);
2904 }
2905 params = 6 + name_len;
2906 pSMB->MaxParameterCount = cpu_to_le16(2);
2907 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2908 pSMB->MaxSetupCount = 0;
2909 pSMB->Reserved = 0;
2910 pSMB->Flags = 0;
2911 pSMB->Timeout = 0;
2912 pSMB->Reserved2 = 0;
2913 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002914 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 offset = param_offset + params;
2916 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2917 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2918
2919 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002920 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921
Steve French790fe572007-07-07 19:25:05 +00002922 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 rc = -EOPNOTSUPP;
2924 goto setACLerrorExit;
2925 }
2926 pSMB->DataOffset = cpu_to_le16(offset);
2927 pSMB->SetupCount = 1;
2928 pSMB->Reserved3 = 0;
2929 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2930 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2931 byte_count = 3 /* pad */ + params + data_count;
2932 pSMB->DataCount = cpu_to_le16(data_count);
2933 pSMB->TotalDataCount = pSMB->DataCount;
2934 pSMB->ParameterCount = cpu_to_le16(params);
2935 pSMB->TotalParameterCount = pSMB->ParameterCount;
2936 pSMB->Reserved4 = 0;
2937 pSMB->hdr.smb_buf_length += byte_count;
2938 pSMB->ByteCount = cpu_to_le16(byte_count);
2939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 if (rc) {
2942 cFYI(1, ("Set POSIX ACL returned %d", rc));
2943 }
2944
2945setACLerrorExit:
2946 cifs_buf_release(pSMB);
2947 if (rc == -EAGAIN)
2948 goto setAclRetry;
2949 return rc;
2950}
2951
Steve Frenchf654bac2005-04-28 22:41:04 -07002952/* BB fix tabs in this function FIXME BB */
2953int
2954CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002955 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002956{
Steve French50c2f752007-07-13 00:33:32 +00002957 int rc = 0;
2958 struct smb_t2_qfi_req *pSMB = NULL;
2959 struct smb_t2_qfi_rsp *pSMBr = NULL;
2960 int bytes_returned;
2961 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002962
Steve French790fe572007-07-07 19:25:05 +00002963 cFYI(1, ("In GetExtAttr"));
2964 if (tcon == NULL)
2965 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002966
2967GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002968 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2969 (void **) &pSMBr);
2970 if (rc)
2971 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002972
Steve French790fe572007-07-07 19:25:05 +00002973 params = 2 /* level */ +2 /* fid */;
2974 pSMB->t2.TotalDataCount = 0;
2975 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2976 /* BB find exact max data count below from sess structure BB */
2977 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2978 pSMB->t2.MaxSetupCount = 0;
2979 pSMB->t2.Reserved = 0;
2980 pSMB->t2.Flags = 0;
2981 pSMB->t2.Timeout = 0;
2982 pSMB->t2.Reserved2 = 0;
2983 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2984 Fid) - 4);
2985 pSMB->t2.DataCount = 0;
2986 pSMB->t2.DataOffset = 0;
2987 pSMB->t2.SetupCount = 1;
2988 pSMB->t2.Reserved3 = 0;
2989 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2990 byte_count = params + 1 /* pad */ ;
2991 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2992 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2993 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2994 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002995 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002996 pSMB->hdr.smb_buf_length += byte_count;
2997 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002998
Steve French790fe572007-07-07 19:25:05 +00002999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3001 if (rc) {
3002 cFYI(1, ("error %d in GetExtAttr", rc));
3003 } else {
3004 /* decode response */
3005 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3006 if (rc || (pSMBr->ByteCount < 2))
3007 /* BB also check enough total bytes returned */
3008 /* If rc should we check for EOPNOSUPP and
3009 disable the srvino flag? or in caller? */
3010 rc = -EIO; /* bad smb */
3011 else {
3012 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3013 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3014 struct file_chattr_info *pfinfo;
3015 /* BB Do we need a cast or hash here ? */
3016 if (count != 16) {
3017 cFYI(1, ("Illegal size ret in GetExtAttr"));
3018 rc = -EIO;
3019 goto GetExtAttrOut;
3020 }
3021 pfinfo = (struct file_chattr_info *)
3022 (data_offset + (char *) &pSMBr->hdr.Protocol);
3023 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003024 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003025 }
3026 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003027GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003028 cifs_buf_release(pSMB);
3029 if (rc == -EAGAIN)
3030 goto GetExtAttrRetry;
3031 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003032}
3033
Steve Frenchf654bac2005-04-28 22:41:04 -07003034#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035
Steve Frencheeac8042006-01-13 21:34:58 -08003036
3037/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01003038static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00003039 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08003040/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01003041static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00003042 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08003043
Steve French0a4b92c2006-01-12 15:44:21 -08003044/* Convert CIFS ACL to POSIX form */
Steve French50c2f752007-07-13 00:33:32 +00003045static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08003046{
Steve French0a4b92c2006-01-12 15:44:21 -08003047 return 0;
3048}
3049
3050/* Get Security Descriptor (by handle) from remote server for a file or dir */
3051int
3052CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French50c2f752007-07-13 00:33:32 +00003053 /* BB fix up return info */ char *acl_inf, const int buflen,
Steve French0a4b92c2006-01-12 15:44:21 -08003054 const int acl_type /* ACCESS/DEFAULT not sure implication */)
3055{
3056 int rc = 0;
3057 int buf_type = 0;
3058 QUERY_SEC_DESC_REQ * pSMB;
3059 struct kvec iov[1];
3060
3061 cFYI(1, ("GetCifsACL"));
3062
Steve French50c2f752007-07-13 00:33:32 +00003063 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003064 8 /* parm len */, tcon, (void **) &pSMB);
3065 if (rc)
3066 return rc;
3067
3068 pSMB->MaxParameterCount = cpu_to_le32(4);
3069 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3070 pSMB->MaxSetupCount = 0;
3071 pSMB->Fid = fid; /* file handle always le */
3072 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3073 CIFS_ACL_DACL);
3074 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3075 pSMB->hdr.smb_buf_length += 11;
3076 iov[0].iov_base = (char *)pSMB;
3077 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3078
3079 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3080 cifs_stats_inc(&tcon->num_acl_get);
3081 if (rc) {
3082 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3083 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003084 struct cifs_sid *psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003085 __le32 * parm;
3086 int parm_len;
3087 int data_len;
3088 int acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003089 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08003090
3091/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003092 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French0a4b92c2006-01-12 15:44:21 -08003093 (char **)&psec_desc,
3094 &parm_len, &data_len);
Steve French790fe572007-07-07 19:25:05 +00003095 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003096 goto qsec_out;
3097 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3098
Steve French50c2f752007-07-13 00:33:32 +00003099 cERROR(1, ("smb %p parm %p data %p",
3100 pSMBr, parm, psec_desc)); /* BB removeme BB */
Steve French0a4b92c2006-01-12 15:44:21 -08003101
3102 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3103 rc = -EIO; /* bad smb */
3104 goto qsec_out;
3105 }
3106
3107/* BB check that data area is minimum length and as big as acl_len */
3108
3109 acl_len = le32_to_cpu(*(__le32 *)parm);
Steve French790fe572007-07-07 19:25:05 +00003110 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003111
3112 parse_sec_desc(psec_desc, acl_len);
3113 }
3114qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003115 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003116 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003117 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003118 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003119/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003120 return rc;
3121}
3122
Steve French6b8edfe2005-08-23 20:26:03 -07003123/* Legacy Query Path Information call for lookup to old servers such
3124 as Win9x/WinME */
3125int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003126 const unsigned char *searchName,
3127 FILE_ALL_INFO *pFinfo,
3128 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003129{
3130 QUERY_INFORMATION_REQ * pSMB;
3131 QUERY_INFORMATION_RSP * pSMBr;
3132 int rc = 0;
3133 int bytes_returned;
3134 int name_len;
3135
Steve French50c2f752007-07-13 00:33:32 +00003136 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003137QInfRetry:
3138 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003139 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003140 if (rc)
3141 return rc;
3142
3143 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3144 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003145 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3146 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003147 name_len++; /* trailing null */
3148 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003149 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003150 name_len = strnlen(searchName, PATH_MAX);
3151 name_len++; /* trailing null */
3152 strncpy(pSMB->FileName, searchName, name_len);
3153 }
3154 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003155 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003156 pSMB->hdr.smb_buf_length += (__u16) name_len;
3157 pSMB->ByteCount = cpu_to_le16(name_len);
3158
3159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003161 if (rc) {
3162 cFYI(1, ("Send error in QueryInfo = %d", rc));
3163 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003164 struct timespec ts;
3165 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3166 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003167 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003168 ts.tv_nsec = 0;
3169 ts.tv_sec = time;
3170 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003171 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003172 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3173 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003174 pFinfo->AllocationSize =
3175 cpu_to_le64(le32_to_cpu(pSMBr->size));
3176 pFinfo->EndOfFile = pFinfo->AllocationSize;
3177 pFinfo->Attributes =
3178 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003179 } else
3180 rc = -EIO; /* bad buffer passed in */
3181
3182 cifs_buf_release(pSMB);
3183
3184 if (rc == -EAGAIN)
3185 goto QInfRetry;
3186
3187 return rc;
3188}
3189
3190
3191
3192
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193int
3194CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3195 const unsigned char *searchName,
3196 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003197 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003198 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199{
3200/* level 263 SMB_QUERY_FILE_ALL_INFO */
3201 TRANSACTION2_QPI_REQ *pSMB = NULL;
3202 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3203 int rc = 0;
3204 int bytes_returned;
3205 int name_len;
3206 __u16 params, byte_count;
3207
3208/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3209QPathInfoRetry:
3210 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3211 (void **) &pSMBr);
3212 if (rc)
3213 return rc;
3214
3215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3216 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003217 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003218 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 name_len++; /* trailing null */
3220 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003221 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 name_len = strnlen(searchName, PATH_MAX);
3223 name_len++; /* trailing null */
3224 strncpy(pSMB->FileName, searchName, name_len);
3225 }
3226
Steve French50c2f752007-07-13 00:33:32 +00003227 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 pSMB->TotalDataCount = 0;
3229 pSMB->MaxParameterCount = cpu_to_le16(2);
3230 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3231 pSMB->MaxSetupCount = 0;
3232 pSMB->Reserved = 0;
3233 pSMB->Flags = 0;
3234 pSMB->Timeout = 0;
3235 pSMB->Reserved2 = 0;
3236 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003237 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 pSMB->DataCount = 0;
3239 pSMB->DataOffset = 0;
3240 pSMB->SetupCount = 1;
3241 pSMB->Reserved3 = 0;
3242 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3243 byte_count = params + 1 /* pad */ ;
3244 pSMB->TotalParameterCount = cpu_to_le16(params);
3245 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003246 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003247 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3248 else
3249 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 pSMB->Reserved4 = 0;
3251 pSMB->hdr.smb_buf_length += byte_count;
3252 pSMB->ByteCount = cpu_to_le16(byte_count);
3253
3254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3256 if (rc) {
3257 cFYI(1, ("Send error in QPathInfo = %d", rc));
3258 } else { /* decode response */
3259 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3260
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003261 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3262 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003263 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003265 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003266 rc = -EIO; /* 24 or 26 expected but we do not read
3267 last field */
3268 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003269 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003271 if (legacy) /* we do not read the last field, EAsize,
3272 fortunately since it varies by subdialect
3273 and on Set vs. Get, is two bytes or 4
3274 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003275 size = sizeof(FILE_INFO_STANDARD);
3276 else
3277 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 memcpy((char *) pFindData,
3279 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003280 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 } else
3282 rc = -ENOMEM;
3283 }
3284 cifs_buf_release(pSMB);
3285 if (rc == -EAGAIN)
3286 goto QPathInfoRetry;
3287
3288 return rc;
3289}
3290
3291int
3292CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3293 const unsigned char *searchName,
3294 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003295 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296{
3297/* SMB_QUERY_FILE_UNIX_BASIC */
3298 TRANSACTION2_QPI_REQ *pSMB = NULL;
3299 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3300 int rc = 0;
3301 int bytes_returned = 0;
3302 int name_len;
3303 __u16 params, byte_count;
3304
3305 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3306UnixQPathInfoRetry:
3307 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3308 (void **) &pSMBr);
3309 if (rc)
3310 return rc;
3311
3312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3313 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003314 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003315 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 name_len++; /* trailing null */
3317 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003318 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 name_len = strnlen(searchName, PATH_MAX);
3320 name_len++; /* trailing null */
3321 strncpy(pSMB->FileName, searchName, name_len);
3322 }
3323
Steve French50c2f752007-07-13 00:33:32 +00003324 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 pSMB->TotalDataCount = 0;
3326 pSMB->MaxParameterCount = cpu_to_le16(2);
3327 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003328 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 pSMB->MaxSetupCount = 0;
3330 pSMB->Reserved = 0;
3331 pSMB->Flags = 0;
3332 pSMB->Timeout = 0;
3333 pSMB->Reserved2 = 0;
3334 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003335 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 pSMB->DataCount = 0;
3337 pSMB->DataOffset = 0;
3338 pSMB->SetupCount = 1;
3339 pSMB->Reserved3 = 0;
3340 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3341 byte_count = params + 1 /* pad */ ;
3342 pSMB->TotalParameterCount = cpu_to_le16(params);
3343 pSMB->ParameterCount = pSMB->TotalParameterCount;
3344 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3345 pSMB->Reserved4 = 0;
3346 pSMB->hdr.smb_buf_length += byte_count;
3347 pSMB->ByteCount = cpu_to_le16(byte_count);
3348
3349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3351 if (rc) {
3352 cFYI(1, ("Send error in QPathInfo = %d", rc));
3353 } else { /* decode response */
3354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3355
3356 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3357 rc = -EIO; /* bad smb */
3358 } else {
3359 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3360 memcpy((char *) pFindData,
3361 (char *) &pSMBr->hdr.Protocol +
3362 data_offset,
3363 sizeof (FILE_UNIX_BASIC_INFO));
3364 }
3365 }
3366 cifs_buf_release(pSMB);
3367 if (rc == -EAGAIN)
3368 goto UnixQPathInfoRetry;
3369
3370 return rc;
3371}
3372
3373#if 0 /* function unused at present */
3374int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3375 const char *searchName, FILE_ALL_INFO * findData,
3376 const struct nls_table *nls_codepage)
3377{
3378/* level 257 SMB_ */
3379 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3380 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3381 int rc = 0;
3382 int bytes_returned;
3383 int name_len;
3384 __u16 params, byte_count;
3385
3386 cFYI(1, ("In FindUnique"));
3387findUniqueRetry:
3388 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3389 (void **) &pSMBr);
3390 if (rc)
3391 return rc;
3392
3393 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3394 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003395 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3396 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 name_len++; /* trailing null */
3398 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003399 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 name_len = strnlen(searchName, PATH_MAX);
3401 name_len++; /* trailing null */
3402 strncpy(pSMB->FileName, searchName, name_len);
3403 }
3404
3405 params = 12 + name_len /* includes null */ ;
3406 pSMB->TotalDataCount = 0; /* no EAs */
3407 pSMB->MaxParameterCount = cpu_to_le16(2);
3408 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3409 pSMB->MaxSetupCount = 0;
3410 pSMB->Reserved = 0;
3411 pSMB->Flags = 0;
3412 pSMB->Timeout = 0;
3413 pSMB->Reserved2 = 0;
3414 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003415 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 pSMB->DataCount = 0;
3417 pSMB->DataOffset = 0;
3418 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3419 pSMB->Reserved3 = 0;
3420 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3421 byte_count = params + 1 /* pad */ ;
3422 pSMB->TotalParameterCount = cpu_to_le16(params);
3423 pSMB->ParameterCount = pSMB->TotalParameterCount;
3424 pSMB->SearchAttributes =
3425 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3426 ATTR_DIRECTORY);
3427 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3428 pSMB->SearchFlags = cpu_to_le16(1);
3429 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3430 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3431 pSMB->hdr.smb_buf_length += byte_count;
3432 pSMB->ByteCount = cpu_to_le16(byte_count);
3433
3434 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3435 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3436
3437 if (rc) {
3438 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3439 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003440 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 /* BB fill in */
3442 }
3443
3444 cifs_buf_release(pSMB);
3445 if (rc == -EAGAIN)
3446 goto findUniqueRetry;
3447
3448 return rc;
3449}
3450#endif /* end unused (temporarily) function */
3451
3452/* xid, tcon, searchName and codepage are input parms, rest are returned */
3453int
3454CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003455 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003457 __u16 *pnetfid,
3458 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459{
3460/* level 257 SMB_ */
3461 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3462 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3463 T2_FFIRST_RSP_PARMS * parms;
3464 int rc = 0;
3465 int bytes_returned = 0;
3466 int name_len;
3467 __u16 params, byte_count;
3468
Steve French50c2f752007-07-13 00:33:32 +00003469 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470
3471findFirstRetry:
3472 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3473 (void **) &pSMBr);
3474 if (rc)
3475 return rc;
3476
3477 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3478 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003479 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003480 PATH_MAX, nls_codepage, remap);
3481 /* We can not add the asterik earlier in case
3482 it got remapped to 0xF03A as if it were part of the
3483 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003485 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003486 pSMB->FileName[name_len+1] = 0;
3487 pSMB->FileName[name_len+2] = '*';
3488 pSMB->FileName[name_len+3] = 0;
3489 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3491 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003492 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 } else { /* BB add check for overrun of SMB buf BB */
3494 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003496 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 free buffer exit; BB */
3498 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003499 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003500 pSMB->FileName[name_len+1] = '*';
3501 pSMB->FileName[name_len+2] = 0;
3502 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 }
3504
3505 params = 12 + name_len /* includes null */ ;
3506 pSMB->TotalDataCount = 0; /* no EAs */
3507 pSMB->MaxParameterCount = cpu_to_le16(10);
3508 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3509 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3510 pSMB->MaxSetupCount = 0;
3511 pSMB->Reserved = 0;
3512 pSMB->Flags = 0;
3513 pSMB->Timeout = 0;
3514 pSMB->Reserved2 = 0;
3515 byte_count = params + 1 /* pad */ ;
3516 pSMB->TotalParameterCount = cpu_to_le16(params);
3517 pSMB->ParameterCount = pSMB->TotalParameterCount;
3518 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003519 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3520 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 pSMB->DataCount = 0;
3522 pSMB->DataOffset = 0;
3523 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3524 pSMB->Reserved3 = 0;
3525 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3526 pSMB->SearchAttributes =
3527 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3528 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003529 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3530 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 CIFS_SEARCH_RETURN_RESUME);
3532 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3533
3534 /* BB what should we set StorageType to? Does it matter? BB */
3535 pSMB->SearchStorageType = 0;
3536 pSMB->hdr.smb_buf_length += byte_count;
3537 pSMB->ByteCount = cpu_to_le16(byte_count);
3538
3539 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3540 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003541 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
Steve French88274812006-03-09 22:21:45 +00003543 if (rc) {/* BB add logic to retry regular search if Unix search
3544 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 /* BB Add code to handle unsupported level rc */
3546 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003547
Steve French88274812006-03-09 22:21:45 +00003548 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
3550 /* BB eventually could optimize out free and realloc of buf */
3551 /* for this case */
3552 if (rc == -EAGAIN)
3553 goto findFirstRetry;
3554 } else { /* decode response */
3555 /* BB remember to free buffer if error BB */
3556 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003557 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3559 psrch_inf->unicode = TRUE;
3560 else
3561 psrch_inf->unicode = FALSE;
3562
3563 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003564 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003565 psrch_inf->srch_entries_start =
3566 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3569 le16_to_cpu(pSMBr->t2.ParameterOffset));
3570
Steve French790fe572007-07-07 19:25:05 +00003571 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 psrch_inf->endOfSearch = TRUE;
3573 else
3574 psrch_inf->endOfSearch = FALSE;
3575
Steve French50c2f752007-07-13 00:33:32 +00003576 psrch_inf->entries_in_buffer =
3577 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003578 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 *pnetfid = parms->SearchHandle;
3581 } else {
3582 cifs_buf_release(pSMB);
3583 }
3584 }
3585
3586 return rc;
3587}
3588
3589int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003590 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591{
3592 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3593 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3594 T2_FNEXT_RSP_PARMS * parms;
3595 char *response_data;
3596 int rc = 0;
3597 int bytes_returned, name_len;
3598 __u16 params, byte_count;
3599
3600 cFYI(1, ("In FindNext"));
3601
Steve French790fe572007-07-07 19:25:05 +00003602 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 return -ENOENT;
3604
3605 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3606 (void **) &pSMBr);
3607 if (rc)
3608 return rc;
3609
Steve French50c2f752007-07-13 00:33:32 +00003610 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 byte_count = 0;
3612 pSMB->TotalDataCount = 0; /* no EAs */
3613 pSMB->MaxParameterCount = cpu_to_le16(8);
3614 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003615 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3616 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 pSMB->MaxSetupCount = 0;
3618 pSMB->Reserved = 0;
3619 pSMB->Flags = 0;
3620 pSMB->Timeout = 0;
3621 pSMB->Reserved2 = 0;
3622 pSMB->ParameterOffset = cpu_to_le16(
3623 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3624 pSMB->DataCount = 0;
3625 pSMB->DataOffset = 0;
3626 pSMB->SetupCount = 1;
3627 pSMB->Reserved3 = 0;
3628 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3629 pSMB->SearchHandle = searchHandle; /* always kept as le */
3630 pSMB->SearchCount =
3631 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3632 /* test for Unix extensions */
3633/* if (tcon->ses->capabilities & CAP_UNIX) {
3634 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3635 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3636 } else {
3637 pSMB->InformationLevel =
3638 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3639 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3640 } */
3641 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3642 pSMB->ResumeKey = psrch_inf->resume_key;
3643 pSMB->SearchFlags =
3644 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3645
3646 name_len = psrch_inf->resume_name_len;
3647 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003648 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3650 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003651 /* 14 byte parm len above enough for 2 byte null terminator */
3652 pSMB->ResumeFileName[name_len] = 0;
3653 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 } else {
3655 rc = -EINVAL;
3656 goto FNext2_err_exit;
3657 }
3658 byte_count = params + 1 /* pad */ ;
3659 pSMB->TotalParameterCount = cpu_to_le16(params);
3660 pSMB->ParameterCount = pSMB->TotalParameterCount;
3661 pSMB->hdr.smb_buf_length += byte_count;
3662 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003663
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3665 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003666 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 if (rc) {
3668 if (rc == -EBADF) {
3669 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003670 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 } else
3672 cFYI(1, ("FindNext returned = %d", rc));
3673 } else { /* decode response */
3674 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003675
Steve French790fe572007-07-07 19:25:05 +00003676 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 /* BB fixme add lock for file (srch_info) struct here */
3678 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3679 psrch_inf->unicode = TRUE;
3680 else
3681 psrch_inf->unicode = FALSE;
3682 response_data = (char *) &pSMBr->hdr.Protocol +
3683 le16_to_cpu(pSMBr->t2.ParameterOffset);
3684 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3685 response_data = (char *)&pSMBr->hdr.Protocol +
3686 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003687 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003688 cifs_small_buf_release(
3689 psrch_inf->ntwrk_buf_start);
3690 else
3691 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 psrch_inf->srch_entries_start = response_data;
3693 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003694 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003695 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 psrch_inf->endOfSearch = TRUE;
3697 else
3698 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003699 psrch_inf->entries_in_buffer =
3700 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 psrch_inf->index_of_last_entry +=
3702 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003703/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3704 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
3706 /* BB fixme add unlock here */
3707 }
3708
3709 }
3710
3711 /* BB On error, should we leave previous search buf (and count and
3712 last entry fields) intact or free the previous one? */
3713
3714 /* Note: On -EAGAIN error only caller can retry on handle based calls
3715 since file handle passed in no longer valid */
3716FNext2_err_exit:
3717 if (rc != 0)
3718 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 return rc;
3720}
3721
3722int
Steve French50c2f752007-07-13 00:33:32 +00003723CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3724 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725{
3726 int rc = 0;
3727 FINDCLOSE_REQ *pSMB = NULL;
3728 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3729 int bytes_returned;
3730
3731 cFYI(1, ("In CIFSSMBFindClose"));
3732 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3733
3734 /* no sense returning error if session restarted
3735 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003736 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 return 0;
3738 if (rc)
3739 return rc;
3740
3741 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3742 pSMB->FileID = searchHandle;
3743 pSMB->ByteCount = 0;
3744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3746 if (rc) {
3747 cERROR(1, ("Send error in FindClose = %d", rc));
3748 }
Steve Frencha4544342005-08-24 13:59:35 -07003749 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 cifs_small_buf_release(pSMB);
3751
3752 /* Since session is dead, search handle closed on server already */
3753 if (rc == -EAGAIN)
3754 rc = 0;
3755
3756 return rc;
3757}
3758
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759int
3760CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003761 const unsigned char *searchName,
3762 __u64 * inode_number,
3763 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764{
3765 int rc = 0;
3766 TRANSACTION2_QPI_REQ *pSMB = NULL;
3767 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3768 int name_len, bytes_returned;
3769 __u16 params, byte_count;
3770
Steve French50c2f752007-07-13 00:33:32 +00003771 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003772 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003773 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
3775GetInodeNumberRetry:
3776 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003777 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 if (rc)
3779 return rc;
3780
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3782 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003783 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003784 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 name_len++; /* trailing null */
3786 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003787 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 name_len = strnlen(searchName, PATH_MAX);
3789 name_len++; /* trailing null */
3790 strncpy(pSMB->FileName, searchName, name_len);
3791 }
3792
3793 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3794 pSMB->TotalDataCount = 0;
3795 pSMB->MaxParameterCount = cpu_to_le16(2);
3796 /* BB find exact max data count below from sess structure BB */
3797 pSMB->MaxDataCount = cpu_to_le16(4000);
3798 pSMB->MaxSetupCount = 0;
3799 pSMB->Reserved = 0;
3800 pSMB->Flags = 0;
3801 pSMB->Timeout = 0;
3802 pSMB->Reserved2 = 0;
3803 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003804 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 pSMB->DataCount = 0;
3806 pSMB->DataOffset = 0;
3807 pSMB->SetupCount = 1;
3808 pSMB->Reserved3 = 0;
3809 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3810 byte_count = params + 1 /* pad */ ;
3811 pSMB->TotalParameterCount = cpu_to_le16(params);
3812 pSMB->ParameterCount = pSMB->TotalParameterCount;
3813 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3814 pSMB->Reserved4 = 0;
3815 pSMB->hdr.smb_buf_length += byte_count;
3816 pSMB->ByteCount = cpu_to_le16(byte_count);
3817
3818 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3819 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3820 if (rc) {
3821 cFYI(1, ("error %d in QueryInternalInfo", rc));
3822 } else {
3823 /* decode response */
3824 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3825 if (rc || (pSMBr->ByteCount < 2))
3826 /* BB also check enough total bytes returned */
3827 /* If rc should we check for EOPNOSUPP and
3828 disable the srvino flag? or in caller? */
3829 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003830 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3832 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003833 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003835 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3837 rc = -EIO;
3838 goto GetInodeNumOut;
3839 }
3840 pfinfo = (struct file_internal_info *)
3841 (data_offset + (char *) &pSMBr->hdr.Protocol);
3842 *inode_number = pfinfo->UniqueId;
3843 }
3844 }
3845GetInodeNumOut:
3846 cifs_buf_release(pSMB);
3847 if (rc == -EAGAIN)
3848 goto GetInodeNumberRetry;
3849 return rc;
3850}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851
3852int
3853CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3854 const unsigned char *searchName,
3855 unsigned char **targetUNCs,
3856 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003857 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858{
3859/* TRANS2_GET_DFS_REFERRAL */
3860 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3861 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003862 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 int rc = 0;
3864 int bytes_returned;
3865 int name_len;
3866 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003867 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 __u16 params, byte_count;
3869 *number_of_UNC_in_array = 0;
3870 *targetUNCs = NULL;
3871
3872 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3873 if (ses == NULL)
3874 return -ENODEV;
3875getDFSRetry:
3876 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3877 (void **) &pSMBr);
3878 if (rc)
3879 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003880
3881 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003882 but should never be null here anyway */
3883 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 pSMB->hdr.Tid = ses->ipc_tid;
3885 pSMB->hdr.Uid = ses->Suid;
3886 if (ses->capabilities & CAP_STATUS32) {
3887 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3888 }
3889 if (ses->capabilities & CAP_DFS) {
3890 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3891 }
3892
3893 if (ses->capabilities & CAP_UNICODE) {
3894 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3895 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003896 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003897 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 name_len++; /* trailing null */
3899 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003900 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 name_len = strnlen(searchName, PATH_MAX);
3902 name_len++; /* trailing null */
3903 strncpy(pSMB->RequestFileName, searchName, name_len);
3904 }
3905
Steve French790fe572007-07-07 19:25:05 +00003906 if (ses->server) {
3907 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003908 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3909 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3910 }
3911
Steve French50c2f752007-07-13 00:33:32 +00003912 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003913
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 params = 2 /* level */ + name_len /*includes null */ ;
3915 pSMB->TotalDataCount = 0;
3916 pSMB->DataCount = 0;
3917 pSMB->DataOffset = 0;
3918 pSMB->MaxParameterCount = 0;
3919 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3920 pSMB->MaxSetupCount = 0;
3921 pSMB->Reserved = 0;
3922 pSMB->Flags = 0;
3923 pSMB->Timeout = 0;
3924 pSMB->Reserved2 = 0;
3925 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003926 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 pSMB->SetupCount = 1;
3928 pSMB->Reserved3 = 0;
3929 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3930 byte_count = params + 3 /* pad */ ;
3931 pSMB->ParameterCount = cpu_to_le16(params);
3932 pSMB->TotalParameterCount = pSMB->ParameterCount;
3933 pSMB->MaxReferralLevel = cpu_to_le16(3);
3934 pSMB->hdr.smb_buf_length += byte_count;
3935 pSMB->ByteCount = cpu_to_le16(byte_count);
3936
3937 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3939 if (rc) {
3940 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3941 } else { /* decode response */
3942/* BB Add logic to parse referrals here */
3943 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3944
Steve French50c2f752007-07-13 00:33:32 +00003945 /* BB Also check if enough total bytes returned? */
3946 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 rc = -EIO; /* bad smb */
3948 else {
Steve French50c2f752007-07-13 00:33:32 +00003949 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3951
3952 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003953 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003955 referrals =
3956 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 (8 /* sizeof start of data block */ +
3958 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003959 (char *) &pSMBr->hdr.Protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 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",
Steve French50c2f752007-07-13 00:33:32 +00003961 le16_to_cpu(pSMBr->NumberOfReferrals),
3962 le16_to_cpu(pSMBr->DFSFlags),
3963 le16_to_cpu(referrals->ReferralSize),
3964 le16_to_cpu(referrals->ServerType),
3965 le16_to_cpu(referrals->ReferralFlags),
3966 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 /* BB This field is actually two bytes in from start of
3968 data block so we could do safety check that DataBlock
3969 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003970 *number_of_UNC_in_array =
3971 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972
3973 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003974 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 *number_of_UNC_in_array = 1;
3976
3977 /* get the length of the strings describing refs */
3978 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003979 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003981 __u16 offset =
3982 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003984 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 not try to copy any more */
3986 *number_of_UNC_in_array = i;
3987 break;
Steve French50c2f752007-07-13 00:33:32 +00003988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 temp = ((char *)referrals) + offset;
3990
3991 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00003992 name_len += UniStrnlen((wchar_t *)temp,
3993 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 } else {
Steve French50c2f752007-07-13 00:33:32 +00003995 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 }
3997 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00003998 /* BB add check that referral pointer does
3999 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 }
4001 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004002 *targetUNCs =
4003 kmalloc(name_len+1+(*number_of_UNC_in_array),
4004 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004005 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 rc = -ENOMEM;
4007 goto GetDFSRefExit;
4008 }
4009 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004010 referrals = (struct dfs_referral_level_3 *)
4011 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 (char *) &pSMBr->hdr.Protocol);
4013
Steve French50c2f752007-07-13 00:33:32 +00004014 for (i = 0; i < *number_of_UNC_in_array; i++) {
4015 temp = ((char *)referrals) +
4016 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4018 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004019 (__le16 *) temp,
4020 name_len,
4021 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 } else {
Steve French50c2f752007-07-13 00:33:32 +00004023 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 }
4025 /* BB update target_uncs pointers */
4026 referrals++;
4027 }
4028 temp = *targetUNCs;
4029 temp[name_len] = 0;
4030 }
4031
4032 }
4033GetDFSRefExit:
4034 if (pSMB)
4035 cifs_buf_release(pSMB);
4036
4037 if (rc == -EAGAIN)
4038 goto getDFSRetry;
4039
4040 return rc;
4041}
4042
Steve French20962432005-09-21 22:05:57 -07004043/* Query File System Info such as free space to old servers such as Win 9x */
4044int
4045SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4046{
4047/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4048 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4049 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4050 FILE_SYSTEM_ALLOC_INFO *response_data;
4051 int rc = 0;
4052 int bytes_returned = 0;
4053 __u16 params, byte_count;
4054
4055 cFYI(1, ("OldQFSInfo"));
4056oldQFSInfoRetry:
4057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4058 (void **) &pSMBr);
4059 if (rc)
4060 return rc;
4061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4062 (void **) &pSMBr);
4063 if (rc)
4064 return rc;
4065
4066 params = 2; /* level */
4067 pSMB->TotalDataCount = 0;
4068 pSMB->MaxParameterCount = cpu_to_le16(2);
4069 pSMB->MaxDataCount = cpu_to_le16(1000);
4070 pSMB->MaxSetupCount = 0;
4071 pSMB->Reserved = 0;
4072 pSMB->Flags = 0;
4073 pSMB->Timeout = 0;
4074 pSMB->Reserved2 = 0;
4075 byte_count = params + 1 /* pad */ ;
4076 pSMB->TotalParameterCount = cpu_to_le16(params);
4077 pSMB->ParameterCount = pSMB->TotalParameterCount;
4078 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4079 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4080 pSMB->DataCount = 0;
4081 pSMB->DataOffset = 0;
4082 pSMB->SetupCount = 1;
4083 pSMB->Reserved3 = 0;
4084 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4085 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4086 pSMB->hdr.smb_buf_length += byte_count;
4087 pSMB->ByteCount = cpu_to_le16(byte_count);
4088
4089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091 if (rc) {
4092 cFYI(1, ("Send error in QFSInfo = %d", rc));
4093 } else { /* decode response */
4094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4095
4096 if (rc || (pSMBr->ByteCount < 18))
4097 rc = -EIO; /* bad smb */
4098 else {
4099 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004100 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004101 pSMBr->ByteCount, data_offset));
4102
Steve French50c2f752007-07-13 00:33:32 +00004103 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004104 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4105 FSData->f_bsize =
4106 le16_to_cpu(response_data->BytesPerSector) *
4107 le32_to_cpu(response_data->
4108 SectorsPerAllocationUnit);
4109 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004110 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004111 FSData->f_bfree = FSData->f_bavail =
4112 le32_to_cpu(response_data->FreeAllocationUnits);
4113 cFYI(1,
4114 ("Blocks: %lld Free: %lld Block size %ld",
4115 (unsigned long long)FSData->f_blocks,
4116 (unsigned long long)FSData->f_bfree,
4117 FSData->f_bsize));
4118 }
4119 }
4120 cifs_buf_release(pSMB);
4121
4122 if (rc == -EAGAIN)
4123 goto oldQFSInfoRetry;
4124
4125 return rc;
4126}
4127
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128int
Steve French737b7582005-04-28 22:41:06 -07004129CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130{
4131/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4132 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4133 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4134 FILE_SYSTEM_INFO *response_data;
4135 int rc = 0;
4136 int bytes_returned = 0;
4137 __u16 params, byte_count;
4138
4139 cFYI(1, ("In QFSInfo"));
4140QFSInfoRetry:
4141 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4142 (void **) &pSMBr);
4143 if (rc)
4144 return rc;
4145
4146 params = 2; /* level */
4147 pSMB->TotalDataCount = 0;
4148 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004149 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 pSMB->MaxSetupCount = 0;
4151 pSMB->Reserved = 0;
4152 pSMB->Flags = 0;
4153 pSMB->Timeout = 0;
4154 pSMB->Reserved2 = 0;
4155 byte_count = params + 1 /* pad */ ;
4156 pSMB->TotalParameterCount = cpu_to_le16(params);
4157 pSMB->ParameterCount = pSMB->TotalParameterCount;
4158 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004159 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 pSMB->DataCount = 0;
4161 pSMB->DataOffset = 0;
4162 pSMB->SetupCount = 1;
4163 pSMB->Reserved3 = 0;
4164 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4165 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4166 pSMB->hdr.smb_buf_length += byte_count;
4167 pSMB->ByteCount = cpu_to_le16(byte_count);
4168
4169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004172 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004174 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Steve French20962432005-09-21 22:05:57 -07004176 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 rc = -EIO; /* bad smb */
4178 else {
4179 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
4181 response_data =
4182 (FILE_SYSTEM_INFO
4183 *) (((char *) &pSMBr->hdr.Protocol) +
4184 data_offset);
4185 FSData->f_bsize =
4186 le32_to_cpu(response_data->BytesPerSector) *
4187 le32_to_cpu(response_data->
4188 SectorsPerAllocationUnit);
4189 FSData->f_blocks =
4190 le64_to_cpu(response_data->TotalAllocationUnits);
4191 FSData->f_bfree = FSData->f_bavail =
4192 le64_to_cpu(response_data->FreeAllocationUnits);
4193 cFYI(1,
4194 ("Blocks: %lld Free: %lld Block size %ld",
4195 (unsigned long long)FSData->f_blocks,
4196 (unsigned long long)FSData->f_bfree,
4197 FSData->f_bsize));
4198 }
4199 }
4200 cifs_buf_release(pSMB);
4201
4202 if (rc == -EAGAIN)
4203 goto QFSInfoRetry;
4204
4205 return rc;
4206}
4207
4208int
Steve French737b7582005-04-28 22:41:06 -07004209CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210{
4211/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4212 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4213 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4214 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4215 int rc = 0;
4216 int bytes_returned = 0;
4217 __u16 params, byte_count;
4218
4219 cFYI(1, ("In QFSAttributeInfo"));
4220QFSAttributeRetry:
4221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4222 (void **) &pSMBr);
4223 if (rc)
4224 return rc;
4225
4226 params = 2; /* level */
4227 pSMB->TotalDataCount = 0;
4228 pSMB->MaxParameterCount = cpu_to_le16(2);
4229 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4230 pSMB->MaxSetupCount = 0;
4231 pSMB->Reserved = 0;
4232 pSMB->Flags = 0;
4233 pSMB->Timeout = 0;
4234 pSMB->Reserved2 = 0;
4235 byte_count = params + 1 /* pad */ ;
4236 pSMB->TotalParameterCount = cpu_to_le16(params);
4237 pSMB->ParameterCount = pSMB->TotalParameterCount;
4238 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004239 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 pSMB->DataCount = 0;
4241 pSMB->DataOffset = 0;
4242 pSMB->SetupCount = 1;
4243 pSMB->Reserved3 = 0;
4244 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4245 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4246 pSMB->hdr.smb_buf_length += byte_count;
4247 pSMB->ByteCount = cpu_to_le16(byte_count);
4248
4249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4250 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4251 if (rc) {
4252 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4253 } else { /* decode response */
4254 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4255
Steve French50c2f752007-07-13 00:33:32 +00004256 if (rc || (pSMBr->ByteCount < 13)) {
4257 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 rc = -EIO; /* bad smb */
4259 } else {
4260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4261 response_data =
4262 (FILE_SYSTEM_ATTRIBUTE_INFO
4263 *) (((char *) &pSMBr->hdr.Protocol) +
4264 data_offset);
4265 memcpy(&tcon->fsAttrInfo, response_data,
4266 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4267 }
4268 }
4269 cifs_buf_release(pSMB);
4270
4271 if (rc == -EAGAIN)
4272 goto QFSAttributeRetry;
4273
4274 return rc;
4275}
4276
4277int
Steve French737b7582005-04-28 22:41:06 -07004278CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279{
4280/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4281 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4282 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4283 FILE_SYSTEM_DEVICE_INFO *response_data;
4284 int rc = 0;
4285 int bytes_returned = 0;
4286 __u16 params, byte_count;
4287
4288 cFYI(1, ("In QFSDeviceInfo"));
4289QFSDeviceRetry:
4290 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4291 (void **) &pSMBr);
4292 if (rc)
4293 return rc;
4294
4295 params = 2; /* level */
4296 pSMB->TotalDataCount = 0;
4297 pSMB->MaxParameterCount = cpu_to_le16(2);
4298 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4299 pSMB->MaxSetupCount = 0;
4300 pSMB->Reserved = 0;
4301 pSMB->Flags = 0;
4302 pSMB->Timeout = 0;
4303 pSMB->Reserved2 = 0;
4304 byte_count = params + 1 /* pad */ ;
4305 pSMB->TotalParameterCount = cpu_to_le16(params);
4306 pSMB->ParameterCount = pSMB->TotalParameterCount;
4307 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004308 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
4310 pSMB->DataCount = 0;
4311 pSMB->DataOffset = 0;
4312 pSMB->SetupCount = 1;
4313 pSMB->Reserved3 = 0;
4314 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4315 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4316 pSMB->hdr.smb_buf_length += byte_count;
4317 pSMB->ByteCount = cpu_to_le16(byte_count);
4318
4319 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4320 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4321 if (rc) {
4322 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4323 } else { /* decode response */
4324 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4325
4326 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4327 rc = -EIO; /* bad smb */
4328 else {
4329 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4330 response_data =
Steve French737b7582005-04-28 22:41:06 -07004331 (FILE_SYSTEM_DEVICE_INFO *)
4332 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 data_offset);
4334 memcpy(&tcon->fsDevInfo, response_data,
4335 sizeof (FILE_SYSTEM_DEVICE_INFO));
4336 }
4337 }
4338 cifs_buf_release(pSMB);
4339
4340 if (rc == -EAGAIN)
4341 goto QFSDeviceRetry;
4342
4343 return rc;
4344}
4345
4346int
Steve French737b7582005-04-28 22:41:06 -07004347CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348{
4349/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4350 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4351 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4352 FILE_SYSTEM_UNIX_INFO *response_data;
4353 int rc = 0;
4354 int bytes_returned = 0;
4355 __u16 params, byte_count;
4356
4357 cFYI(1, ("In QFSUnixInfo"));
4358QFSUnixRetry:
4359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4360 (void **) &pSMBr);
4361 if (rc)
4362 return rc;
4363
4364 params = 2; /* level */
4365 pSMB->TotalDataCount = 0;
4366 pSMB->DataCount = 0;
4367 pSMB->DataOffset = 0;
4368 pSMB->MaxParameterCount = cpu_to_le16(2);
4369 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4370 pSMB->MaxSetupCount = 0;
4371 pSMB->Reserved = 0;
4372 pSMB->Flags = 0;
4373 pSMB->Timeout = 0;
4374 pSMB->Reserved2 = 0;
4375 byte_count = params + 1 /* pad */ ;
4376 pSMB->ParameterCount = cpu_to_le16(params);
4377 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004378 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4379 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 pSMB->SetupCount = 1;
4381 pSMB->Reserved3 = 0;
4382 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4383 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4384 pSMB->hdr.smb_buf_length += byte_count;
4385 pSMB->ByteCount = cpu_to_le16(byte_count);
4386
4387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4388 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4389 if (rc) {
4390 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4391 } else { /* decode response */
4392 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4393
4394 if (rc || (pSMBr->ByteCount < 13)) {
4395 rc = -EIO; /* bad smb */
4396 } else {
4397 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4398 response_data =
4399 (FILE_SYSTEM_UNIX_INFO
4400 *) (((char *) &pSMBr->hdr.Protocol) +
4401 data_offset);
4402 memcpy(&tcon->fsUnixInfo, response_data,
4403 sizeof (FILE_SYSTEM_UNIX_INFO));
4404 }
4405 }
4406 cifs_buf_release(pSMB);
4407
4408 if (rc == -EAGAIN)
4409 goto QFSUnixRetry;
4410
4411
4412 return rc;
4413}
4414
Jeremy Allisonac670552005-06-22 17:26:35 -07004415int
Steve French45abc6e2005-06-23 13:42:03 -05004416CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004417{
4418/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4419 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4420 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4421 int rc = 0;
4422 int bytes_returned = 0;
4423 __u16 params, param_offset, offset, byte_count;
4424
4425 cFYI(1, ("In SETFSUnixInfo"));
4426SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004427 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429 (void **) &pSMBr);
4430 if (rc)
4431 return rc;
4432
4433 params = 4; /* 2 bytes zero followed by info level. */
4434 pSMB->MaxSetupCount = 0;
4435 pSMB->Reserved = 0;
4436 pSMB->Flags = 0;
4437 pSMB->Timeout = 0;
4438 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004439 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4440 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004441 offset = param_offset + params;
4442
4443 pSMB->MaxParameterCount = cpu_to_le16(4);
4444 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4445 pSMB->SetupCount = 1;
4446 pSMB->Reserved3 = 0;
4447 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4448 byte_count = 1 /* pad */ + params + 12;
4449
4450 pSMB->DataCount = cpu_to_le16(12);
4451 pSMB->ParameterCount = cpu_to_le16(params);
4452 pSMB->TotalDataCount = pSMB->DataCount;
4453 pSMB->TotalParameterCount = pSMB->ParameterCount;
4454 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4455 pSMB->DataOffset = cpu_to_le16(offset);
4456
4457 /* Params. */
4458 pSMB->FileNum = 0;
4459 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4460
4461 /* Data. */
4462 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4463 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4464 pSMB->ClientUnixCap = cpu_to_le64(cap);
4465
4466 pSMB->hdr.smb_buf_length += byte_count;
4467 pSMB->ByteCount = cpu_to_le16(byte_count);
4468
4469 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4470 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4471 if (rc) {
4472 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4473 } else { /* decode response */
4474 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4475 if (rc) {
4476 rc = -EIO; /* bad smb */
4477 }
4478 }
4479 cifs_buf_release(pSMB);
4480
4481 if (rc == -EAGAIN)
4482 goto SETFSUnixRetry;
4483
4484 return rc;
4485}
4486
4487
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488
4489int
4490CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004491 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492{
4493/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4494 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4495 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4496 FILE_SYSTEM_POSIX_INFO *response_data;
4497 int rc = 0;
4498 int bytes_returned = 0;
4499 __u16 params, byte_count;
4500
4501 cFYI(1, ("In QFSPosixInfo"));
4502QFSPosixRetry:
4503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4504 (void **) &pSMBr);
4505 if (rc)
4506 return rc;
4507
4508 params = 2; /* level */
4509 pSMB->TotalDataCount = 0;
4510 pSMB->DataCount = 0;
4511 pSMB->DataOffset = 0;
4512 pSMB->MaxParameterCount = cpu_to_le16(2);
4513 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4514 pSMB->MaxSetupCount = 0;
4515 pSMB->Reserved = 0;
4516 pSMB->Flags = 0;
4517 pSMB->Timeout = 0;
4518 pSMB->Reserved2 = 0;
4519 byte_count = params + 1 /* pad */ ;
4520 pSMB->ParameterCount = cpu_to_le16(params);
4521 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004522 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4523 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 pSMB->SetupCount = 1;
4525 pSMB->Reserved3 = 0;
4526 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4527 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4528 pSMB->hdr.smb_buf_length += byte_count;
4529 pSMB->ByteCount = cpu_to_le16(byte_count);
4530
4531 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4532 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4533 if (rc) {
4534 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4535 } else { /* decode response */
4536 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4537
4538 if (rc || (pSMBr->ByteCount < 13)) {
4539 rc = -EIO; /* bad smb */
4540 } else {
4541 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4542 response_data =
4543 (FILE_SYSTEM_POSIX_INFO
4544 *) (((char *) &pSMBr->hdr.Protocol) +
4545 data_offset);
4546 FSData->f_bsize =
4547 le32_to_cpu(response_data->BlockSize);
4548 FSData->f_blocks =
4549 le64_to_cpu(response_data->TotalBlocks);
4550 FSData->f_bfree =
4551 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004552 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 FSData->f_bavail = FSData->f_bfree;
4554 } else {
4555 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004556 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 }
Steve French790fe572007-07-07 19:25:05 +00004558 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004560 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004561 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004563 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 }
4565 }
4566 cifs_buf_release(pSMB);
4567
4568 if (rc == -EAGAIN)
4569 goto QFSPosixRetry;
4570
4571 return rc;
4572}
4573
4574
Steve French50c2f752007-07-13 00:33:32 +00004575/* We can not use write of zero bytes trick to
4576 set file size due to need for large file support. Also note that
4577 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 routine which is only needed to work around a sharing violation bug
4579 in Samba which this routine can run into */
4580
4581int
4582CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004583 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004584 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585{
4586 struct smb_com_transaction2_spi_req *pSMB = NULL;
4587 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4588 struct file_end_of_file_info *parm_data;
4589 int name_len;
4590 int rc = 0;
4591 int bytes_returned = 0;
4592 __u16 params, byte_count, data_count, param_offset, offset;
4593
4594 cFYI(1, ("In SetEOF"));
4595SetEOFRetry:
4596 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4597 (void **) &pSMBr);
4598 if (rc)
4599 return rc;
4600
4601 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4602 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004603 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004604 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 name_len++; /* trailing null */
4606 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004607 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 name_len = strnlen(fileName, PATH_MAX);
4609 name_len++; /* trailing null */
4610 strncpy(pSMB->FileName, fileName, name_len);
4611 }
4612 params = 6 + name_len;
4613 data_count = sizeof (struct file_end_of_file_info);
4614 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004615 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 pSMB->MaxSetupCount = 0;
4617 pSMB->Reserved = 0;
4618 pSMB->Flags = 0;
4619 pSMB->Timeout = 0;
4620 pSMB->Reserved2 = 0;
4621 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004622 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004624 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004625 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4626 pSMB->InformationLevel =
4627 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4628 else
4629 pSMB->InformationLevel =
4630 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4631 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4633 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004634 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 else
4636 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004637 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 }
4639
4640 parm_data =
4641 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4642 offset);
4643 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4644 pSMB->DataOffset = cpu_to_le16(offset);
4645 pSMB->SetupCount = 1;
4646 pSMB->Reserved3 = 0;
4647 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4648 byte_count = 3 /* pad */ + params + data_count;
4649 pSMB->DataCount = cpu_to_le16(data_count);
4650 pSMB->TotalDataCount = pSMB->DataCount;
4651 pSMB->ParameterCount = cpu_to_le16(params);
4652 pSMB->TotalParameterCount = pSMB->ParameterCount;
4653 pSMB->Reserved4 = 0;
4654 pSMB->hdr.smb_buf_length += byte_count;
4655 parm_data->FileSize = cpu_to_le64(size);
4656 pSMB->ByteCount = cpu_to_le16(byte_count);
4657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4659 if (rc) {
4660 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4661 }
4662
4663 cifs_buf_release(pSMB);
4664
4665 if (rc == -EAGAIN)
4666 goto SetEOFRetry;
4667
4668 return rc;
4669}
4670
4671int
Steve French50c2f752007-07-13 00:33:32 +00004672CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4673 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674{
4675 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4676 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4677 char *data_offset;
4678 struct file_end_of_file_info *parm_data;
4679 int rc = 0;
4680 int bytes_returned = 0;
4681 __u16 params, param_offset, offset, byte_count, count;
4682
4683 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4684 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004685 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4686
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 if (rc)
4688 return rc;
4689
Steve Frenchcd634992005-04-28 22:41:10 -07004690 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4691
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4693 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004694
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 params = 6;
4696 pSMB->MaxSetupCount = 0;
4697 pSMB->Reserved = 0;
4698 pSMB->Flags = 0;
4699 pSMB->Timeout = 0;
4700 pSMB->Reserved2 = 0;
4701 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4702 offset = param_offset + params;
4703
Steve French50c2f752007-07-13 00:33:32 +00004704 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705
4706 count = sizeof(struct file_end_of_file_info);
4707 pSMB->MaxParameterCount = cpu_to_le16(2);
4708 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4709 pSMB->SetupCount = 1;
4710 pSMB->Reserved3 = 0;
4711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4712 byte_count = 3 /* pad */ + params + count;
4713 pSMB->DataCount = cpu_to_le16(count);
4714 pSMB->ParameterCount = cpu_to_le16(params);
4715 pSMB->TotalDataCount = pSMB->DataCount;
4716 pSMB->TotalParameterCount = pSMB->ParameterCount;
4717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4718 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004719 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4720 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 pSMB->DataOffset = cpu_to_le16(offset);
4722 parm_data->FileSize = cpu_to_le64(size);
4723 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004724 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4726 pSMB->InformationLevel =
4727 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4728 else
4729 pSMB->InformationLevel =
4730 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004731 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004734 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 else
4736 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004737 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 }
4739 pSMB->Reserved4 = 0;
4740 pSMB->hdr.smb_buf_length += byte_count;
4741 pSMB->ByteCount = cpu_to_le16(byte_count);
4742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4744 if (rc) {
4745 cFYI(1,
4746 ("Send error in SetFileInfo (SetFileSize) = %d",
4747 rc));
4748 }
4749
4750 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004751 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752
Steve French50c2f752007-07-13 00:33:32 +00004753 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 since file handle passed in no longer valid */
4755
4756 return rc;
4757}
4758
Steve French50c2f752007-07-13 00:33:32 +00004759/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 an open handle, rather than by pathname - this is awkward due to
4761 potential access conflicts on the open, but it is unavoidable for these
4762 old servers since the only other choice is to go from 100 nanosecond DCE
4763 time and resort to the original setpathinfo level which takes the ancient
4764 DOS time format with 2 second granularity */
4765int
Steve French50c2f752007-07-13 00:33:32 +00004766CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4767 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
4769 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4770 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4771 char *data_offset;
4772 int rc = 0;
4773 int bytes_returned = 0;
4774 __u16 params, param_offset, offset, byte_count, count;
4775
4776 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004777 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4778
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 if (rc)
4780 return rc;
4781
Steve Frenchcd634992005-04-28 22:41:10 -07004782 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4783
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 /* At this point there is no need to override the current pid
4785 with the pid of the opener, but that could change if we someday
4786 use an existing handle (rather than opening one on the fly) */
4787 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4788 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004789
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 params = 6;
4791 pSMB->MaxSetupCount = 0;
4792 pSMB->Reserved = 0;
4793 pSMB->Flags = 0;
4794 pSMB->Timeout = 0;
4795 pSMB->Reserved2 = 0;
4796 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4797 offset = param_offset + params;
4798
Steve French50c2f752007-07-13 00:33:32 +00004799 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800
4801 count = sizeof (FILE_BASIC_INFO);
4802 pSMB->MaxParameterCount = cpu_to_le16(2);
4803 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4804 pSMB->SetupCount = 1;
4805 pSMB->Reserved3 = 0;
4806 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4807 byte_count = 3 /* pad */ + params + count;
4808 pSMB->DataCount = cpu_to_le16(count);
4809 pSMB->ParameterCount = cpu_to_le16(params);
4810 pSMB->TotalDataCount = pSMB->DataCount;
4811 pSMB->TotalParameterCount = pSMB->ParameterCount;
4812 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4813 pSMB->DataOffset = cpu_to_le16(offset);
4814 pSMB->Fid = fid;
4815 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4816 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4817 else
4818 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4819 pSMB->Reserved4 = 0;
4820 pSMB->hdr.smb_buf_length += byte_count;
4821 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004822 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4824 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4825 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004826 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 }
4828
Steve Frenchcd634992005-04-28 22:41:10 -07004829 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830
Steve French50c2f752007-07-13 00:33:32 +00004831 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 since file handle passed in no longer valid */
4833
4834 return rc;
4835}
4836
4837
4838int
4839CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004840 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004841 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842{
4843 TRANSACTION2_SPI_REQ *pSMB = NULL;
4844 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4845 int name_len;
4846 int rc = 0;
4847 int bytes_returned = 0;
4848 char *data_offset;
4849 __u16 params, param_offset, offset, byte_count, count;
4850
4851 cFYI(1, ("In SetTimes"));
4852
4853SetTimesRetry:
4854 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4855 (void **) &pSMBr);
4856 if (rc)
4857 return rc;
4858
4859 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4860 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004861 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004862 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 name_len++; /* trailing null */
4864 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004865 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 name_len = strnlen(fileName, PATH_MAX);
4867 name_len++; /* trailing null */
4868 strncpy(pSMB->FileName, fileName, name_len);
4869 }
4870
4871 params = 6 + name_len;
4872 count = sizeof (FILE_BASIC_INFO);
4873 pSMB->MaxParameterCount = cpu_to_le16(2);
4874 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4875 pSMB->MaxSetupCount = 0;
4876 pSMB->Reserved = 0;
4877 pSMB->Flags = 0;
4878 pSMB->Timeout = 0;
4879 pSMB->Reserved2 = 0;
4880 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004881 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 offset = param_offset + params;
4883 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4884 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4885 pSMB->DataOffset = cpu_to_le16(offset);
4886 pSMB->SetupCount = 1;
4887 pSMB->Reserved3 = 0;
4888 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4889 byte_count = 3 /* pad */ + params + count;
4890
4891 pSMB->DataCount = cpu_to_le16(count);
4892 pSMB->ParameterCount = cpu_to_le16(params);
4893 pSMB->TotalDataCount = pSMB->DataCount;
4894 pSMB->TotalParameterCount = pSMB->ParameterCount;
4895 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4896 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4897 else
4898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4899 pSMB->Reserved4 = 0;
4900 pSMB->hdr.smb_buf_length += byte_count;
4901 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4902 pSMB->ByteCount = cpu_to_le16(byte_count);
4903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4905 if (rc) {
4906 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4907 }
4908
4909 cifs_buf_release(pSMB);
4910
4911 if (rc == -EAGAIN)
4912 goto SetTimesRetry;
4913
4914 return rc;
4915}
4916
4917/* Can not be used to set time stamps yet (due to old DOS time format) */
4918/* Can be used to set attributes */
4919#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4920 handling it anyway and NT4 was what we thought it would be needed for
4921 Do not delete it until we prove whether needed for Win9x though */
4922int
4923CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4924 __u16 dos_attrs, const struct nls_table *nls_codepage)
4925{
4926 SETATTR_REQ *pSMB = NULL;
4927 SETATTR_RSP *pSMBr = NULL;
4928 int rc = 0;
4929 int bytes_returned;
4930 int name_len;
4931
4932 cFYI(1, ("In SetAttrLegacy"));
4933
4934SetAttrLgcyRetry:
4935 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4936 (void **) &pSMBr);
4937 if (rc)
4938 return rc;
4939
4940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4941 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004942 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 PATH_MAX, nls_codepage);
4944 name_len++; /* trailing null */
4945 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004946 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 name_len = strnlen(fileName, PATH_MAX);
4948 name_len++; /* trailing null */
4949 strncpy(pSMB->fileName, fileName, name_len);
4950 }
4951 pSMB->attr = cpu_to_le16(dos_attrs);
4952 pSMB->BufferFormat = 0x04;
4953 pSMB->hdr.smb_buf_length += name_len + 1;
4954 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4957 if (rc) {
4958 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4959 }
4960
4961 cifs_buf_release(pSMB);
4962
4963 if (rc == -EAGAIN)
4964 goto SetAttrLgcyRetry;
4965
4966 return rc;
4967}
4968#endif /* temporarily unneeded SetAttr legacy function */
4969
4970int
4971CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004972 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4973 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004974 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975{
4976 TRANSACTION2_SPI_REQ *pSMB = NULL;
4977 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4978 int name_len;
4979 int rc = 0;
4980 int bytes_returned = 0;
4981 FILE_UNIX_BASIC_INFO *data_offset;
4982 __u16 params, param_offset, offset, count, byte_count;
4983
4984 cFYI(1, ("In SetUID/GID/Mode"));
4985setPermsRetry:
4986 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4987 (void **) &pSMBr);
4988 if (rc)
4989 return rc;
4990
4991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4992 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004993 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004994 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 name_len++; /* trailing null */
4996 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004997 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 name_len = strnlen(fileName, PATH_MAX);
4999 name_len++; /* trailing null */
5000 strncpy(pSMB->FileName, fileName, name_len);
5001 }
5002
5003 params = 6 + name_len;
5004 count = sizeof (FILE_UNIX_BASIC_INFO);
5005 pSMB->MaxParameterCount = cpu_to_le16(2);
5006 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5007 pSMB->MaxSetupCount = 0;
5008 pSMB->Reserved = 0;
5009 pSMB->Flags = 0;
5010 pSMB->Timeout = 0;
5011 pSMB->Reserved2 = 0;
5012 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005013 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 offset = param_offset + params;
5015 data_offset =
5016 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5017 offset);
5018 memset(data_offset, 0, count);
5019 pSMB->DataOffset = cpu_to_le16(offset);
5020 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5021 pSMB->SetupCount = 1;
5022 pSMB->Reserved3 = 0;
5023 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5024 byte_count = 3 /* pad */ + params + count;
5025 pSMB->ParameterCount = cpu_to_le16(params);
5026 pSMB->DataCount = cpu_to_le16(count);
5027 pSMB->TotalParameterCount = pSMB->ParameterCount;
5028 pSMB->TotalDataCount = pSMB->DataCount;
5029 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5030 pSMB->Reserved4 = 0;
5031 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005032 /* Samba server ignores set of file size to zero due to bugs in some
5033 older clients, but we should be precise - we use SetFileSize to
5034 set file size and do not want to truncate file size to zero
5035 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005036 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005037 data_offset->EndOfFile = NO_CHANGE_64;
5038 data_offset->NumOfBytes = NO_CHANGE_64;
5039 data_offset->LastStatusChange = NO_CHANGE_64;
5040 data_offset->LastAccessTime = NO_CHANGE_64;
5041 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 data_offset->Uid = cpu_to_le64(uid);
5043 data_offset->Gid = cpu_to_le64(gid);
5044 /* better to leave device as zero when it is */
5045 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5046 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5047 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005048
Steve French790fe572007-07-07 19:25:05 +00005049 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005051 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005053 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005055 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005057 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005059 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005061 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5063
5064
5065 pSMB->ByteCount = cpu_to_le16(byte_count);
5066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5067 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5068 if (rc) {
5069 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5070 }
5071
5072 if (pSMB)
5073 cifs_buf_release(pSMB);
5074 if (rc == -EAGAIN)
5075 goto setPermsRetry;
5076 return rc;
5077}
5078
Steve French50c2f752007-07-13 00:33:32 +00005079int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005080 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005081 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005082 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083{
5084 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005085 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5086 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005087 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 int bytes_returned;
5089
Steve French50c2f752007-07-13 00:33:32 +00005090 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005092 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 if (rc)
5094 return rc;
5095
5096 pSMB->TotalParameterCount = 0 ;
5097 pSMB->TotalDataCount = 0;
5098 pSMB->MaxParameterCount = cpu_to_le32(2);
5099 /* BB find exact data count max from sess structure BB */
5100 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005101/* BB VERIFY verify which is correct for above BB */
5102 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5103 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5104
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 pSMB->MaxSetupCount = 4;
5106 pSMB->Reserved = 0;
5107 pSMB->ParameterOffset = 0;
5108 pSMB->DataCount = 0;
5109 pSMB->DataOffset = 0;
5110 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5111 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5112 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005113 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5115 pSMB->Reserved2 = 0;
5116 pSMB->CompletionFilter = cpu_to_le32(filter);
5117 pSMB->Fid = netfid; /* file handle always le */
5118 pSMB->ByteCount = 0;
5119
5120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5121 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5122 if (rc) {
5123 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005124 } else {
5125 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005126 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005127 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005128 sizeof(struct dir_notify_req),
5129 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005130 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005131 dnotify_req->Pid = pSMB->hdr.Pid;
5132 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5133 dnotify_req->Mid = pSMB->hdr.Mid;
5134 dnotify_req->Tid = pSMB->hdr.Tid;
5135 dnotify_req->Uid = pSMB->hdr.Uid;
5136 dnotify_req->netfid = netfid;
5137 dnotify_req->pfile = pfile;
5138 dnotify_req->filter = filter;
5139 dnotify_req->multishot = multishot;
5140 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005141 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005142 &GlobalDnotifyReqList);
5143 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005144 } else
Steve French47c786e2005-10-11 20:03:18 -07005145 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 }
5147 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005148 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149}
5150#ifdef CONFIG_CIFS_XATTR
5151ssize_t
5152CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5153 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005154 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005155 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156{
5157 /* BB assumes one setup word */
5158 TRANSACTION2_QPI_REQ *pSMB = NULL;
5159 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5160 int rc = 0;
5161 int bytes_returned;
5162 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005163 struct fea *temp_fea;
5164 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 __u16 params, byte_count;
5166
5167 cFYI(1, ("In Query All EAs path %s", searchName));
5168QAllEAsRetry:
5169 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5170 (void **) &pSMBr);
5171 if (rc)
5172 return rc;
5173
5174 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5175 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005176 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005177 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 name_len++; /* trailing null */
5179 name_len *= 2;
5180 } else { /* BB improve the check for buffer overruns BB */
5181 name_len = strnlen(searchName, PATH_MAX);
5182 name_len++; /* trailing null */
5183 strncpy(pSMB->FileName, searchName, name_len);
5184 }
5185
Steve French50c2f752007-07-13 00:33:32 +00005186 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 pSMB->TotalDataCount = 0;
5188 pSMB->MaxParameterCount = cpu_to_le16(2);
5189 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5190 pSMB->MaxSetupCount = 0;
5191 pSMB->Reserved = 0;
5192 pSMB->Flags = 0;
5193 pSMB->Timeout = 0;
5194 pSMB->Reserved2 = 0;
5195 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005196 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 pSMB->DataCount = 0;
5198 pSMB->DataOffset = 0;
5199 pSMB->SetupCount = 1;
5200 pSMB->Reserved3 = 0;
5201 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5202 byte_count = params + 1 /* pad */ ;
5203 pSMB->TotalParameterCount = cpu_to_le16(params);
5204 pSMB->ParameterCount = pSMB->TotalParameterCount;
5205 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5206 pSMB->Reserved4 = 0;
5207 pSMB->hdr.smb_buf_length += byte_count;
5208 pSMB->ByteCount = cpu_to_le16(byte_count);
5209
5210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5212 if (rc) {
5213 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5214 } else { /* decode response */
5215 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5216
5217 /* BB also check enough total bytes returned */
5218 /* BB we need to improve the validity checking
5219 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005220 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 rc = -EIO; /* bad smb */
5222 /* else if (pFindData){
5223 memcpy((char *) pFindData,
5224 (char *) &pSMBr->hdr.Protocol +
5225 data_offset, kl);
5226 }*/ else {
5227 /* check that length of list is not more than bcc */
5228 /* check that each entry does not go beyond length
5229 of list */
5230 /* check that each element of each entry does not
5231 go beyond end of list */
5232 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005233 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 rc = 0;
5235 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005236 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 ea_response_data = (struct fealist *)
5238 (((char *) &pSMBr->hdr.Protocol) +
5239 data_offset);
5240 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005241 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005242 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005244 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 } else {
5246 /* account for ea list len */
5247 name_len -= 4;
5248 temp_fea = ea_response_data->list;
5249 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005250 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 __u16 value_len;
5252 name_len -= 4;
5253 temp_ptr += 4;
5254 rc += temp_fea->name_len;
5255 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005256 rc = rc + 5 + 1;
5257 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005258 memcpy(EAData, "user.", 5);
5259 EAData += 5;
5260 memcpy(EAData, temp_ptr,
5261 temp_fea->name_len);
5262 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 /* null terminate name */
5264 *EAData = 0;
5265 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005266 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 /* skip copy - calc size only */
5268 } else {
5269 /* stop before overrun buffer */
5270 rc = -ERANGE;
5271 break;
5272 }
5273 name_len -= temp_fea->name_len;
5274 temp_ptr += temp_fea->name_len;
5275 /* account for trailing null */
5276 name_len--;
5277 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005278 value_len =
5279 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 name_len -= value_len;
5281 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005282 /* BB check that temp_ptr is still
5283 within the SMB BB*/
5284
5285 /* no trailing null to account for
5286 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 /* go on to next EA */
5288 temp_fea = (struct fea *)temp_ptr;
5289 }
5290 }
5291 }
5292 }
5293 if (pSMB)
5294 cifs_buf_release(pSMB);
5295 if (rc == -EAGAIN)
5296 goto QAllEAsRetry;
5297
5298 return (ssize_t)rc;
5299}
5300
Steve French50c2f752007-07-13 00:33:32 +00005301ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5302 const unsigned char *searchName, const unsigned char *ea_name,
5303 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005304 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305{
5306 TRANSACTION2_QPI_REQ *pSMB = NULL;
5307 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5308 int rc = 0;
5309 int bytes_returned;
5310 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005311 struct fea *temp_fea;
5312 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 __u16 params, byte_count;
5314
5315 cFYI(1, ("In Query EA path %s", searchName));
5316QEARetry:
5317 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5318 (void **) &pSMBr);
5319 if (rc)
5320 return rc;
5321
5322 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5323 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005324 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005325 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 name_len++; /* trailing null */
5327 name_len *= 2;
5328 } else { /* BB improve the check for buffer overruns BB */
5329 name_len = strnlen(searchName, PATH_MAX);
5330 name_len++; /* trailing null */
5331 strncpy(pSMB->FileName, searchName, name_len);
5332 }
5333
Steve French50c2f752007-07-13 00:33:32 +00005334 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 pSMB->TotalDataCount = 0;
5336 pSMB->MaxParameterCount = cpu_to_le16(2);
5337 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5338 pSMB->MaxSetupCount = 0;
5339 pSMB->Reserved = 0;
5340 pSMB->Flags = 0;
5341 pSMB->Timeout = 0;
5342 pSMB->Reserved2 = 0;
5343 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005344 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 pSMB->DataCount = 0;
5346 pSMB->DataOffset = 0;
5347 pSMB->SetupCount = 1;
5348 pSMB->Reserved3 = 0;
5349 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5350 byte_count = params + 1 /* pad */ ;
5351 pSMB->TotalParameterCount = cpu_to_le16(params);
5352 pSMB->ParameterCount = pSMB->TotalParameterCount;
5353 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5354 pSMB->Reserved4 = 0;
5355 pSMB->hdr.smb_buf_length += byte_count;
5356 pSMB->ByteCount = cpu_to_le16(byte_count);
5357
5358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5360 if (rc) {
5361 cFYI(1, ("Send error in Query EA = %d", rc));
5362 } else { /* decode response */
5363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5364
5365 /* BB also check enough total bytes returned */
5366 /* BB we need to improve the validity checking
5367 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005368 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 rc = -EIO; /* bad smb */
5370 /* else if (pFindData){
5371 memcpy((char *) pFindData,
5372 (char *) &pSMBr->hdr.Protocol +
5373 data_offset, kl);
5374 }*/ else {
5375 /* check that length of list is not more than bcc */
5376 /* check that each entry does not go beyond length
5377 of list */
5378 /* check that each element of each entry does not
5379 go beyond end of list */
5380 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005381 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 rc = -ENODATA;
5383 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005384 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 ea_response_data = (struct fealist *)
5386 (((char *) &pSMBr->hdr.Protocol) +
5387 data_offset);
5388 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005389 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005390 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005392 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 } else {
5394 /* account for ea list len */
5395 name_len -= 4;
5396 temp_fea = ea_response_data->list;
5397 temp_ptr = (char *)temp_fea;
5398 /* loop through checking if we have a matching
5399 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005400 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 __u16 value_len;
5402 name_len -= 4;
5403 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005404 value_len =
5405 le16_to_cpu(temp_fea->value_len);
5406 /* BB validate that value_len falls within SMB,
5407 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005408 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 temp_fea->name_len) == 0) {
5410 /* found a match */
5411 rc = value_len;
5412 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005413 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 memcpy(ea_value,
5415 temp_fea->name+temp_fea->name_len+1,
5416 rc);
Steve French50c2f752007-07-13 00:33:32 +00005417 /* ea values, unlike ea
5418 names, are not null
5419 terminated */
Steve French790fe572007-07-07 19:25:05 +00005420 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 /* skip copy - calc size only */
5422 } else {
Steve French50c2f752007-07-13 00:33:32 +00005423 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 rc = -ERANGE;
5425 }
5426 break;
5427 }
5428 name_len -= temp_fea->name_len;
5429 temp_ptr += temp_fea->name_len;
5430 /* account for trailing null */
5431 name_len--;
5432 temp_ptr++;
5433 name_len -= value_len;
5434 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005435 /* No trailing null to account for in
5436 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 temp_fea = (struct fea *)temp_ptr;
5438 }
Steve French50c2f752007-07-13 00:33:32 +00005439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 }
5441 }
5442 if (pSMB)
5443 cifs_buf_release(pSMB);
5444 if (rc == -EAGAIN)
5445 goto QEARetry;
5446
5447 return (ssize_t)rc;
5448}
5449
5450int
5451CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005452 const char *ea_name, const void *ea_value,
5453 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5454 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455{
5456 struct smb_com_transaction2_spi_req *pSMB = NULL;
5457 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5458 struct fealist *parm_data;
5459 int name_len;
5460 int rc = 0;
5461 int bytes_returned = 0;
5462 __u16 params, param_offset, byte_count, offset, count;
5463
5464 cFYI(1, ("In SetEA"));
5465SetEARetry:
5466 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5467 (void **) &pSMBr);
5468 if (rc)
5469 return rc;
5470
5471 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5472 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005473 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005474 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 name_len++; /* trailing null */
5476 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005477 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 name_len = strnlen(fileName, PATH_MAX);
5479 name_len++; /* trailing null */
5480 strncpy(pSMB->FileName, fileName, name_len);
5481 }
5482
5483 params = 6 + name_len;
5484
5485 /* done calculating parms using name_len of file name,
5486 now use name_len to calculate length of ea name
5487 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005488 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 name_len = 0;
5490 else
Steve French50c2f752007-07-13 00:33:32 +00005491 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492
5493 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5494 pSMB->MaxParameterCount = cpu_to_le16(2);
5495 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5496 pSMB->MaxSetupCount = 0;
5497 pSMB->Reserved = 0;
5498 pSMB->Flags = 0;
5499 pSMB->Timeout = 0;
5500 pSMB->Reserved2 = 0;
5501 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005502 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 offset = param_offset + params;
5504 pSMB->InformationLevel =
5505 cpu_to_le16(SMB_SET_FILE_EA);
5506
5507 parm_data =
5508 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5509 offset);
5510 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5511 pSMB->DataOffset = cpu_to_le16(offset);
5512 pSMB->SetupCount = 1;
5513 pSMB->Reserved3 = 0;
5514 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5515 byte_count = 3 /* pad */ + params + count;
5516 pSMB->DataCount = cpu_to_le16(count);
5517 parm_data->list_len = cpu_to_le32(count);
5518 parm_data->list[0].EA_flags = 0;
5519 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005520 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005522 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005523 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 parm_data->list[0].name[name_len] = 0;
5525 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5526 /* caller ensures that ea_value_len is less than 64K but
5527 we need to ensure that it fits within the smb */
5528
Steve French50c2f752007-07-13 00:33:32 +00005529 /*BB add length check to see if it would fit in
5530 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005531 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5532 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005533 memcpy(parm_data->list[0].name+name_len+1,
5534 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535
5536 pSMB->TotalDataCount = pSMB->DataCount;
5537 pSMB->ParameterCount = cpu_to_le16(params);
5538 pSMB->TotalParameterCount = pSMB->ParameterCount;
5539 pSMB->Reserved4 = 0;
5540 pSMB->hdr.smb_buf_length += byte_count;
5541 pSMB->ByteCount = cpu_to_le16(byte_count);
5542 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5543 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5544 if (rc) {
5545 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5546 }
5547
5548 cifs_buf_release(pSMB);
5549
5550 if (rc == -EAGAIN)
5551 goto SetEARetry;
5552
5553 return rc;
5554}
5555
5556#endif