blob: 3ab78b77697723028499f51705de965c99fff16e [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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-10-02 05:53:29 +0000513 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000514 if (val < 0)
Steve Frenchb815f1e52006-10-02 05:53:29 +0000515 result = - result;
516 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000517 } else {
Steve Frenchb815f1e52006-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 Frenchb815f1e52006-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 French737b7582005-04-28 22:41:06 -0700792CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
793 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
795 DELETE_FILE_REQ *pSMB = NULL;
796 DELETE_FILE_RSP *pSMBr = NULL;
797 int rc = 0;
798 int bytes_returned;
799 int name_len;
800
801DelFileRetry:
802 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
803 (void **) &pSMBr);
804 if (rc)
805 return rc;
806
807 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
808 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000809 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700810 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 name_len++; /* trailing null */
812 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700813 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 name_len = strnlen(fileName, PATH_MAX);
815 name_len++; /* trailing null */
816 strncpy(pSMB->fileName, fileName, name_len);
817 }
818 pSMB->SearchAttributes =
819 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
820 pSMB->BufferFormat = 0x04;
821 pSMB->hdr.smb_buf_length += name_len + 1;
822 pSMB->ByteCount = cpu_to_le16(name_len + 1);
823 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
824 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700825 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (rc) {
827 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 cifs_buf_release(pSMB);
831 if (rc == -EAGAIN)
832 goto DelFileRetry;
833
834 return rc;
835}
836
837int
Steve French50c2f752007-07-13 00:33:32 +0000838CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700839 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840{
841 DELETE_DIRECTORY_REQ *pSMB = NULL;
842 DELETE_DIRECTORY_RSP *pSMBr = NULL;
843 int rc = 0;
844 int bytes_returned;
845 int name_len;
846
847 cFYI(1, ("In CIFSSMBRmDir"));
848RmDirRetry:
849 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
850 (void **) &pSMBr);
851 if (rc)
852 return rc;
853
854 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700855 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
856 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 name_len++; /* trailing null */
858 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700859 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 name_len = strnlen(dirName, PATH_MAX);
861 name_len++; /* trailing null */
862 strncpy(pSMB->DirName, dirName, name_len);
863 }
864
865 pSMB->BufferFormat = 0x04;
866 pSMB->hdr.smb_buf_length += name_len + 1;
867 pSMB->ByteCount = cpu_to_le16(name_len + 1);
868 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700870 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 if (rc) {
872 cFYI(1, ("Error in RMDir = %d", rc));
873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875 cifs_buf_release(pSMB);
876 if (rc == -EAGAIN)
877 goto RmDirRetry;
878 return rc;
879}
880
881int
882CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700883 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 int rc = 0;
886 CREATE_DIRECTORY_REQ *pSMB = NULL;
887 CREATE_DIRECTORY_RSP *pSMBr = NULL;
888 int bytes_returned;
889 int name_len;
890
891 cFYI(1, ("In CIFSSMBMkDir"));
892MkDirRetry:
893 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
894 (void **) &pSMBr);
895 if (rc)
896 return rc;
897
898 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000899 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700900 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len++; /* trailing null */
902 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700903 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 name_len = strnlen(name, PATH_MAX);
905 name_len++; /* trailing null */
906 strncpy(pSMB->DirName, name, name_len);
907 }
908
909 pSMB->BufferFormat = 0x04;
910 pSMB->hdr.smb_buf_length += name_len + 1;
911 pSMB->ByteCount = cpu_to_le16(name_len + 1);
912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700914 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 if (rc) {
916 cFYI(1, ("Error in Mkdir = %d", rc));
917 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700918
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 cifs_buf_release(pSMB);
920 if (rc == -EAGAIN)
921 goto MkDirRetry;
922 return rc;
923}
924
Steve French2dd29d32007-04-23 22:07:35 +0000925int
926CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
927 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000928 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000929 const struct nls_table *nls_codepage, int remap)
930{
931 TRANSACTION2_SPI_REQ *pSMB = NULL;
932 TRANSACTION2_SPI_RSP *pSMBr = NULL;
933 int name_len;
934 int rc = 0;
935 int bytes_returned = 0;
936 char *data_offset;
937 __u16 params, param_offset, offset, byte_count, count;
938 OPEN_PSX_REQ * pdata;
939 OPEN_PSX_RSP * psx_rsp;
940
941 cFYI(1, ("In POSIX Create"));
942PsxCreat:
943 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
944 (void **) &pSMBr);
945 if (rc)
946 return rc;
947
948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
949 name_len =
950 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
951 PATH_MAX, nls_codepage, remap);
952 name_len++; /* trailing null */
953 name_len *= 2;
954 } else { /* BB improve the check for buffer overruns BB */
955 name_len = strnlen(name, PATH_MAX);
956 name_len++; /* trailing null */
957 strncpy(pSMB->FileName, name, name_len);
958 }
959
960 params = 6 + name_len;
961 count = sizeof(OPEN_PSX_REQ);
962 pSMB->MaxParameterCount = cpu_to_le16(2);
963 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
964 pSMB->MaxSetupCount = 0;
965 pSMB->Reserved = 0;
966 pSMB->Flags = 0;
967 pSMB->Timeout = 0;
968 pSMB->Reserved2 = 0;
969 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +0000970 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +0000971 offset = param_offset + params;
972 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
973 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
974 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
975 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +0000976 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +0000977 pdata->OpenFlags = cpu_to_le32(*pOplock);
978 pSMB->ParameterOffset = cpu_to_le16(param_offset);
979 pSMB->DataOffset = cpu_to_le16(offset);
980 pSMB->SetupCount = 1;
981 pSMB->Reserved3 = 0;
982 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
983 byte_count = 3 /* pad */ + params + count;
984
985 pSMB->DataCount = cpu_to_le16(count);
986 pSMB->ParameterCount = cpu_to_le16(params);
987 pSMB->TotalDataCount = pSMB->DataCount;
988 pSMB->TotalParameterCount = pSMB->ParameterCount;
989 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
990 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +0000991 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +0000992 pSMB->ByteCount = cpu_to_le16(byte_count);
993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
995 if (rc) {
996 cFYI(1, ("Posix create returned %d", rc));
997 goto psx_create_err;
998 }
999
Steve French790fe572007-07-07 19:25:05 +00001000 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001001 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1002
1003 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1004 rc = -EIO; /* bad smb */
1005 goto psx_create_err;
1006 }
1007
1008 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001009 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001010 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001011
Steve French2dd29d32007-04-23 22:07:35 +00001012 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001013 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001014 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1015 /* Let caller know file was created so we can set the mode. */
1016 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001017 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001018 *pOplock |= CIFS_CREATE_ACTION;
1019 /* check to make sure response data is there */
Steve French790fe572007-07-07 19:25:05 +00001020 if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001021 pRetData->Type = -1; /* unknown */
1022#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001023 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001024#endif
1025 } else {
Steve French790fe572007-07-07 19:25:05 +00001026 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001027 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001028 cERROR(1, ("Open response data too small"));
Steve French2dd29d32007-04-23 22:07:35 +00001029 pRetData->Type = -1;
1030 goto psx_create_err;
1031 }
Steve French50c2f752007-07-13 00:33:32 +00001032 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001033 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French2dd29d32007-04-23 22:07:35 +00001034 sizeof (FILE_UNIX_BASIC_INFO));
1035 }
Steve French2dd29d32007-04-23 22:07:35 +00001036
1037psx_create_err:
1038 cifs_buf_release(pSMB);
1039
1040 cifs_stats_inc(&tcon->num_mkdirs);
1041
1042 if (rc == -EAGAIN)
1043 goto PsxCreat;
1044
Steve French50c2f752007-07-13 00:33:32 +00001045 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001046}
1047
Steve Frencha9d02ad2005-08-24 23:06:05 -07001048static __u16 convert_disposition(int disposition)
1049{
1050 __u16 ofun = 0;
1051
1052 switch (disposition) {
1053 case FILE_SUPERSEDE:
1054 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1055 break;
1056 case FILE_OPEN:
1057 ofun = SMBOPEN_OAPPEND;
1058 break;
1059 case FILE_CREATE:
1060 ofun = SMBOPEN_OCREATE;
1061 break;
1062 case FILE_OPEN_IF:
1063 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1064 break;
1065 case FILE_OVERWRITE:
1066 ofun = SMBOPEN_OTRUNC;
1067 break;
1068 case FILE_OVERWRITE_IF:
1069 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1070 break;
1071 default:
Steve French790fe572007-07-07 19:25:05 +00001072 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001073 ofun = SMBOPEN_OAPPEND; /* regular open */
1074 }
1075 return ofun;
1076}
1077
1078int
1079SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1080 const char *fileName, const int openDisposition,
1081 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001082 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001083 const struct nls_table *nls_codepage, int remap)
1084{
1085 int rc = -EACCES;
1086 OPENX_REQ *pSMB = NULL;
1087 OPENX_RSP *pSMBr = NULL;
1088 int bytes_returned;
1089 int name_len;
1090 __u16 count;
1091
1092OldOpenRetry:
1093 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1094 (void **) &pSMBr);
1095 if (rc)
1096 return rc;
1097
1098 pSMB->AndXCommand = 0xFF; /* none */
1099
1100 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1101 count = 1; /* account for one byte pad to word boundary */
1102 name_len =
1103 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1104 fileName, PATH_MAX, nls_codepage, remap);
1105 name_len++; /* trailing null */
1106 name_len *= 2;
1107 } else { /* BB improve check for buffer overruns BB */
1108 count = 0; /* no pad */
1109 name_len = strnlen(fileName, PATH_MAX);
1110 name_len++; /* trailing null */
1111 strncpy(pSMB->fileName, fileName, name_len);
1112 }
1113 if (*pOplock & REQ_OPLOCK)
1114 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1115 else if (*pOplock & REQ_BATCHOPLOCK) {
1116 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1117 }
1118 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1119 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1120 /* 0 = read
1121 1 = write
1122 2 = rw
1123 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001124 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001125 pSMB->Mode = cpu_to_le16(2);
1126 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1127 /* set file as system file if special file such
1128 as fifo and server expecting SFU style and
1129 no Unix extensions */
1130
Steve French790fe572007-07-07 19:25:05 +00001131 if (create_options & CREATE_OPTION_SPECIAL)
1132 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1133 else
Steve French3e87d802005-09-18 20:49:21 -07001134 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001135
1136 /* if ((omode & S_IWUGO) == 0)
1137 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1138 /* Above line causes problems due to vfs splitting create into two
1139 pieces - need to set mode after file created not while it is
1140 being created */
1141
1142 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001143/* pSMB->CreateOptions = cpu_to_le32(create_options &
1144 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001145 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001146
1147 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001148 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001149 count += name_len;
1150 pSMB->hdr.smb_buf_length += count;
1151
1152 pSMB->ByteCount = cpu_to_le16(count);
1153 /* long_op set to 1 to allow for oplock break timeouts */
1154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001155 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001156 cifs_stats_inc(&tcon->num_opens);
1157 if (rc) {
1158 cFYI(1, ("Error in Open = %d", rc));
1159 } else {
1160 /* BB verify if wct == 15 */
1161
1162/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1163
1164 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1165 /* Let caller know file was created so we can set the mode. */
1166 /* Do we care about the CreateAction in any other cases? */
1167 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001168/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001169 *pOplock |= CIFS_CREATE_ACTION; */
1170 /* BB FIXME END */
1171
Steve French790fe572007-07-07 19:25:05 +00001172 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1174 pfile_info->LastAccessTime = 0; /* BB fixme */
1175 pfile_info->LastWriteTime = 0; /* BB fixme */
1176 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001177 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001178 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001179 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001180 pfile_info->AllocationSize =
1181 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1182 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183 pfile_info->NumberOfLinks = cpu_to_le32(1);
1184 }
1185 }
1186
1187 cifs_buf_release(pSMB);
1188 if (rc == -EAGAIN)
1189 goto OldOpenRetry;
1190 return rc;
1191}
1192
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193int
1194CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1195 const char *fileName, const int openDisposition,
1196 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001197 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001198 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
1200 int rc = -EACCES;
1201 OPEN_REQ *pSMB = NULL;
1202 OPEN_RSP *pSMBr = NULL;
1203 int bytes_returned;
1204 int name_len;
1205 __u16 count;
1206
1207openRetry:
1208 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1209 (void **) &pSMBr);
1210 if (rc)
1211 return rc;
1212
1213 pSMB->AndXCommand = 0xFF; /* none */
1214
1215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1216 count = 1; /* account for one byte pad to word boundary */
1217 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001218 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001219 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 name_len++; /* trailing null */
1221 name_len *= 2;
1222 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001223 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 count = 0; /* no pad */
1225 name_len = strnlen(fileName, PATH_MAX);
1226 name_len++; /* trailing null */
1227 pSMB->NameLength = cpu_to_le16(name_len);
1228 strncpy(pSMB->fileName, fileName, name_len);
1229 }
1230 if (*pOplock & REQ_OPLOCK)
1231 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1232 else if (*pOplock & REQ_BATCHOPLOCK) {
1233 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1234 }
1235 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1236 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001237 /* set file as system file if special file such
1238 as fifo and server expecting SFU style and
1239 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001240 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001241 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1242 else
1243 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 /* XP does not handle ATTR_POSIX_SEMANTICS */
1245 /* but it helps speed up case sensitive checks for other
1246 servers such as Samba */
1247 if (tcon->ses->capabilities & CAP_UNIX)
1248 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1249
1250 /* if ((omode & S_IWUGO) == 0)
1251 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1252 /* Above line causes problems due to vfs splitting create into two
1253 pieces - need to set mode after file created not while it is
1254 being created */
1255 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1256 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001257 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001258 /* BB Expirement with various impersonation levels and verify */
1259 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 pSMB->SecurityFlags =
1261 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1262
1263 count += name_len;
1264 pSMB->hdr.smb_buf_length += count;
1265
1266 pSMB->ByteCount = cpu_to_le16(count);
1267 /* long_op set to 1 to allow for oplock break timeouts */
1268 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1269 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001270 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 if (rc) {
1272 cFYI(1, ("Error in Open = %d", rc));
1273 } else {
Steve French09d1db52005-04-28 22:41:08 -07001274 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1276 /* Let caller know file was created so we can set the mode. */
1277 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001278 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001279 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001280 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001281 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 36 /* CreationTime to Attributes */);
1283 /* the file_info buf is endian converted by caller */
1284 pfile_info->AllocationSize = pSMBr->AllocationSize;
1285 pfile_info->EndOfFile = pSMBr->EndOfFile;
1286 pfile_info->NumberOfLinks = cpu_to_le32(1);
1287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 cifs_buf_release(pSMB);
1291 if (rc == -EAGAIN)
1292 goto openRetry;
1293 return rc;
1294}
1295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296int
Steve French50c2f752007-07-13 00:33:32 +00001297CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1298 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1299 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300{
1301 int rc = -EACCES;
1302 READ_REQ *pSMB = NULL;
1303 READ_RSP *pSMBr = NULL;
1304 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001305 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001306 int resp_buf_type = 0;
1307 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Steve French790fe572007-07-07 19:25:05 +00001309 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1310 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001311 wct = 12;
1312 else
1313 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
1315 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001316 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (rc)
1318 return rc;
1319
1320 /* tcon and ses pointer are checked in smb_init */
1321 if (tcon->ses->server == NULL)
1322 return -ECONNABORTED;
1323
Steve Frenchec637e32005-12-12 20:53:18 -08001324 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->Fid = netfid;
1326 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001327 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001328 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001329 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001330 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 pSMB->Remaining = 0;
1333 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1334 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001335 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001336 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1337 else {
1338 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001339 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001340 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001341 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001342 }
Steve Frenchec637e32005-12-12 20:53:18 -08001343
1344 iov[0].iov_base = (char *)pSMB;
1345 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve French50c2f752007-07-13 00:33:32 +00001346 rc = SendReceive2(xid, tcon->ses, iov,
Steve Frenchec637e32005-12-12 20:53:18 -08001347 1 /* num iovecs */,
Steve French50c2f752007-07-13 00:33:32 +00001348 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001349 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001350 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if (rc) {
1352 cERROR(1, ("Send error in read = %d", rc));
1353 } else {
1354 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1355 data_length = data_length << 16;
1356 data_length += le16_to_cpu(pSMBr->DataLength);
1357 *nbytes = data_length;
1358
1359 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001360 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001362 cFYI(1, ("bad length %d for count %d",
1363 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 rc = -EIO;
1365 *nbytes = 0;
1366 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001367 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 le16_to_cpu(pSMBr->DataOffset);
Steve French790fe572007-07-07 19:25:05 +00001369/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001370 cERROR(1,("Faulting on read rc = %d",rc));
1371 rc = -EFAULT;
Steve Frenchec637e32005-12-12 20:53:18 -08001372 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001373 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001374 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 }
1376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Steve French4b8f9302006-02-26 16:41:18 +00001378/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001379 if (*buf) {
1380 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001381 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001382 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001383 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001384 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001385 /* return buffer to caller to free */
1386 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001387 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001388 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001389 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001390 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001391 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001392
1393 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 since file handle passed in no longer valid */
1395 return rc;
1396}
1397
Steve Frenchec637e32005-12-12 20:53:18 -08001398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399int
1400CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1401 const int netfid, const unsigned int count,
1402 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001403 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404{
1405 int rc = -EACCES;
1406 WRITE_REQ *pSMB = NULL;
1407 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001408 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 __u32 bytes_sent;
1410 __u16 byte_count;
1411
1412 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001413 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001414 return -ECONNABORTED;
1415
Steve French790fe572007-07-07 19:25:05 +00001416 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001417 wct = 14;
1418 else
1419 wct = 12;
1420
1421 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 (void **) &pSMBr);
1423 if (rc)
1424 return rc;
1425 /* tcon and ses pointer are checked in smb_init */
1426 if (tcon->ses->server == NULL)
1427 return -ECONNABORTED;
1428
1429 pSMB->AndXCommand = 0xFF; /* none */
1430 pSMB->Fid = netfid;
1431 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001432 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001433 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001434 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001435 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001436
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 pSMB->Reserved = 0xFFFFFFFF;
1438 pSMB->WriteMode = 0;
1439 pSMB->Remaining = 0;
1440
Steve French50c2f752007-07-13 00:33:32 +00001441 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 can send more if LARGE_WRITE_X capability returned by the server and if
1443 our buffer is big enough or if we convert to iovecs on socket writes
1444 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001445 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1447 } else {
1448 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1449 & ~0xFF;
1450 }
1451
1452 if (bytes_sent > count)
1453 bytes_sent = count;
1454 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001455 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001456 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001457 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001458 else if (ubuf) {
1459 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 cifs_buf_release(pSMB);
1461 return -EFAULT;
1462 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001463 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 /* No buffer */
1465 cifs_buf_release(pSMB);
1466 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001467 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001468 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001469 byte_count = bytes_sent + 1; /* pad */
1470 else /* wct == 12 */ {
1471 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1474 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001475 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001476
Steve French790fe572007-07-07 19:25:05 +00001477 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001478 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001479 else { /* old style write has byte count 4 bytes earlier
1480 so 4 bytes pad */
1481 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001482 (struct smb_com_writex_req *)pSMB;
1483 pSMBW->ByteCount = cpu_to_le16(byte_count);
1484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
1486 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1487 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001488 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (rc) {
1490 cFYI(1, ("Send error in write = %d", rc));
1491 *nbytes = 0;
1492 } else {
1493 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1494 *nbytes = (*nbytes) << 16;
1495 *nbytes += le16_to_cpu(pSMBr->Count);
1496 }
1497
1498 cifs_buf_release(pSMB);
1499
Steve French50c2f752007-07-13 00:33:32 +00001500 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 since file handle passed in no longer valid */
1502
1503 return rc;
1504}
1505
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001506int
1507CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001509 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1510 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
1512 int rc = -EACCES;
1513 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001514 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001515 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001516 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
Steve French790fe572007-07-07 19:25:05 +00001518 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001519
Steve French790fe572007-07-07 19:25:05 +00001520 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001521 wct = 14;
1522 else
1523 wct = 12;
1524 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 if (rc)
1526 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 /* tcon and ses pointer are checked in smb_init */
1528 if (tcon->ses->server == NULL)
1529 return -ECONNABORTED;
1530
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001531 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 pSMB->Fid = netfid;
1533 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001534 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001535 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001536 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001537 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 pSMB->Reserved = 0xFFFFFFFF;
1539 pSMB->WriteMode = 0;
1540 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001543 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Steve French3e844692005-10-03 13:37:24 -07001545 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1546 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001547 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001548 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001549 pSMB->hdr.smb_buf_length += count+1;
1550 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001551 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1552 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001553 pSMB->ByteCount = cpu_to_le16(count + 1);
1554 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001555 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001556 (struct smb_com_writex_req *)pSMB;
1557 pSMBW->ByteCount = cpu_to_le16(count + 5);
1558 }
Steve French3e844692005-10-03 13:37:24 -07001559 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001560 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001561 iov[0].iov_len = smb_hdr_len + 4;
1562 else /* wct == 12 pad bigger by four bytes */
1563 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001564
Steve French3e844692005-10-03 13:37:24 -07001565
Steve Frenchec637e32005-12-12 20:53:18 -08001566 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001567 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001568 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001570 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001572 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001573 /* presumably this can not happen, but best to be safe */
1574 rc = -EIO;
1575 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001576 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001577 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001578 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1579 *nbytes = (*nbytes) << 16;
1580 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Steve French4b8f9302006-02-26 16:41:18 +00001583/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001584 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001585 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001586 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001587 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
Steve French50c2f752007-07-13 00:33:32 +00001589 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 since file handle passed in no longer valid */
1591
1592 return rc;
1593}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001594
1595
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596int
1597CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1598 const __u16 smb_file_id, const __u64 len,
1599 const __u64 offset, const __u32 numUnlock,
1600 const __u32 numLock, const __u8 lockType, const int waitFlag)
1601{
1602 int rc = 0;
1603 LOCK_REQ *pSMB = NULL;
1604 LOCK_RSP *pSMBr = NULL;
1605 int bytes_returned;
1606 int timeout = 0;
1607 __u16 count;
1608
Steve French50c2f752007-07-13 00:33:32 +00001609 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001610 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 if (rc)
1613 return rc;
1614
Steve French46810cb2005-04-28 22:41:09 -07001615 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1616
Steve French790fe572007-07-07 19:25:05 +00001617 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 timeout = -1; /* no response expected */
1619 pSMB->Timeout = 0;
1620 } else if (waitFlag == TRUE) {
1621 timeout = 3; /* blocking operation, no timeout */
1622 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1623 } else {
1624 pSMB->Timeout = 0;
1625 }
1626
1627 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1628 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1629 pSMB->LockType = lockType;
1630 pSMB->AndXCommand = 0xFF; /* none */
1631 pSMB->Fid = smb_file_id; /* netfid stays le */
1632
Steve French790fe572007-07-07 19:25:05 +00001633 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1635 /* BB where to store pid high? */
1636 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1637 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1638 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1639 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1640 count = sizeof(LOCKING_ANDX_RANGE);
1641 } else {
1642 /* oplock break */
1643 count = 0;
1644 }
1645 pSMB->hdr.smb_buf_length += count;
1646 pSMB->ByteCount = cpu_to_le16(count);
1647
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001648 if (waitFlag) {
1649 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1650 (struct smb_hdr *) pSMBr, &bytes_returned);
1651 } else {
1652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001654 }
Steve Frencha4544342005-08-24 13:59:35 -07001655 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 if (rc) {
1657 cFYI(1, ("Send error in Lock = %d", rc));
1658 }
Steve French46810cb2005-04-28 22:41:09 -07001659 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
Steve French50c2f752007-07-13 00:33:32 +00001661 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 since file handle passed in no longer valid */
1663 return rc;
1664}
1665
1666int
Steve French08547b02006-02-28 22:39:25 +00001667CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1668 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001669 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001670 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001671{
1672 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1673 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1674 char *data_offset;
1675 struct cifs_posix_lock *parm_data;
1676 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001677 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001678 int bytes_returned = 0;
1679 __u16 params, param_offset, offset, byte_count, count;
1680
1681 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001682
Steve French790fe572007-07-07 19:25:05 +00001683 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001684 return EINVAL;
1685
Steve French08547b02006-02-28 22:39:25 +00001686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1687
1688 if (rc)
1689 return rc;
1690
1691 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1692
Steve French50c2f752007-07-13 00:33:32 +00001693 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001694 pSMB->MaxSetupCount = 0;
1695 pSMB->Reserved = 0;
1696 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001697 pSMB->Reserved2 = 0;
1698 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1699 offset = param_offset + params;
1700
1701 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1702
1703 count = sizeof(struct cifs_posix_lock);
1704 pSMB->MaxParameterCount = cpu_to_le16(2);
1705 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1706 pSMB->SetupCount = 1;
1707 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001708 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001709 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1710 else
1711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1712 byte_count = 3 /* pad */ + params + count;
1713 pSMB->DataCount = cpu_to_le16(count);
1714 pSMB->ParameterCount = cpu_to_le16(params);
1715 pSMB->TotalDataCount = pSMB->DataCount;
1716 pSMB->TotalParameterCount = pSMB->ParameterCount;
1717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001718 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001719 (((char *) &pSMB->hdr.Protocol) + offset);
1720
1721 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001722 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001723 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001724 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001725 pSMB->Timeout = cpu_to_le32(-1);
1726 } else
1727 pSMB->Timeout = 0;
1728
Steve French08547b02006-02-28 22:39:25 +00001729 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001730 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001731 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001732
1733 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001734 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001735 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1736 pSMB->Reserved4 = 0;
1737 pSMB->hdr.smb_buf_length += byte_count;
1738 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001739 if (waitFlag) {
1740 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1741 (struct smb_hdr *) pSMBr, &bytes_returned);
1742 } else {
1743 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001744 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001745 }
1746
Steve French08547b02006-02-28 22:39:25 +00001747 if (rc) {
1748 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001749 } else if (get_flag) {
1750 /* lock structure can be returned on get */
1751 __u16 data_offset;
1752 __u16 data_count;
1753 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001754
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001755 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1756 rc = -EIO; /* bad smb */
1757 goto plk_err_exit;
1758 }
Steve French790fe572007-07-07 19:25:05 +00001759 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001760 rc = -EINVAL;
1761 goto plk_err_exit;
1762 }
1763 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1764 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001765 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001766 rc = -EIO;
1767 goto plk_err_exit;
1768 }
1769 parm_data = (struct cifs_posix_lock *)
1770 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001771 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001772 pLockData->fl_type = F_UNLCK;
1773 }
Steve French50c2f752007-07-13 00:33:32 +00001774
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001775plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001776 if (pSMB)
1777 cifs_small_buf_release(pSMB);
1778
1779 /* Note: On -EAGAIN error only caller can retry on handle based calls
1780 since file handle passed in no longer valid */
1781
1782 return rc;
1783}
1784
1785
1786int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1788{
1789 int rc = 0;
1790 CLOSE_REQ *pSMB = NULL;
1791 CLOSE_RSP *pSMBr = NULL;
1792 int bytes_returned;
1793 cFYI(1, ("In CIFSSMBClose"));
1794
1795/* do not retry on dead session on close */
1796 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001797 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 return 0;
1799 if (rc)
1800 return rc;
1801
1802 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1803
1804 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001805 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 pSMB->ByteCount = 0;
1807 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1808 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001809 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001811 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 /* EINTR is expected when user ctl-c to kill app */
1813 cERROR(1, ("Send error in Close = %d", rc));
1814 }
1815 }
1816
1817 cifs_small_buf_release(pSMB);
1818
1819 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001820 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 rc = 0;
1822
1823 return rc;
1824}
1825
1826int
1827CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1828 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001829 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830{
1831 int rc = 0;
1832 RENAME_REQ *pSMB = NULL;
1833 RENAME_RSP *pSMBr = NULL;
1834 int bytes_returned;
1835 int name_len, name_len2;
1836 __u16 count;
1837
1838 cFYI(1, ("In CIFSSMBRename"));
1839renameRetry:
1840 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1841 (void **) &pSMBr);
1842 if (rc)
1843 return rc;
1844
1845 pSMB->BufferFormat = 0x04;
1846 pSMB->SearchAttributes =
1847 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1848 ATTR_DIRECTORY);
1849
1850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1851 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001852 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001853 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 name_len++; /* trailing null */
1855 name_len *= 2;
1856 pSMB->OldFileName[name_len] = 0x04; /* pad */
1857 /* protocol requires ASCII signature byte on Unicode string */
1858 pSMB->OldFileName[name_len + 1] = 0x00;
1859 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001860 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001861 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1863 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001864 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 name_len = strnlen(fromName, PATH_MAX);
1866 name_len++; /* trailing null */
1867 strncpy(pSMB->OldFileName, fromName, name_len);
1868 name_len2 = strnlen(toName, PATH_MAX);
1869 name_len2++; /* trailing null */
1870 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1871 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1872 name_len2++; /* trailing null */
1873 name_len2++; /* signature byte */
1874 }
1875
1876 count = 1 /* 1st signature byte */ + name_len + name_len2;
1877 pSMB->hdr.smb_buf_length += count;
1878 pSMB->ByteCount = cpu_to_le16(count);
1879
1880 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1881 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001882 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (rc) {
1884 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 cifs_buf_release(pSMB);
1888
1889 if (rc == -EAGAIN)
1890 goto renameRetry;
1891
1892 return rc;
1893}
1894
Steve French50c2f752007-07-13 00:33:32 +00001895int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1896 int netfid, char *target_name,
1897 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898{
1899 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1900 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001901 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 char *data_offset;
1903 char dummy_string[30];
1904 int rc = 0;
1905 int bytes_returned = 0;
1906 int len_of_str;
1907 __u16 params, param_offset, offset, count, byte_count;
1908
1909 cFYI(1, ("Rename to File by handle"));
1910 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1911 (void **) &pSMBr);
1912 if (rc)
1913 return rc;
1914
1915 params = 6;
1916 pSMB->MaxSetupCount = 0;
1917 pSMB->Reserved = 0;
1918 pSMB->Flags = 0;
1919 pSMB->Timeout = 0;
1920 pSMB->Reserved2 = 0;
1921 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1922 offset = param_offset + params;
1923
1924 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1925 rename_info = (struct set_file_rename *) data_offset;
1926 pSMB->MaxParameterCount = cpu_to_le16(2);
1927 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1928 pSMB->SetupCount = 1;
1929 pSMB->Reserved3 = 0;
1930 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1931 byte_count = 3 /* pad */ + params;
1932 pSMB->ParameterCount = cpu_to_le16(params);
1933 pSMB->TotalParameterCount = pSMB->ParameterCount;
1934 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1935 pSMB->DataOffset = cpu_to_le16(offset);
1936 /* construct random name ".cifs_tmp<inodenum><mid>" */
1937 rename_info->overwrite = cpu_to_le32(1);
1938 rename_info->root_fid = 0;
1939 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00001940 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001941 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
1942 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001943 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001945 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00001946 target_name, PATH_MAX, nls_codepage,
1947 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 }
1949 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1950 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1951 byte_count += count;
1952 pSMB->DataCount = cpu_to_le16(count);
1953 pSMB->TotalDataCount = pSMB->DataCount;
1954 pSMB->Fid = netfid;
1955 pSMB->InformationLevel =
1956 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1957 pSMB->Reserved4 = 0;
1958 pSMB->hdr.smb_buf_length += byte_count;
1959 pSMB->ByteCount = cpu_to_le16(byte_count);
1960 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001961 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001962 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001964 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001966
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 cifs_buf_release(pSMB);
1968
1969 /* Note: On -EAGAIN error only caller can retry on handle based calls
1970 since file handle passed in no longer valid */
1971
1972 return rc;
1973}
1974
1975int
Steve French50c2f752007-07-13 00:33:32 +00001976CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
1977 const __u16 target_tid, const char *toName, const int flags,
1978 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
1980 int rc = 0;
1981 COPY_REQ *pSMB = NULL;
1982 COPY_RSP *pSMBr = NULL;
1983 int bytes_returned;
1984 int name_len, name_len2;
1985 __u16 count;
1986
1987 cFYI(1, ("In CIFSSMBCopy"));
1988copyRetry:
1989 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1990 (void **) &pSMBr);
1991 if (rc)
1992 return rc;
1993
1994 pSMB->BufferFormat = 0x04;
1995 pSMB->Tid2 = target_tid;
1996
1997 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1998
1999 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002000 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002001 fromName, PATH_MAX, nls_codepage,
2002 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 name_len++; /* trailing null */
2004 name_len *= 2;
2005 pSMB->OldFileName[name_len] = 0x04; /* pad */
2006 /* protocol requires ASCII signature byte on Unicode string */
2007 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002008 name_len2 =
2009 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002010 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2012 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002013 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 name_len = strnlen(fromName, PATH_MAX);
2015 name_len++; /* trailing null */
2016 strncpy(pSMB->OldFileName, fromName, name_len);
2017 name_len2 = strnlen(toName, PATH_MAX);
2018 name_len2++; /* trailing null */
2019 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2020 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2021 name_len2++; /* trailing null */
2022 name_len2++; /* signature byte */
2023 }
2024
2025 count = 1 /* 1st signature byte */ + name_len + name_len2;
2026 pSMB->hdr.smb_buf_length += count;
2027 pSMB->ByteCount = cpu_to_le16(count);
2028
2029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2031 if (rc) {
2032 cFYI(1, ("Send error in copy = %d with %d files copied",
2033 rc, le16_to_cpu(pSMBr->CopyCount)));
2034 }
2035 if (pSMB)
2036 cifs_buf_release(pSMB);
2037
2038 if (rc == -EAGAIN)
2039 goto copyRetry;
2040
2041 return rc;
2042}
2043
2044int
2045CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2046 const char *fromName, const char *toName,
2047 const struct nls_table *nls_codepage)
2048{
2049 TRANSACTION2_SPI_REQ *pSMB = NULL;
2050 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2051 char *data_offset;
2052 int name_len;
2053 int name_len_target;
2054 int rc = 0;
2055 int bytes_returned = 0;
2056 __u16 params, param_offset, offset, byte_count;
2057
2058 cFYI(1, ("In Symlink Unix style"));
2059createSymLinkRetry:
2060 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2061 (void **) &pSMBr);
2062 if (rc)
2063 return rc;
2064
2065 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2066 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002067 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 /* find define for this maxpathcomponent */
2069 , nls_codepage);
2070 name_len++; /* trailing null */
2071 name_len *= 2;
2072
Steve French50c2f752007-07-13 00:33:32 +00002073 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 name_len = strnlen(fromName, PATH_MAX);
2075 name_len++; /* trailing null */
2076 strncpy(pSMB->FileName, fromName, name_len);
2077 }
2078 params = 6 + name_len;
2079 pSMB->MaxSetupCount = 0;
2080 pSMB->Reserved = 0;
2081 pSMB->Flags = 0;
2082 pSMB->Timeout = 0;
2083 pSMB->Reserved2 = 0;
2084 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002085 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 offset = param_offset + params;
2087
2088 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2089 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2090 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002091 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 /* find define for this maxpathcomponent */
2093 , nls_codepage);
2094 name_len_target++; /* trailing null */
2095 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002096 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 name_len_target = strnlen(toName, PATH_MAX);
2098 name_len_target++; /* trailing null */
2099 strncpy(data_offset, toName, name_len_target);
2100 }
2101
2102 pSMB->MaxParameterCount = cpu_to_le16(2);
2103 /* BB find exact max on data count below from sess */
2104 pSMB->MaxDataCount = cpu_to_le16(1000);
2105 pSMB->SetupCount = 1;
2106 pSMB->Reserved3 = 0;
2107 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2108 byte_count = 3 /* pad */ + params + name_len_target;
2109 pSMB->DataCount = cpu_to_le16(name_len_target);
2110 pSMB->ParameterCount = cpu_to_le16(params);
2111 pSMB->TotalDataCount = pSMB->DataCount;
2112 pSMB->TotalParameterCount = pSMB->ParameterCount;
2113 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2114 pSMB->DataOffset = cpu_to_le16(offset);
2115 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2116 pSMB->Reserved4 = 0;
2117 pSMB->hdr.smb_buf_length += byte_count;
2118 pSMB->ByteCount = cpu_to_le16(byte_count);
2119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002121 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 if (rc) {
2123 cFYI(1,
2124 ("Send error in SetPathInfo (create symlink) = %d",
2125 rc));
2126 }
2127
2128 if (pSMB)
2129 cifs_buf_release(pSMB);
2130
2131 if (rc == -EAGAIN)
2132 goto createSymLinkRetry;
2133
2134 return rc;
2135}
2136
2137int
2138CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2139 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002140 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141{
2142 TRANSACTION2_SPI_REQ *pSMB = NULL;
2143 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2144 char *data_offset;
2145 int name_len;
2146 int name_len_target;
2147 int rc = 0;
2148 int bytes_returned = 0;
2149 __u16 params, param_offset, offset, byte_count;
2150
2151 cFYI(1, ("In Create Hard link Unix style"));
2152createHardLinkRetry:
2153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154 (void **) &pSMBr);
2155 if (rc)
2156 return rc;
2157
2158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002159 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002160 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 name_len++; /* trailing null */
2162 name_len *= 2;
2163
Steve French50c2f752007-07-13 00:33:32 +00002164 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 name_len = strnlen(toName, PATH_MAX);
2166 name_len++; /* trailing null */
2167 strncpy(pSMB->FileName, toName, name_len);
2168 }
2169 params = 6 + name_len;
2170 pSMB->MaxSetupCount = 0;
2171 pSMB->Reserved = 0;
2172 pSMB->Flags = 0;
2173 pSMB->Timeout = 0;
2174 pSMB->Reserved2 = 0;
2175 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002176 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 offset = param_offset + params;
2178
2179 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2181 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002182 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002183 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 name_len_target++; /* trailing null */
2185 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002186 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 name_len_target = strnlen(fromName, PATH_MAX);
2188 name_len_target++; /* trailing null */
2189 strncpy(data_offset, fromName, name_len_target);
2190 }
2191
2192 pSMB->MaxParameterCount = cpu_to_le16(2);
2193 /* BB find exact max on data count below from sess*/
2194 pSMB->MaxDataCount = cpu_to_le16(1000);
2195 pSMB->SetupCount = 1;
2196 pSMB->Reserved3 = 0;
2197 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2198 byte_count = 3 /* pad */ + params + name_len_target;
2199 pSMB->ParameterCount = cpu_to_le16(params);
2200 pSMB->TotalParameterCount = pSMB->ParameterCount;
2201 pSMB->DataCount = cpu_to_le16(name_len_target);
2202 pSMB->TotalDataCount = pSMB->DataCount;
2203 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2204 pSMB->DataOffset = cpu_to_le16(offset);
2205 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2206 pSMB->Reserved4 = 0;
2207 pSMB->hdr.smb_buf_length += byte_count;
2208 pSMB->ByteCount = cpu_to_le16(byte_count);
2209 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2210 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002211 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 if (rc) {
2213 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2214 }
2215
2216 cifs_buf_release(pSMB);
2217 if (rc == -EAGAIN)
2218 goto createHardLinkRetry;
2219
2220 return rc;
2221}
2222
2223int
2224CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2225 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002226 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227{
2228 int rc = 0;
2229 NT_RENAME_REQ *pSMB = NULL;
2230 RENAME_RSP *pSMBr = NULL;
2231 int bytes_returned;
2232 int name_len, name_len2;
2233 __u16 count;
2234
2235 cFYI(1, ("In CIFSCreateHardLink"));
2236winCreateHardLinkRetry:
2237
2238 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2239 (void **) &pSMBr);
2240 if (rc)
2241 return rc;
2242
2243 pSMB->SearchAttributes =
2244 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2245 ATTR_DIRECTORY);
2246 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2247 pSMB->ClusterCount = 0;
2248
2249 pSMB->BufferFormat = 0x04;
2250
2251 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2252 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002253 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002254 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 name_len++; /* trailing null */
2256 name_len *= 2;
2257 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002258 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002260 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002261 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2263 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002264 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 name_len = strnlen(fromName, PATH_MAX);
2266 name_len++; /* trailing null */
2267 strncpy(pSMB->OldFileName, fromName, name_len);
2268 name_len2 = strnlen(toName, PATH_MAX);
2269 name_len2++; /* trailing null */
2270 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2271 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2272 name_len2++; /* trailing null */
2273 name_len2++; /* signature byte */
2274 }
2275
2276 count = 1 /* string type byte */ + name_len + name_len2;
2277 pSMB->hdr.smb_buf_length += count;
2278 pSMB->ByteCount = cpu_to_le16(count);
2279
2280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2281 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002282 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 if (rc) {
2284 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2285 }
2286 cifs_buf_release(pSMB);
2287 if (rc == -EAGAIN)
2288 goto winCreateHardLinkRetry;
2289
2290 return rc;
2291}
2292
2293int
2294CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2295 const unsigned char *searchName,
2296 char *symlinkinfo, const int buflen,
2297 const struct nls_table *nls_codepage)
2298{
2299/* SMB_QUERY_FILE_UNIX_LINK */
2300 TRANSACTION2_QPI_REQ *pSMB = NULL;
2301 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2302 int rc = 0;
2303 int bytes_returned;
2304 int name_len;
2305 __u16 params, byte_count;
2306
2307 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2308
2309querySymLinkRetry:
2310 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2311 (void **) &pSMBr);
2312 if (rc)
2313 return rc;
2314
2315 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2316 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002317 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2318 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 name_len++; /* trailing null */
2320 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002321 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 name_len = strnlen(searchName, PATH_MAX);
2323 name_len++; /* trailing null */
2324 strncpy(pSMB->FileName, searchName, name_len);
2325 }
2326
2327 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2328 pSMB->TotalDataCount = 0;
2329 pSMB->MaxParameterCount = cpu_to_le16(2);
2330 /* BB find exact max data count below from sess structure BB */
2331 pSMB->MaxDataCount = cpu_to_le16(4000);
2332 pSMB->MaxSetupCount = 0;
2333 pSMB->Reserved = 0;
2334 pSMB->Flags = 0;
2335 pSMB->Timeout = 0;
2336 pSMB->Reserved2 = 0;
2337 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002338 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 pSMB->DataCount = 0;
2340 pSMB->DataOffset = 0;
2341 pSMB->SetupCount = 1;
2342 pSMB->Reserved3 = 0;
2343 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2344 byte_count = params + 1 /* pad */ ;
2345 pSMB->TotalParameterCount = cpu_to_le16(params);
2346 pSMB->ParameterCount = pSMB->TotalParameterCount;
2347 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2348 pSMB->Reserved4 = 0;
2349 pSMB->hdr.smb_buf_length += byte_count;
2350 pSMB->ByteCount = cpu_to_le16(byte_count);
2351
2352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2354 if (rc) {
2355 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2356 } else {
2357 /* decode response */
2358
2359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2360 if (rc || (pSMBr->ByteCount < 2))
2361 /* BB also check enough total bytes returned */
2362 rc = -EIO; /* bad smb */
2363 else {
2364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2365 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2366
2367 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2368 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002369 &pSMBr->hdr.Protocol + data_offset),
2370 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002371 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002373 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2374 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 name_len, nls_codepage);
2376 } else {
2377 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002378 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 data_offset,
2380 min_t(const int, buflen, count));
2381 }
2382 symlinkinfo[buflen] = 0;
2383 /* just in case so calling code does not go off the end of buffer */
2384 }
2385 }
2386 cifs_buf_release(pSMB);
2387 if (rc == -EAGAIN)
2388 goto querySymLinkRetry;
2389 return rc;
2390}
2391
Steve French0a4b92c2006-01-12 15:44:21 -08002392/* Initialize NT TRANSACT SMB into small smb request buffer.
2393 This assumes that all NT TRANSACTS that we init here have
2394 total parm and data under about 400 bytes (to fit in small cifs
2395 buffer size), which is the case so far, it easily fits. NB:
2396 Setup words themselves and ByteCount
2397 MaxSetupCount (size of returned setup area) and
2398 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002399static int
Steve French0a4b92c2006-01-12 15:44:21 -08002400smb_init_ntransact(const __u16 sub_command, const int setup_count,
2401 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002402 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002403{
2404 int rc;
2405 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002406 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002407
2408 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2409 (void **)&pSMB);
2410 if (rc)
2411 return rc;
2412 *ret_buf = (void *)pSMB;
2413 pSMB->Reserved = 0;
2414 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2415 pSMB->TotalDataCount = 0;
2416 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2417 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2418 pSMB->ParameterCount = pSMB->TotalParameterCount;
2419 pSMB->DataCount = pSMB->TotalDataCount;
2420 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2421 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2422 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2423 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2424 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2425 pSMB->SubCommand = cpu_to_le16(sub_command);
2426 return 0;
2427}
2428
2429static int
Steve French50c2f752007-07-13 00:33:32 +00002430validate_ntransact(char *buf, char **ppparm, char **ppdata,
2431 int *pdatalen, int *pparmlen)
Steve French0a4b92c2006-01-12 15:44:21 -08002432{
Steve French50c2f752007-07-13 00:33:32 +00002433 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002434 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002435 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002436
Steve French790fe572007-07-07 19:25:05 +00002437 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002438 return -EINVAL;
2439
2440 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2441
2442 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002443 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002444 (char *)&pSMBr->ByteCount;
2445
Steve French0a4b92c2006-01-12 15:44:21 -08002446 data_offset = le32_to_cpu(pSMBr->DataOffset);
2447 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002448 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002449 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2450
2451 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2452 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2453
2454 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002455 if (*ppparm > end_of_smb) {
2456 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002457 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002458 } else if (parm_count + *ppparm > end_of_smb) {
2459 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002460 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002461 } else if (*ppdata > end_of_smb) {
2462 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002463 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002464 } else if (data_count + *ppdata > end_of_smb) {
Steve French0a4b92c2006-01-12 15:44:21 -08002465 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002466 *ppdata, data_count, (data_count + *ppdata),
2467 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002468 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002469 } else if (parm_count + data_count > pSMBr->ByteCount) {
2470 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002471 return -EINVAL;
2472 }
2473 return 0;
2474}
2475
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476int
2477CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2478 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002479 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 const struct nls_table *nls_codepage)
2481{
2482 int rc = 0;
2483 int bytes_returned;
2484 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002485 struct smb_com_transaction_ioctl_req *pSMB;
2486 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
2488 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2489 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2490 (void **) &pSMBr);
2491 if (rc)
2492 return rc;
2493
2494 pSMB->TotalParameterCount = 0 ;
2495 pSMB->TotalDataCount = 0;
2496 pSMB->MaxParameterCount = cpu_to_le32(2);
2497 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002498 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2499 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 pSMB->MaxSetupCount = 4;
2501 pSMB->Reserved = 0;
2502 pSMB->ParameterOffset = 0;
2503 pSMB->DataCount = 0;
2504 pSMB->DataOffset = 0;
2505 pSMB->SetupCount = 4;
2506 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2507 pSMB->ParameterCount = pSMB->TotalParameterCount;
2508 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2509 pSMB->IsFsctl = 1; /* FSCTL */
2510 pSMB->IsRootFlag = 0;
2511 pSMB->Fid = fid; /* file handle always le */
2512 pSMB->ByteCount = 0;
2513
2514 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2515 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2516 if (rc) {
2517 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2518 } else { /* decode response */
2519 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2520 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2521 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2522 /* BB also check enough total bytes returned */
2523 rc = -EIO; /* bad smb */
2524 else {
Steve French790fe572007-07-07 19:25:05 +00002525 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002526 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002527 pSMBr->ByteCount +
2528 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
Steve French50c2f752007-07-13 00:33:32 +00002530 struct reparse_data *reparse_buf =
2531 (struct reparse_data *)
2532 ((char *)&pSMBr->hdr.Protocol
2533 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002534 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 rc = -EIO;
2536 goto qreparse_out;
2537 }
Steve French790fe572007-07-07 19:25:05 +00002538 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 reparse_buf->TargetNameOffset +
2540 reparse_buf->TargetNameLen) >
2541 end_of_smb) {
2542 cFYI(1,("reparse buf extended beyond SMB"));
2543 rc = -EIO;
2544 goto qreparse_out;
2545 }
Steve French50c2f752007-07-13 00:33:32 +00002546
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2548 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002549 (reparse_buf->LinkNamesBuf +
2550 reparse_buf->TargetNameOffset),
2551 min(buflen/2,
2552 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002554 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 reparse_buf->TargetNameOffset),
2556 name_len, nls_codepage);
2557 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002558 strncpy(symlinkinfo,
2559 reparse_buf->LinkNamesBuf +
2560 reparse_buf->TargetNameOffset,
2561 min_t(const int, buflen,
2562 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 }
2564 } else {
2565 rc = -EIO;
2566 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2567 }
2568 symlinkinfo[buflen] = 0; /* just in case so the caller
2569 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002570 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 }
2572 }
2573qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002574 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575
2576 /* Note: On -EAGAIN error only caller can retry on handle based calls
2577 since file handle passed in no longer valid */
2578
2579 return rc;
2580}
2581
2582#ifdef CONFIG_CIFS_POSIX
2583
2584/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002585static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2586 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587{
2588 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002589 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2590 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2591 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2593
2594 return;
2595}
2596
2597/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002598static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2599 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600{
2601 int size = 0;
2602 int i;
2603 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002604 struct cifs_posix_ace *pACE;
2605 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2606 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2609 return -EOPNOTSUPP;
2610
Steve French790fe572007-07-07 19:25:05 +00002611 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 count = le16_to_cpu(cifs_acl->access_entry_count);
2613 pACE = &cifs_acl->ace_array[0];
2614 size = sizeof(struct cifs_posix_acl);
2615 size += sizeof(struct cifs_posix_ace) * count;
2616 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002617 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002618 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2619 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 return -EINVAL;
2621 }
Steve French790fe572007-07-07 19:25:05 +00002622 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 count = le16_to_cpu(cifs_acl->access_entry_count);
2624 size = sizeof(struct cifs_posix_acl);
2625 size += sizeof(struct cifs_posix_ace) * count;
2626/* skip past access ACEs to get to default ACEs */
2627 pACE = &cifs_acl->ace_array[count];
2628 count = le16_to_cpu(cifs_acl->default_entry_count);
2629 size += sizeof(struct cifs_posix_ace) * count;
2630 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002631 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 return -EINVAL;
2633 } else {
2634 /* illegal type */
2635 return -EINVAL;
2636 }
2637
2638 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002639 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002640 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002641 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 return -ERANGE;
2643 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002644 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002645 for (i = 0; i < count ; i++) {
2646 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2647 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 }
2649 }
2650 return size;
2651}
2652
Steve French50c2f752007-07-13 00:33:32 +00002653static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2654 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655{
2656 __u16 rc = 0; /* 0 = ACL converted ok */
2657
Steve Frenchff7feac2005-11-15 16:45:16 -08002658 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2659 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002661 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 /* Probably no need to le convert -1 on any arch but can not hurt */
2663 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002664 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002665 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002666 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 return rc;
2668}
2669
2670/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002671static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2672 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673{
2674 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002675 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2676 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 int count;
2678 int i;
2679
Steve French790fe572007-07-07 19:25:05 +00002680 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 return 0;
2682
2683 count = posix_acl_xattr_count((size_t)buflen);
2684 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002685 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002686 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002687 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002688 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 return 0;
2690 }
2691 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002692 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002693 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002694 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002695 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 else {
Steve French50c2f752007-07-13 00:33:32 +00002697 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 return 0;
2699 }
Steve French50c2f752007-07-13 00:33:32 +00002700 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2702 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002703 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 /* ACE not converted */
2705 break;
2706 }
2707 }
Steve French790fe572007-07-07 19:25:05 +00002708 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2710 rc += sizeof(struct cifs_posix_acl);
2711 /* BB add check to make sure ACL does not overflow SMB */
2712 }
2713 return rc;
2714}
2715
2716int
2717CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002718 const unsigned char *searchName,
2719 char *acl_inf, const int buflen, const int acl_type,
2720 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721{
2722/* SMB_QUERY_POSIX_ACL */
2723 TRANSACTION2_QPI_REQ *pSMB = NULL;
2724 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2725 int rc = 0;
2726 int bytes_returned;
2727 int name_len;
2728 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002729
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2731
2732queryAclRetry:
2733 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2734 (void **) &pSMBr);
2735 if (rc)
2736 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002737
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2739 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002740 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002741 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 name_len++; /* trailing null */
2743 name_len *= 2;
2744 pSMB->FileName[name_len] = 0;
2745 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002746 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 name_len = strnlen(searchName, PATH_MAX);
2748 name_len++; /* trailing null */
2749 strncpy(pSMB->FileName, searchName, name_len);
2750 }
2751
2752 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2753 pSMB->TotalDataCount = 0;
2754 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002755 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 pSMB->MaxDataCount = cpu_to_le16(4000);
2757 pSMB->MaxSetupCount = 0;
2758 pSMB->Reserved = 0;
2759 pSMB->Flags = 0;
2760 pSMB->Timeout = 0;
2761 pSMB->Reserved2 = 0;
2762 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002763 offsetof(struct smb_com_transaction2_qpi_req,
2764 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 pSMB->DataCount = 0;
2766 pSMB->DataOffset = 0;
2767 pSMB->SetupCount = 1;
2768 pSMB->Reserved3 = 0;
2769 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2770 byte_count = params + 1 /* pad */ ;
2771 pSMB->TotalParameterCount = cpu_to_le16(params);
2772 pSMB->ParameterCount = pSMB->TotalParameterCount;
2773 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2774 pSMB->Reserved4 = 0;
2775 pSMB->hdr.smb_buf_length += byte_count;
2776 pSMB->ByteCount = cpu_to_le16(byte_count);
2777
2778 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2779 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002780 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 if (rc) {
2782 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2783 } else {
2784 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002785
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2787 if (rc || (pSMBr->ByteCount < 2))
2788 /* BB also check enough total bytes returned */
2789 rc = -EIO; /* bad smb */
2790 else {
2791 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2792 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2793 rc = cifs_copy_posix_acl(acl_inf,
2794 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002795 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 }
2797 }
2798 cifs_buf_release(pSMB);
2799 if (rc == -EAGAIN)
2800 goto queryAclRetry;
2801 return rc;
2802}
2803
2804int
2805CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002806 const unsigned char *fileName,
2807 const char *local_acl, const int buflen,
2808 const int acl_type,
2809 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810{
2811 struct smb_com_transaction2_spi_req *pSMB = NULL;
2812 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2813 char *parm_data;
2814 int name_len;
2815 int rc = 0;
2816 int bytes_returned = 0;
2817 __u16 params, byte_count, data_count, param_offset, offset;
2818
2819 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2820setAclRetry:
2821 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002822 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 if (rc)
2824 return rc;
2825 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2826 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002827 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002828 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 name_len++; /* trailing null */
2830 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002831 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 name_len = strnlen(fileName, PATH_MAX);
2833 name_len++; /* trailing null */
2834 strncpy(pSMB->FileName, fileName, name_len);
2835 }
2836 params = 6 + name_len;
2837 pSMB->MaxParameterCount = cpu_to_le16(2);
2838 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2839 pSMB->MaxSetupCount = 0;
2840 pSMB->Reserved = 0;
2841 pSMB->Flags = 0;
2842 pSMB->Timeout = 0;
2843 pSMB->Reserved2 = 0;
2844 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002845 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 offset = param_offset + params;
2847 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2848 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2849
2850 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002851 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
Steve French790fe572007-07-07 19:25:05 +00002853 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 rc = -EOPNOTSUPP;
2855 goto setACLerrorExit;
2856 }
2857 pSMB->DataOffset = cpu_to_le16(offset);
2858 pSMB->SetupCount = 1;
2859 pSMB->Reserved3 = 0;
2860 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2861 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2862 byte_count = 3 /* pad */ + params + data_count;
2863 pSMB->DataCount = cpu_to_le16(data_count);
2864 pSMB->TotalDataCount = pSMB->DataCount;
2865 pSMB->ParameterCount = cpu_to_le16(params);
2866 pSMB->TotalParameterCount = pSMB->ParameterCount;
2867 pSMB->Reserved4 = 0;
2868 pSMB->hdr.smb_buf_length += byte_count;
2869 pSMB->ByteCount = cpu_to_le16(byte_count);
2870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 if (rc) {
2873 cFYI(1, ("Set POSIX ACL returned %d", rc));
2874 }
2875
2876setACLerrorExit:
2877 cifs_buf_release(pSMB);
2878 if (rc == -EAGAIN)
2879 goto setAclRetry;
2880 return rc;
2881}
2882
Steve Frenchf654bac2005-04-28 22:41:04 -07002883/* BB fix tabs in this function FIXME BB */
2884int
2885CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002886 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002887{
Steve French50c2f752007-07-13 00:33:32 +00002888 int rc = 0;
2889 struct smb_t2_qfi_req *pSMB = NULL;
2890 struct smb_t2_qfi_rsp *pSMBr = NULL;
2891 int bytes_returned;
2892 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002893
Steve French790fe572007-07-07 19:25:05 +00002894 cFYI(1, ("In GetExtAttr"));
2895 if (tcon == NULL)
2896 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002897
2898GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002899 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2900 (void **) &pSMBr);
2901 if (rc)
2902 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002903
Steve French790fe572007-07-07 19:25:05 +00002904 params = 2 /* level */ +2 /* fid */;
2905 pSMB->t2.TotalDataCount = 0;
2906 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2907 /* BB find exact max data count below from sess structure BB */
2908 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2909 pSMB->t2.MaxSetupCount = 0;
2910 pSMB->t2.Reserved = 0;
2911 pSMB->t2.Flags = 0;
2912 pSMB->t2.Timeout = 0;
2913 pSMB->t2.Reserved2 = 0;
2914 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2915 Fid) - 4);
2916 pSMB->t2.DataCount = 0;
2917 pSMB->t2.DataOffset = 0;
2918 pSMB->t2.SetupCount = 1;
2919 pSMB->t2.Reserved3 = 0;
2920 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2921 byte_count = params + 1 /* pad */ ;
2922 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2923 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2924 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2925 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002926 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002927 pSMB->hdr.smb_buf_length += byte_count;
2928 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002929
Steve French790fe572007-07-07 19:25:05 +00002930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2932 if (rc) {
2933 cFYI(1, ("error %d in GetExtAttr", rc));
2934 } else {
2935 /* decode response */
2936 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2937 if (rc || (pSMBr->ByteCount < 2))
2938 /* BB also check enough total bytes returned */
2939 /* If rc should we check for EOPNOSUPP and
2940 disable the srvino flag? or in caller? */
2941 rc = -EIO; /* bad smb */
2942 else {
2943 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2944 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2945 struct file_chattr_info *pfinfo;
2946 /* BB Do we need a cast or hash here ? */
2947 if (count != 16) {
2948 cFYI(1, ("Illegal size ret in GetExtAttr"));
2949 rc = -EIO;
2950 goto GetExtAttrOut;
2951 }
2952 pfinfo = (struct file_chattr_info *)
2953 (data_offset + (char *) &pSMBr->hdr.Protocol);
2954 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07002955 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00002956 }
2957 }
Steve Frenchf654bac2005-04-28 22:41:04 -07002958GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00002959 cifs_buf_release(pSMB);
2960 if (rc == -EAGAIN)
2961 goto GetExtAttrRetry;
2962 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002963}
2964
Steve Frenchf654bac2005-04-28 22:41:04 -07002965#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
Steve Frencheeac8042006-01-13 21:34:58 -08002967
2968/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002969static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00002970 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002971/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002972static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00002973 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002974
Steve French0a4b92c2006-01-12 15:44:21 -08002975/* Convert CIFS ACL to POSIX form */
Steve French50c2f752007-07-13 00:33:32 +00002976static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002977{
Steve French0a4b92c2006-01-12 15:44:21 -08002978 return 0;
2979}
2980
2981/* Get Security Descriptor (by handle) from remote server for a file or dir */
2982int
2983CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French50c2f752007-07-13 00:33:32 +00002984 /* BB fix up return info */ char *acl_inf, const int buflen,
Steve French0a4b92c2006-01-12 15:44:21 -08002985 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2986{
2987 int rc = 0;
2988 int buf_type = 0;
2989 QUERY_SEC_DESC_REQ * pSMB;
2990 struct kvec iov[1];
2991
2992 cFYI(1, ("GetCifsACL"));
2993
Steve French50c2f752007-07-13 00:33:32 +00002994 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08002995 8 /* parm len */, tcon, (void **) &pSMB);
2996 if (rc)
2997 return rc;
2998
2999 pSMB->MaxParameterCount = cpu_to_le32(4);
3000 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3001 pSMB->MaxSetupCount = 0;
3002 pSMB->Fid = fid; /* file handle always le */
3003 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3004 CIFS_ACL_DACL);
3005 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3006 pSMB->hdr.smb_buf_length += 11;
3007 iov[0].iov_base = (char *)pSMB;
3008 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3009
3010 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3011 cifs_stats_inc(&tcon->num_acl_get);
3012 if (rc) {
3013 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3014 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003015 struct cifs_sid *psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003016 __le32 * parm;
3017 int parm_len;
3018 int data_len;
3019 int acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003020 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08003021
3022/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003023 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French0a4b92c2006-01-12 15:44:21 -08003024 (char **)&psec_desc,
3025 &parm_len, &data_len);
Steve French790fe572007-07-07 19:25:05 +00003026 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003027 goto qsec_out;
3028 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3029
Steve French50c2f752007-07-13 00:33:32 +00003030 cERROR(1, ("smb %p parm %p data %p",
3031 pSMBr, parm, psec_desc)); /* BB removeme BB */
Steve French0a4b92c2006-01-12 15:44:21 -08003032
3033 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3034 rc = -EIO; /* bad smb */
3035 goto qsec_out;
3036 }
3037
3038/* BB check that data area is minimum length and as big as acl_len */
3039
3040 acl_len = le32_to_cpu(*(__le32 *)parm);
Steve French790fe572007-07-07 19:25:05 +00003041 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003042
3043 parse_sec_desc(psec_desc, acl_len);
3044 }
3045qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003046 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003047 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003048 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003049 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003050/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003051 return rc;
3052}
3053
Steve French6b8edfe2005-08-23 20:26:03 -07003054/* Legacy Query Path Information call for lookup to old servers such
3055 as Win9x/WinME */
3056int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003057 const unsigned char *searchName,
3058 FILE_ALL_INFO *pFinfo,
3059 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003060{
3061 QUERY_INFORMATION_REQ * pSMB;
3062 QUERY_INFORMATION_RSP * pSMBr;
3063 int rc = 0;
3064 int bytes_returned;
3065 int name_len;
3066
Steve French50c2f752007-07-13 00:33:32 +00003067 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003068QInfRetry:
3069 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003070 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003071 if (rc)
3072 return rc;
3073
3074 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3075 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003076 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3077 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003078 name_len++; /* trailing null */
3079 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003080 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003081 name_len = strnlen(searchName, PATH_MAX);
3082 name_len++; /* trailing null */
3083 strncpy(pSMB->FileName, searchName, name_len);
3084 }
3085 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003086 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003087 pSMB->hdr.smb_buf_length += (__u16) name_len;
3088 pSMB->ByteCount = cpu_to_le16(name_len);
3089
3090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003092 if (rc) {
3093 cFYI(1, ("Send error in QueryInfo = %d", rc));
3094 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003095 struct timespec ts;
3096 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3097 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003098 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003099 ts.tv_nsec = 0;
3100 ts.tv_sec = time;
3101 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003102 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003103 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3104 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003105 pFinfo->AllocationSize =
3106 cpu_to_le64(le32_to_cpu(pSMBr->size));
3107 pFinfo->EndOfFile = pFinfo->AllocationSize;
3108 pFinfo->Attributes =
3109 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003110 } else
3111 rc = -EIO; /* bad buffer passed in */
3112
3113 cifs_buf_release(pSMB);
3114
3115 if (rc == -EAGAIN)
3116 goto QInfRetry;
3117
3118 return rc;
3119}
3120
3121
3122
3123
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124int
3125CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3126 const unsigned char *searchName,
3127 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003128 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003129 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130{
3131/* level 263 SMB_QUERY_FILE_ALL_INFO */
3132 TRANSACTION2_QPI_REQ *pSMB = NULL;
3133 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3134 int rc = 0;
3135 int bytes_returned;
3136 int name_len;
3137 __u16 params, byte_count;
3138
3139/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3140QPathInfoRetry:
3141 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3142 (void **) &pSMBr);
3143 if (rc)
3144 return rc;
3145
3146 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3147 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003148 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003149 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 name_len++; /* trailing null */
3151 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003152 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 name_len = strnlen(searchName, PATH_MAX);
3154 name_len++; /* trailing null */
3155 strncpy(pSMB->FileName, searchName, name_len);
3156 }
3157
Steve French50c2f752007-07-13 00:33:32 +00003158 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 pSMB->TotalDataCount = 0;
3160 pSMB->MaxParameterCount = cpu_to_le16(2);
3161 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3162 pSMB->MaxSetupCount = 0;
3163 pSMB->Reserved = 0;
3164 pSMB->Flags = 0;
3165 pSMB->Timeout = 0;
3166 pSMB->Reserved2 = 0;
3167 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003168 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 pSMB->DataCount = 0;
3170 pSMB->DataOffset = 0;
3171 pSMB->SetupCount = 1;
3172 pSMB->Reserved3 = 0;
3173 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3174 byte_count = params + 1 /* pad */ ;
3175 pSMB->TotalParameterCount = cpu_to_le16(params);
3176 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003177 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003178 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3179 else
3180 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 pSMB->Reserved4 = 0;
3182 pSMB->hdr.smb_buf_length += byte_count;
3183 pSMB->ByteCount = cpu_to_le16(byte_count);
3184
3185 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3186 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3187 if (rc) {
3188 cFYI(1, ("Send error in QPathInfo = %d", rc));
3189 } else { /* decode response */
3190 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3191
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003192 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3193 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003194 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003196 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003197 rc = -EIO; /* 24 or 26 expected but we do not read
3198 last field */
3199 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003200 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003202 if (legacy) /* we do not read the last field, EAsize,
3203 fortunately since it varies by subdialect
3204 and on Set vs. Get, is two bytes or 4
3205 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003206 size = sizeof(FILE_INFO_STANDARD);
3207 else
3208 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 memcpy((char *) pFindData,
3210 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003211 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 } else
3213 rc = -ENOMEM;
3214 }
3215 cifs_buf_release(pSMB);
3216 if (rc == -EAGAIN)
3217 goto QPathInfoRetry;
3218
3219 return rc;
3220}
3221
3222int
3223CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3224 const unsigned char *searchName,
3225 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003226 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227{
3228/* SMB_QUERY_FILE_UNIX_BASIC */
3229 TRANSACTION2_QPI_REQ *pSMB = NULL;
3230 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3231 int rc = 0;
3232 int bytes_returned = 0;
3233 int name_len;
3234 __u16 params, byte_count;
3235
3236 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3237UnixQPathInfoRetry:
3238 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3239 (void **) &pSMBr);
3240 if (rc)
3241 return rc;
3242
3243 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3244 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003245 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003246 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 name_len++; /* trailing null */
3248 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003249 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 name_len = strnlen(searchName, PATH_MAX);
3251 name_len++; /* trailing null */
3252 strncpy(pSMB->FileName, searchName, name_len);
3253 }
3254
Steve French50c2f752007-07-13 00:33:32 +00003255 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 pSMB->TotalDataCount = 0;
3257 pSMB->MaxParameterCount = cpu_to_le16(2);
3258 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003259 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 pSMB->MaxSetupCount = 0;
3261 pSMB->Reserved = 0;
3262 pSMB->Flags = 0;
3263 pSMB->Timeout = 0;
3264 pSMB->Reserved2 = 0;
3265 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003266 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 pSMB->DataCount = 0;
3268 pSMB->DataOffset = 0;
3269 pSMB->SetupCount = 1;
3270 pSMB->Reserved3 = 0;
3271 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3272 byte_count = params + 1 /* pad */ ;
3273 pSMB->TotalParameterCount = cpu_to_le16(params);
3274 pSMB->ParameterCount = pSMB->TotalParameterCount;
3275 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3276 pSMB->Reserved4 = 0;
3277 pSMB->hdr.smb_buf_length += byte_count;
3278 pSMB->ByteCount = cpu_to_le16(byte_count);
3279
3280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3281 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3282 if (rc) {
3283 cFYI(1, ("Send error in QPathInfo = %d", rc));
3284 } else { /* decode response */
3285 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3286
3287 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3288 rc = -EIO; /* bad smb */
3289 } else {
3290 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3291 memcpy((char *) pFindData,
3292 (char *) &pSMBr->hdr.Protocol +
3293 data_offset,
3294 sizeof (FILE_UNIX_BASIC_INFO));
3295 }
3296 }
3297 cifs_buf_release(pSMB);
3298 if (rc == -EAGAIN)
3299 goto UnixQPathInfoRetry;
3300
3301 return rc;
3302}
3303
3304#if 0 /* function unused at present */
3305int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3306 const char *searchName, FILE_ALL_INFO * findData,
3307 const struct nls_table *nls_codepage)
3308{
3309/* level 257 SMB_ */
3310 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3311 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3312 int rc = 0;
3313 int bytes_returned;
3314 int name_len;
3315 __u16 params, byte_count;
3316
3317 cFYI(1, ("In FindUnique"));
3318findUniqueRetry:
3319 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3320 (void **) &pSMBr);
3321 if (rc)
3322 return rc;
3323
3324 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3325 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003326 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3327 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 name_len++; /* trailing null */
3329 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003330 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 name_len = strnlen(searchName, PATH_MAX);
3332 name_len++; /* trailing null */
3333 strncpy(pSMB->FileName, searchName, name_len);
3334 }
3335
3336 params = 12 + name_len /* includes null */ ;
3337 pSMB->TotalDataCount = 0; /* no EAs */
3338 pSMB->MaxParameterCount = cpu_to_le16(2);
3339 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3340 pSMB->MaxSetupCount = 0;
3341 pSMB->Reserved = 0;
3342 pSMB->Flags = 0;
3343 pSMB->Timeout = 0;
3344 pSMB->Reserved2 = 0;
3345 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003346 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 pSMB->DataCount = 0;
3348 pSMB->DataOffset = 0;
3349 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3350 pSMB->Reserved3 = 0;
3351 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3352 byte_count = params + 1 /* pad */ ;
3353 pSMB->TotalParameterCount = cpu_to_le16(params);
3354 pSMB->ParameterCount = pSMB->TotalParameterCount;
3355 pSMB->SearchAttributes =
3356 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3357 ATTR_DIRECTORY);
3358 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3359 pSMB->SearchFlags = cpu_to_le16(1);
3360 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3361 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3362 pSMB->hdr.smb_buf_length += byte_count;
3363 pSMB->ByteCount = cpu_to_le16(byte_count);
3364
3365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3366 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3367
3368 if (rc) {
3369 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3370 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003371 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 /* BB fill in */
3373 }
3374
3375 cifs_buf_release(pSMB);
3376 if (rc == -EAGAIN)
3377 goto findUniqueRetry;
3378
3379 return rc;
3380}
3381#endif /* end unused (temporarily) function */
3382
3383/* xid, tcon, searchName and codepage are input parms, rest are returned */
3384int
3385CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003386 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003388 __u16 *pnetfid,
3389 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390{
3391/* level 257 SMB_ */
3392 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3393 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3394 T2_FFIRST_RSP_PARMS * parms;
3395 int rc = 0;
3396 int bytes_returned = 0;
3397 int name_len;
3398 __u16 params, byte_count;
3399
Steve French50c2f752007-07-13 00:33:32 +00003400 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401
3402findFirstRetry:
3403 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3404 (void **) &pSMBr);
3405 if (rc)
3406 return rc;
3407
3408 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3409 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003410 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003411 PATH_MAX, nls_codepage, remap);
3412 /* We can not add the asterik earlier in case
3413 it got remapped to 0xF03A as if it were part of the
3414 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003416 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003417 pSMB->FileName[name_len+1] = 0;
3418 pSMB->FileName[name_len+2] = '*';
3419 pSMB->FileName[name_len+3] = 0;
3420 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3422 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003423 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 } else { /* BB add check for overrun of SMB buf BB */
3425 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003427 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 free buffer exit; BB */
3429 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003430 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003431 pSMB->FileName[name_len+1] = '*';
3432 pSMB->FileName[name_len+2] = 0;
3433 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 }
3435
3436 params = 12 + name_len /* includes null */ ;
3437 pSMB->TotalDataCount = 0; /* no EAs */
3438 pSMB->MaxParameterCount = cpu_to_le16(10);
3439 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3440 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3441 pSMB->MaxSetupCount = 0;
3442 pSMB->Reserved = 0;
3443 pSMB->Flags = 0;
3444 pSMB->Timeout = 0;
3445 pSMB->Reserved2 = 0;
3446 byte_count = params + 1 /* pad */ ;
3447 pSMB->TotalParameterCount = cpu_to_le16(params);
3448 pSMB->ParameterCount = pSMB->TotalParameterCount;
3449 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003450 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3451 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 pSMB->DataCount = 0;
3453 pSMB->DataOffset = 0;
3454 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3455 pSMB->Reserved3 = 0;
3456 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3457 pSMB->SearchAttributes =
3458 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3459 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003460 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3461 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 CIFS_SEARCH_RETURN_RESUME);
3463 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3464
3465 /* BB what should we set StorageType to? Does it matter? BB */
3466 pSMB->SearchStorageType = 0;
3467 pSMB->hdr.smb_buf_length += byte_count;
3468 pSMB->ByteCount = cpu_to_le16(byte_count);
3469
3470 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003472 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473
Steve French88274812006-03-09 22:21:45 +00003474 if (rc) {/* BB add logic to retry regular search if Unix search
3475 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 /* BB Add code to handle unsupported level rc */
3477 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003478
Steve French88274812006-03-09 22:21:45 +00003479 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480
3481 /* BB eventually could optimize out free and realloc of buf */
3482 /* for this case */
3483 if (rc == -EAGAIN)
3484 goto findFirstRetry;
3485 } else { /* decode response */
3486 /* BB remember to free buffer if error BB */
3487 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003488 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3490 psrch_inf->unicode = TRUE;
3491 else
3492 psrch_inf->unicode = FALSE;
3493
3494 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003495 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003496 psrch_inf->srch_entries_start =
3497 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3500 le16_to_cpu(pSMBr->t2.ParameterOffset));
3501
Steve French790fe572007-07-07 19:25:05 +00003502 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 psrch_inf->endOfSearch = TRUE;
3504 else
3505 psrch_inf->endOfSearch = FALSE;
3506
Steve French50c2f752007-07-13 00:33:32 +00003507 psrch_inf->entries_in_buffer =
3508 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003509 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 *pnetfid = parms->SearchHandle;
3512 } else {
3513 cifs_buf_release(pSMB);
3514 }
3515 }
3516
3517 return rc;
3518}
3519
3520int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003521 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522{
3523 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3524 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3525 T2_FNEXT_RSP_PARMS * parms;
3526 char *response_data;
3527 int rc = 0;
3528 int bytes_returned, name_len;
3529 __u16 params, byte_count;
3530
3531 cFYI(1, ("In FindNext"));
3532
Steve French790fe572007-07-07 19:25:05 +00003533 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 return -ENOENT;
3535
3536 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3537 (void **) &pSMBr);
3538 if (rc)
3539 return rc;
3540
Steve French50c2f752007-07-13 00:33:32 +00003541 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 byte_count = 0;
3543 pSMB->TotalDataCount = 0; /* no EAs */
3544 pSMB->MaxParameterCount = cpu_to_le16(8);
3545 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003546 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3547 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 pSMB->MaxSetupCount = 0;
3549 pSMB->Reserved = 0;
3550 pSMB->Flags = 0;
3551 pSMB->Timeout = 0;
3552 pSMB->Reserved2 = 0;
3553 pSMB->ParameterOffset = cpu_to_le16(
3554 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3555 pSMB->DataCount = 0;
3556 pSMB->DataOffset = 0;
3557 pSMB->SetupCount = 1;
3558 pSMB->Reserved3 = 0;
3559 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3560 pSMB->SearchHandle = searchHandle; /* always kept as le */
3561 pSMB->SearchCount =
3562 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3563 /* test for Unix extensions */
3564/* if (tcon->ses->capabilities & CAP_UNIX) {
3565 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3566 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3567 } else {
3568 pSMB->InformationLevel =
3569 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3570 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3571 } */
3572 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3573 pSMB->ResumeKey = psrch_inf->resume_key;
3574 pSMB->SearchFlags =
3575 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3576
3577 name_len = psrch_inf->resume_name_len;
3578 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003579 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3581 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003582 /* 14 byte parm len above enough for 2 byte null terminator */
3583 pSMB->ResumeFileName[name_len] = 0;
3584 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 } else {
3586 rc = -EINVAL;
3587 goto FNext2_err_exit;
3588 }
3589 byte_count = params + 1 /* pad */ ;
3590 pSMB->TotalParameterCount = cpu_to_le16(params);
3591 pSMB->ParameterCount = pSMB->TotalParameterCount;
3592 pSMB->hdr.smb_buf_length += byte_count;
3593 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003594
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3596 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003597 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 if (rc) {
3599 if (rc == -EBADF) {
3600 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003601 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 } else
3603 cFYI(1, ("FindNext returned = %d", rc));
3604 } else { /* decode response */
3605 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003606
Steve French790fe572007-07-07 19:25:05 +00003607 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 /* BB fixme add lock for file (srch_info) struct here */
3609 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3610 psrch_inf->unicode = TRUE;
3611 else
3612 psrch_inf->unicode = FALSE;
3613 response_data = (char *) &pSMBr->hdr.Protocol +
3614 le16_to_cpu(pSMBr->t2.ParameterOffset);
3615 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3616 response_data = (char *)&pSMBr->hdr.Protocol +
3617 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003618 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003619 cifs_small_buf_release(
3620 psrch_inf->ntwrk_buf_start);
3621 else
3622 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 psrch_inf->srch_entries_start = response_data;
3624 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003625 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003626 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 psrch_inf->endOfSearch = TRUE;
3628 else
3629 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003630 psrch_inf->entries_in_buffer =
3631 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 psrch_inf->index_of_last_entry +=
3633 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003634/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3635 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636
3637 /* BB fixme add unlock here */
3638 }
3639
3640 }
3641
3642 /* BB On error, should we leave previous search buf (and count and
3643 last entry fields) intact or free the previous one? */
3644
3645 /* Note: On -EAGAIN error only caller can retry on handle based calls
3646 since file handle passed in no longer valid */
3647FNext2_err_exit:
3648 if (rc != 0)
3649 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 return rc;
3651}
3652
3653int
Steve French50c2f752007-07-13 00:33:32 +00003654CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3655 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656{
3657 int rc = 0;
3658 FINDCLOSE_REQ *pSMB = NULL;
3659 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3660 int bytes_returned;
3661
3662 cFYI(1, ("In CIFSSMBFindClose"));
3663 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3664
3665 /* no sense returning error if session restarted
3666 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003667 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 return 0;
3669 if (rc)
3670 return rc;
3671
3672 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3673 pSMB->FileID = searchHandle;
3674 pSMB->ByteCount = 0;
3675 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3677 if (rc) {
3678 cERROR(1, ("Send error in FindClose = %d", rc));
3679 }
Steve Frencha4544342005-08-24 13:59:35 -07003680 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 cifs_small_buf_release(pSMB);
3682
3683 /* Since session is dead, search handle closed on server already */
3684 if (rc == -EAGAIN)
3685 rc = 0;
3686
3687 return rc;
3688}
3689
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690int
3691CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003692 const unsigned char *searchName,
3693 __u64 * inode_number,
3694 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695{
3696 int rc = 0;
3697 TRANSACTION2_QPI_REQ *pSMB = NULL;
3698 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3699 int name_len, bytes_returned;
3700 __u16 params, byte_count;
3701
Steve French50c2f752007-07-13 00:33:32 +00003702 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003703 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003704 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
3706GetInodeNumberRetry:
3707 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003708 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 if (rc)
3710 return rc;
3711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3713 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003714 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003715 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 name_len++; /* trailing null */
3717 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003718 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 name_len = strnlen(searchName, PATH_MAX);
3720 name_len++; /* trailing null */
3721 strncpy(pSMB->FileName, searchName, name_len);
3722 }
3723
3724 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3725 pSMB->TotalDataCount = 0;
3726 pSMB->MaxParameterCount = cpu_to_le16(2);
3727 /* BB find exact max data count below from sess structure BB */
3728 pSMB->MaxDataCount = cpu_to_le16(4000);
3729 pSMB->MaxSetupCount = 0;
3730 pSMB->Reserved = 0;
3731 pSMB->Flags = 0;
3732 pSMB->Timeout = 0;
3733 pSMB->Reserved2 = 0;
3734 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003735 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 pSMB->DataCount = 0;
3737 pSMB->DataOffset = 0;
3738 pSMB->SetupCount = 1;
3739 pSMB->Reserved3 = 0;
3740 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3741 byte_count = params + 1 /* pad */ ;
3742 pSMB->TotalParameterCount = cpu_to_le16(params);
3743 pSMB->ParameterCount = pSMB->TotalParameterCount;
3744 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3745 pSMB->Reserved4 = 0;
3746 pSMB->hdr.smb_buf_length += byte_count;
3747 pSMB->ByteCount = cpu_to_le16(byte_count);
3748
3749 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3750 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3751 if (rc) {
3752 cFYI(1, ("error %d in QueryInternalInfo", rc));
3753 } else {
3754 /* decode response */
3755 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3756 if (rc || (pSMBr->ByteCount < 2))
3757 /* BB also check enough total bytes returned */
3758 /* If rc should we check for EOPNOSUPP and
3759 disable the srvino flag? or in caller? */
3760 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003761 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3763 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003764 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003766 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3768 rc = -EIO;
3769 goto GetInodeNumOut;
3770 }
3771 pfinfo = (struct file_internal_info *)
3772 (data_offset + (char *) &pSMBr->hdr.Protocol);
3773 *inode_number = pfinfo->UniqueId;
3774 }
3775 }
3776GetInodeNumOut:
3777 cifs_buf_release(pSMB);
3778 if (rc == -EAGAIN)
3779 goto GetInodeNumberRetry;
3780 return rc;
3781}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
3783int
3784CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3785 const unsigned char *searchName,
3786 unsigned char **targetUNCs,
3787 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003788 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789{
3790/* TRANS2_GET_DFS_REFERRAL */
3791 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3792 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003793 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 int rc = 0;
3795 int bytes_returned;
3796 int name_len;
3797 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003798 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 __u16 params, byte_count;
3800 *number_of_UNC_in_array = 0;
3801 *targetUNCs = NULL;
3802
3803 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3804 if (ses == NULL)
3805 return -ENODEV;
3806getDFSRetry:
3807 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3808 (void **) &pSMBr);
3809 if (rc)
3810 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003811
3812 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003813 but should never be null here anyway */
3814 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 pSMB->hdr.Tid = ses->ipc_tid;
3816 pSMB->hdr.Uid = ses->Suid;
3817 if (ses->capabilities & CAP_STATUS32) {
3818 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3819 }
3820 if (ses->capabilities & CAP_DFS) {
3821 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3822 }
3823
3824 if (ses->capabilities & CAP_UNICODE) {
3825 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3826 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003827 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003828 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 name_len++; /* trailing null */
3830 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003831 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 name_len = strnlen(searchName, PATH_MAX);
3833 name_len++; /* trailing null */
3834 strncpy(pSMB->RequestFileName, searchName, name_len);
3835 }
3836
Steve French790fe572007-07-07 19:25:05 +00003837 if (ses->server) {
3838 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003839 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3840 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3841 }
3842
Steve French50c2f752007-07-13 00:33:32 +00003843 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003844
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 params = 2 /* level */ + name_len /*includes null */ ;
3846 pSMB->TotalDataCount = 0;
3847 pSMB->DataCount = 0;
3848 pSMB->DataOffset = 0;
3849 pSMB->MaxParameterCount = 0;
3850 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3851 pSMB->MaxSetupCount = 0;
3852 pSMB->Reserved = 0;
3853 pSMB->Flags = 0;
3854 pSMB->Timeout = 0;
3855 pSMB->Reserved2 = 0;
3856 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003857 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 pSMB->SetupCount = 1;
3859 pSMB->Reserved3 = 0;
3860 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3861 byte_count = params + 3 /* pad */ ;
3862 pSMB->ParameterCount = cpu_to_le16(params);
3863 pSMB->TotalParameterCount = pSMB->ParameterCount;
3864 pSMB->MaxReferralLevel = cpu_to_le16(3);
3865 pSMB->hdr.smb_buf_length += byte_count;
3866 pSMB->ByteCount = cpu_to_le16(byte_count);
3867
3868 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3870 if (rc) {
3871 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3872 } else { /* decode response */
3873/* BB Add logic to parse referrals here */
3874 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3875
Steve French50c2f752007-07-13 00:33:32 +00003876 /* BB Also check if enough total bytes returned? */
3877 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 rc = -EIO; /* bad smb */
3879 else {
Steve French50c2f752007-07-13 00:33:32 +00003880 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3882
3883 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003884 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003886 referrals =
3887 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 (8 /* sizeof start of data block */ +
3889 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003890 (char *) &pSMBr->hdr.Protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 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 +00003892 le16_to_cpu(pSMBr->NumberOfReferrals),
3893 le16_to_cpu(pSMBr->DFSFlags),
3894 le16_to_cpu(referrals->ReferralSize),
3895 le16_to_cpu(referrals->ServerType),
3896 le16_to_cpu(referrals->ReferralFlags),
3897 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 /* BB This field is actually two bytes in from start of
3899 data block so we could do safety check that DataBlock
3900 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003901 *number_of_UNC_in_array =
3902 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
3904 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003905 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 *number_of_UNC_in_array = 1;
3907
3908 /* get the length of the strings describing refs */
3909 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003910 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003912 __u16 offset =
3913 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003915 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 not try to copy any more */
3917 *number_of_UNC_in_array = i;
3918 break;
Steve French50c2f752007-07-13 00:33:32 +00003919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 temp = ((char *)referrals) + offset;
3921
3922 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00003923 name_len += UniStrnlen((wchar_t *)temp,
3924 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 } else {
Steve French50c2f752007-07-13 00:33:32 +00003926 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 }
3928 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00003929 /* BB add check that referral pointer does
3930 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 }
3932 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00003933 *targetUNCs =
3934 kmalloc(name_len+1+(*number_of_UNC_in_array),
3935 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00003936 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 rc = -ENOMEM;
3938 goto GetDFSRefExit;
3939 }
3940 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00003941 referrals = (struct dfs_referral_level_3 *)
3942 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 (char *) &pSMBr->hdr.Protocol);
3944
Steve French50c2f752007-07-13 00:33:32 +00003945 for (i = 0; i < *number_of_UNC_in_array; i++) {
3946 temp = ((char *)referrals) +
3947 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3949 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00003950 (__le16 *) temp,
3951 name_len,
3952 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 } else {
Steve French50c2f752007-07-13 00:33:32 +00003954 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 }
3956 /* BB update target_uncs pointers */
3957 referrals++;
3958 }
3959 temp = *targetUNCs;
3960 temp[name_len] = 0;
3961 }
3962
3963 }
3964GetDFSRefExit:
3965 if (pSMB)
3966 cifs_buf_release(pSMB);
3967
3968 if (rc == -EAGAIN)
3969 goto getDFSRetry;
3970
3971 return rc;
3972}
3973
Steve French20962432005-09-21 22:05:57 -07003974/* Query File System Info such as free space to old servers such as Win 9x */
3975int
3976SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3977{
3978/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3979 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3980 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3981 FILE_SYSTEM_ALLOC_INFO *response_data;
3982 int rc = 0;
3983 int bytes_returned = 0;
3984 __u16 params, byte_count;
3985
3986 cFYI(1, ("OldQFSInfo"));
3987oldQFSInfoRetry:
3988 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3989 (void **) &pSMBr);
3990 if (rc)
3991 return rc;
3992 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3993 (void **) &pSMBr);
3994 if (rc)
3995 return rc;
3996
3997 params = 2; /* level */
3998 pSMB->TotalDataCount = 0;
3999 pSMB->MaxParameterCount = cpu_to_le16(2);
4000 pSMB->MaxDataCount = cpu_to_le16(1000);
4001 pSMB->MaxSetupCount = 0;
4002 pSMB->Reserved = 0;
4003 pSMB->Flags = 0;
4004 pSMB->Timeout = 0;
4005 pSMB->Reserved2 = 0;
4006 byte_count = params + 1 /* pad */ ;
4007 pSMB->TotalParameterCount = cpu_to_le16(params);
4008 pSMB->ParameterCount = pSMB->TotalParameterCount;
4009 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4010 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4011 pSMB->DataCount = 0;
4012 pSMB->DataOffset = 0;
4013 pSMB->SetupCount = 1;
4014 pSMB->Reserved3 = 0;
4015 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4016 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4017 pSMB->hdr.smb_buf_length += byte_count;
4018 pSMB->ByteCount = cpu_to_le16(byte_count);
4019
4020 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4021 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4022 if (rc) {
4023 cFYI(1, ("Send error in QFSInfo = %d", rc));
4024 } else { /* decode response */
4025 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4026
4027 if (rc || (pSMBr->ByteCount < 18))
4028 rc = -EIO; /* bad smb */
4029 else {
4030 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004031 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004032 pSMBr->ByteCount, data_offset));
4033
Steve French50c2f752007-07-13 00:33:32 +00004034 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004035 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4036 FSData->f_bsize =
4037 le16_to_cpu(response_data->BytesPerSector) *
4038 le32_to_cpu(response_data->
4039 SectorsPerAllocationUnit);
4040 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004041 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004042 FSData->f_bfree = FSData->f_bavail =
4043 le32_to_cpu(response_data->FreeAllocationUnits);
4044 cFYI(1,
4045 ("Blocks: %lld Free: %lld Block size %ld",
4046 (unsigned long long)FSData->f_blocks,
4047 (unsigned long long)FSData->f_bfree,
4048 FSData->f_bsize));
4049 }
4050 }
4051 cifs_buf_release(pSMB);
4052
4053 if (rc == -EAGAIN)
4054 goto oldQFSInfoRetry;
4055
4056 return rc;
4057}
4058
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059int
Steve French737b7582005-04-28 22:41:06 -07004060CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061{
4062/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4063 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4064 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4065 FILE_SYSTEM_INFO *response_data;
4066 int rc = 0;
4067 int bytes_returned = 0;
4068 __u16 params, byte_count;
4069
4070 cFYI(1, ("In QFSInfo"));
4071QFSInfoRetry:
4072 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4073 (void **) &pSMBr);
4074 if (rc)
4075 return rc;
4076
4077 params = 2; /* level */
4078 pSMB->TotalDataCount = 0;
4079 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004080 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 pSMB->MaxSetupCount = 0;
4082 pSMB->Reserved = 0;
4083 pSMB->Flags = 0;
4084 pSMB->Timeout = 0;
4085 pSMB->Reserved2 = 0;
4086 byte_count = params + 1 /* pad */ ;
4087 pSMB->TotalParameterCount = cpu_to_le16(params);
4088 pSMB->ParameterCount = pSMB->TotalParameterCount;
4089 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004090 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 pSMB->DataCount = 0;
4092 pSMB->DataOffset = 0;
4093 pSMB->SetupCount = 1;
4094 pSMB->Reserved3 = 0;
4095 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4096 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4097 pSMB->hdr.smb_buf_length += byte_count;
4098 pSMB->ByteCount = cpu_to_le16(byte_count);
4099
4100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4102 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004103 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
Steve French20962432005-09-21 22:05:57 -07004107 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 rc = -EIO; /* bad smb */
4109 else {
4110 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
4112 response_data =
4113 (FILE_SYSTEM_INFO
4114 *) (((char *) &pSMBr->hdr.Protocol) +
4115 data_offset);
4116 FSData->f_bsize =
4117 le32_to_cpu(response_data->BytesPerSector) *
4118 le32_to_cpu(response_data->
4119 SectorsPerAllocationUnit);
4120 FSData->f_blocks =
4121 le64_to_cpu(response_data->TotalAllocationUnits);
4122 FSData->f_bfree = FSData->f_bavail =
4123 le64_to_cpu(response_data->FreeAllocationUnits);
4124 cFYI(1,
4125 ("Blocks: %lld Free: %lld Block size %ld",
4126 (unsigned long long)FSData->f_blocks,
4127 (unsigned long long)FSData->f_bfree,
4128 FSData->f_bsize));
4129 }
4130 }
4131 cifs_buf_release(pSMB);
4132
4133 if (rc == -EAGAIN)
4134 goto QFSInfoRetry;
4135
4136 return rc;
4137}
4138
4139int
Steve French737b7582005-04-28 22:41:06 -07004140CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141{
4142/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4143 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4144 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4145 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4146 int rc = 0;
4147 int bytes_returned = 0;
4148 __u16 params, byte_count;
4149
4150 cFYI(1, ("In QFSAttributeInfo"));
4151QFSAttributeRetry:
4152 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4153 (void **) &pSMBr);
4154 if (rc)
4155 return rc;
4156
4157 params = 2; /* level */
4158 pSMB->TotalDataCount = 0;
4159 pSMB->MaxParameterCount = cpu_to_le16(2);
4160 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4161 pSMB->MaxSetupCount = 0;
4162 pSMB->Reserved = 0;
4163 pSMB->Flags = 0;
4164 pSMB->Timeout = 0;
4165 pSMB->Reserved2 = 0;
4166 byte_count = params + 1 /* pad */ ;
4167 pSMB->TotalParameterCount = cpu_to_le16(params);
4168 pSMB->ParameterCount = pSMB->TotalParameterCount;
4169 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004170 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 pSMB->DataCount = 0;
4172 pSMB->DataOffset = 0;
4173 pSMB->SetupCount = 1;
4174 pSMB->Reserved3 = 0;
4175 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4176 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4177 pSMB->hdr.smb_buf_length += byte_count;
4178 pSMB->ByteCount = cpu_to_le16(byte_count);
4179
4180 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4181 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4182 if (rc) {
4183 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4184 } else { /* decode response */
4185 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4186
Steve French50c2f752007-07-13 00:33:32 +00004187 if (rc || (pSMBr->ByteCount < 13)) {
4188 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 rc = -EIO; /* bad smb */
4190 } else {
4191 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4192 response_data =
4193 (FILE_SYSTEM_ATTRIBUTE_INFO
4194 *) (((char *) &pSMBr->hdr.Protocol) +
4195 data_offset);
4196 memcpy(&tcon->fsAttrInfo, response_data,
4197 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4198 }
4199 }
4200 cifs_buf_release(pSMB);
4201
4202 if (rc == -EAGAIN)
4203 goto QFSAttributeRetry;
4204
4205 return rc;
4206}
4207
4208int
Steve French737b7582005-04-28 22:41:06 -07004209CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210{
4211/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4212 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4213 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4214 FILE_SYSTEM_DEVICE_INFO *response_data;
4215 int rc = 0;
4216 int bytes_returned = 0;
4217 __u16 params, byte_count;
4218
4219 cFYI(1, ("In QFSDeviceInfo"));
4220QFSDeviceRetry:
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
4241 pSMB->DataCount = 0;
4242 pSMB->DataOffset = 0;
4243 pSMB->SetupCount = 1;
4244 pSMB->Reserved3 = 0;
4245 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4246 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4247 pSMB->hdr.smb_buf_length += byte_count;
4248 pSMB->ByteCount = cpu_to_le16(byte_count);
4249
4250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4251 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4252 if (rc) {
4253 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4254 } else { /* decode response */
4255 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4256
4257 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4258 rc = -EIO; /* bad smb */
4259 else {
4260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4261 response_data =
Steve French737b7582005-04-28 22:41:06 -07004262 (FILE_SYSTEM_DEVICE_INFO *)
4263 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 data_offset);
4265 memcpy(&tcon->fsDevInfo, response_data,
4266 sizeof (FILE_SYSTEM_DEVICE_INFO));
4267 }
4268 }
4269 cifs_buf_release(pSMB);
4270
4271 if (rc == -EAGAIN)
4272 goto QFSDeviceRetry;
4273
4274 return rc;
4275}
4276
4277int
Steve French737b7582005-04-28 22:41:06 -07004278CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279{
4280/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4281 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4282 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4283 FILE_SYSTEM_UNIX_INFO *response_data;
4284 int rc = 0;
4285 int bytes_returned = 0;
4286 __u16 params, byte_count;
4287
4288 cFYI(1, ("In QFSUnixInfo"));
4289QFSUnixRetry:
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->DataCount = 0;
4298 pSMB->DataOffset = 0;
4299 pSMB->MaxParameterCount = cpu_to_le16(2);
4300 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4301 pSMB->MaxSetupCount = 0;
4302 pSMB->Reserved = 0;
4303 pSMB->Flags = 0;
4304 pSMB->Timeout = 0;
4305 pSMB->Reserved2 = 0;
4306 byte_count = params + 1 /* pad */ ;
4307 pSMB->ParameterCount = cpu_to_le16(params);
4308 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004309 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4310 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 pSMB->SetupCount = 1;
4312 pSMB->Reserved3 = 0;
4313 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4314 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4315 pSMB->hdr.smb_buf_length += byte_count;
4316 pSMB->ByteCount = cpu_to_le16(byte_count);
4317
4318 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4319 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4320 if (rc) {
4321 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4322 } else { /* decode response */
4323 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4324
4325 if (rc || (pSMBr->ByteCount < 13)) {
4326 rc = -EIO; /* bad smb */
4327 } else {
4328 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4329 response_data =
4330 (FILE_SYSTEM_UNIX_INFO
4331 *) (((char *) &pSMBr->hdr.Protocol) +
4332 data_offset);
4333 memcpy(&tcon->fsUnixInfo, response_data,
4334 sizeof (FILE_SYSTEM_UNIX_INFO));
4335 }
4336 }
4337 cifs_buf_release(pSMB);
4338
4339 if (rc == -EAGAIN)
4340 goto QFSUnixRetry;
4341
4342
4343 return rc;
4344}
4345
Jeremy Allisonac670552005-06-22 17:26:35 -07004346int
Steve French45abc6e2005-06-23 13:42:03 -05004347CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004348{
4349/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4350 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4351 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4352 int rc = 0;
4353 int bytes_returned = 0;
4354 __u16 params, param_offset, offset, byte_count;
4355
4356 cFYI(1, ("In SETFSUnixInfo"));
4357SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004358 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4360 (void **) &pSMBr);
4361 if (rc)
4362 return rc;
4363
4364 params = 4; /* 2 bytes zero followed by info level. */
4365 pSMB->MaxSetupCount = 0;
4366 pSMB->Reserved = 0;
4367 pSMB->Flags = 0;
4368 pSMB->Timeout = 0;
4369 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004370 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4371 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004372 offset = param_offset + params;
4373
4374 pSMB->MaxParameterCount = cpu_to_le16(4);
4375 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4376 pSMB->SetupCount = 1;
4377 pSMB->Reserved3 = 0;
4378 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4379 byte_count = 1 /* pad */ + params + 12;
4380
4381 pSMB->DataCount = cpu_to_le16(12);
4382 pSMB->ParameterCount = cpu_to_le16(params);
4383 pSMB->TotalDataCount = pSMB->DataCount;
4384 pSMB->TotalParameterCount = pSMB->ParameterCount;
4385 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4386 pSMB->DataOffset = cpu_to_le16(offset);
4387
4388 /* Params. */
4389 pSMB->FileNum = 0;
4390 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4391
4392 /* Data. */
4393 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4394 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4395 pSMB->ClientUnixCap = cpu_to_le64(cap);
4396
4397 pSMB->hdr.smb_buf_length += byte_count;
4398 pSMB->ByteCount = cpu_to_le16(byte_count);
4399
4400 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4401 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4402 if (rc) {
4403 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4404 } else { /* decode response */
4405 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4406 if (rc) {
4407 rc = -EIO; /* bad smb */
4408 }
4409 }
4410 cifs_buf_release(pSMB);
4411
4412 if (rc == -EAGAIN)
4413 goto SETFSUnixRetry;
4414
4415 return rc;
4416}
4417
4418
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419
4420int
4421CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004422 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423{
4424/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4425 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4426 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4427 FILE_SYSTEM_POSIX_INFO *response_data;
4428 int rc = 0;
4429 int bytes_returned = 0;
4430 __u16 params, byte_count;
4431
4432 cFYI(1, ("In QFSPosixInfo"));
4433QFSPosixRetry:
4434 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4435 (void **) &pSMBr);
4436 if (rc)
4437 return rc;
4438
4439 params = 2; /* level */
4440 pSMB->TotalDataCount = 0;
4441 pSMB->DataCount = 0;
4442 pSMB->DataOffset = 0;
4443 pSMB->MaxParameterCount = cpu_to_le16(2);
4444 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4445 pSMB->MaxSetupCount = 0;
4446 pSMB->Reserved = 0;
4447 pSMB->Flags = 0;
4448 pSMB->Timeout = 0;
4449 pSMB->Reserved2 = 0;
4450 byte_count = params + 1 /* pad */ ;
4451 pSMB->ParameterCount = cpu_to_le16(params);
4452 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004453 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4454 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 pSMB->SetupCount = 1;
4456 pSMB->Reserved3 = 0;
4457 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4458 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4459 pSMB->hdr.smb_buf_length += byte_count;
4460 pSMB->ByteCount = cpu_to_le16(byte_count);
4461
4462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4464 if (rc) {
4465 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4466 } else { /* decode response */
4467 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4468
4469 if (rc || (pSMBr->ByteCount < 13)) {
4470 rc = -EIO; /* bad smb */
4471 } else {
4472 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4473 response_data =
4474 (FILE_SYSTEM_POSIX_INFO
4475 *) (((char *) &pSMBr->hdr.Protocol) +
4476 data_offset);
4477 FSData->f_bsize =
4478 le32_to_cpu(response_data->BlockSize);
4479 FSData->f_blocks =
4480 le64_to_cpu(response_data->TotalBlocks);
4481 FSData->f_bfree =
4482 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004483 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 FSData->f_bavail = FSData->f_bfree;
4485 } else {
4486 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004487 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 }
Steve French790fe572007-07-07 19:25:05 +00004489 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004491 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004492 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004494 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 }
4496 }
4497 cifs_buf_release(pSMB);
4498
4499 if (rc == -EAGAIN)
4500 goto QFSPosixRetry;
4501
4502 return rc;
4503}
4504
4505
Steve French50c2f752007-07-13 00:33:32 +00004506/* We can not use write of zero bytes trick to
4507 set file size due to need for large file support. Also note that
4508 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 routine which is only needed to work around a sharing violation bug
4510 in Samba which this routine can run into */
4511
4512int
4513CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004514 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004515 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516{
4517 struct smb_com_transaction2_spi_req *pSMB = NULL;
4518 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4519 struct file_end_of_file_info *parm_data;
4520 int name_len;
4521 int rc = 0;
4522 int bytes_returned = 0;
4523 __u16 params, byte_count, data_count, param_offset, offset;
4524
4525 cFYI(1, ("In SetEOF"));
4526SetEOFRetry:
4527 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4528 (void **) &pSMBr);
4529 if (rc)
4530 return rc;
4531
4532 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4533 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004534 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004535 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 name_len++; /* trailing null */
4537 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004538 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 name_len = strnlen(fileName, PATH_MAX);
4540 name_len++; /* trailing null */
4541 strncpy(pSMB->FileName, fileName, name_len);
4542 }
4543 params = 6 + name_len;
4544 data_count = sizeof (struct file_end_of_file_info);
4545 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004546 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 pSMB->MaxSetupCount = 0;
4548 pSMB->Reserved = 0;
4549 pSMB->Flags = 0;
4550 pSMB->Timeout = 0;
4551 pSMB->Reserved2 = 0;
4552 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004553 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004555 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004556 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4557 pSMB->InformationLevel =
4558 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4559 else
4560 pSMB->InformationLevel =
4561 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4562 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4564 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004565 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 else
4567 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004568 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 }
4570
4571 parm_data =
4572 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4573 offset);
4574 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4575 pSMB->DataOffset = cpu_to_le16(offset);
4576 pSMB->SetupCount = 1;
4577 pSMB->Reserved3 = 0;
4578 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4579 byte_count = 3 /* pad */ + params + data_count;
4580 pSMB->DataCount = cpu_to_le16(data_count);
4581 pSMB->TotalDataCount = pSMB->DataCount;
4582 pSMB->ParameterCount = cpu_to_le16(params);
4583 pSMB->TotalParameterCount = pSMB->ParameterCount;
4584 pSMB->Reserved4 = 0;
4585 pSMB->hdr.smb_buf_length += byte_count;
4586 parm_data->FileSize = cpu_to_le64(size);
4587 pSMB->ByteCount = cpu_to_le16(byte_count);
4588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4590 if (rc) {
4591 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4592 }
4593
4594 cifs_buf_release(pSMB);
4595
4596 if (rc == -EAGAIN)
4597 goto SetEOFRetry;
4598
4599 return rc;
4600}
4601
4602int
Steve French50c2f752007-07-13 00:33:32 +00004603CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4604 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605{
4606 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4607 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4608 char *data_offset;
4609 struct file_end_of_file_info *parm_data;
4610 int rc = 0;
4611 int bytes_returned = 0;
4612 __u16 params, param_offset, offset, byte_count, count;
4613
4614 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4615 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004616 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4617
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 if (rc)
4619 return rc;
4620
Steve Frenchcd634992005-04-28 22:41:10 -07004621 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4622
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4624 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004625
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 params = 6;
4627 pSMB->MaxSetupCount = 0;
4628 pSMB->Reserved = 0;
4629 pSMB->Flags = 0;
4630 pSMB->Timeout = 0;
4631 pSMB->Reserved2 = 0;
4632 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4633 offset = param_offset + params;
4634
Steve French50c2f752007-07-13 00:33:32 +00004635 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
4637 count = sizeof(struct file_end_of_file_info);
4638 pSMB->MaxParameterCount = cpu_to_le16(2);
4639 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4640 pSMB->SetupCount = 1;
4641 pSMB->Reserved3 = 0;
4642 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4643 byte_count = 3 /* pad */ + params + count;
4644 pSMB->DataCount = cpu_to_le16(count);
4645 pSMB->ParameterCount = cpu_to_le16(params);
4646 pSMB->TotalDataCount = pSMB->DataCount;
4647 pSMB->TotalParameterCount = pSMB->ParameterCount;
4648 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4649 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004650 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4651 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 pSMB->DataOffset = cpu_to_le16(offset);
4653 parm_data->FileSize = cpu_to_le64(size);
4654 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004655 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4657 pSMB->InformationLevel =
4658 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4659 else
4660 pSMB->InformationLevel =
4661 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004662 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4664 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004665 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 else
4667 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004668 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 }
4670 pSMB->Reserved4 = 0;
4671 pSMB->hdr.smb_buf_length += byte_count;
4672 pSMB->ByteCount = cpu_to_le16(byte_count);
4673 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4674 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4675 if (rc) {
4676 cFYI(1,
4677 ("Send error in SetFileInfo (SetFileSize) = %d",
4678 rc));
4679 }
4680
4681 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004682 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683
Steve French50c2f752007-07-13 00:33:32 +00004684 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 since file handle passed in no longer valid */
4686
4687 return rc;
4688}
4689
Steve French50c2f752007-07-13 00:33:32 +00004690/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 an open handle, rather than by pathname - this is awkward due to
4692 potential access conflicts on the open, but it is unavoidable for these
4693 old servers since the only other choice is to go from 100 nanosecond DCE
4694 time and resort to the original setpathinfo level which takes the ancient
4695 DOS time format with 2 second granularity */
4696int
Steve French50c2f752007-07-13 00:33:32 +00004697CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4698 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699{
4700 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4701 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4702 char *data_offset;
4703 int rc = 0;
4704 int bytes_returned = 0;
4705 __u16 params, param_offset, offset, byte_count, count;
4706
4707 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004708 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4709
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 if (rc)
4711 return rc;
4712
Steve Frenchcd634992005-04-28 22:41:10 -07004713 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4714
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 /* At this point there is no need to override the current pid
4716 with the pid of the opener, but that could change if we someday
4717 use an existing handle (rather than opening one on the fly) */
4718 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4719 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004720
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 params = 6;
4722 pSMB->MaxSetupCount = 0;
4723 pSMB->Reserved = 0;
4724 pSMB->Flags = 0;
4725 pSMB->Timeout = 0;
4726 pSMB->Reserved2 = 0;
4727 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4728 offset = param_offset + params;
4729
Steve French50c2f752007-07-13 00:33:32 +00004730 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731
4732 count = sizeof (FILE_BASIC_INFO);
4733 pSMB->MaxParameterCount = cpu_to_le16(2);
4734 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4735 pSMB->SetupCount = 1;
4736 pSMB->Reserved3 = 0;
4737 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4738 byte_count = 3 /* pad */ + params + count;
4739 pSMB->DataCount = cpu_to_le16(count);
4740 pSMB->ParameterCount = cpu_to_le16(params);
4741 pSMB->TotalDataCount = pSMB->DataCount;
4742 pSMB->TotalParameterCount = pSMB->ParameterCount;
4743 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4744 pSMB->DataOffset = cpu_to_le16(offset);
4745 pSMB->Fid = fid;
4746 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4747 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4748 else
4749 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4750 pSMB->Reserved4 = 0;
4751 pSMB->hdr.smb_buf_length += byte_count;
4752 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004753 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4756 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004757 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 }
4759
Steve Frenchcd634992005-04-28 22:41:10 -07004760 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Steve French50c2f752007-07-13 00:33:32 +00004762 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 since file handle passed in no longer valid */
4764
4765 return rc;
4766}
4767
4768
4769int
4770CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004771 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004772 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773{
4774 TRANSACTION2_SPI_REQ *pSMB = NULL;
4775 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4776 int name_len;
4777 int rc = 0;
4778 int bytes_returned = 0;
4779 char *data_offset;
4780 __u16 params, param_offset, offset, byte_count, count;
4781
4782 cFYI(1, ("In SetTimes"));
4783
4784SetTimesRetry:
4785 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4786 (void **) &pSMBr);
4787 if (rc)
4788 return rc;
4789
4790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4791 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004792 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004793 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 name_len++; /* trailing null */
4795 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004796 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 name_len = strnlen(fileName, PATH_MAX);
4798 name_len++; /* trailing null */
4799 strncpy(pSMB->FileName, fileName, name_len);
4800 }
4801
4802 params = 6 + name_len;
4803 count = sizeof (FILE_BASIC_INFO);
4804 pSMB->MaxParameterCount = cpu_to_le16(2);
4805 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4806 pSMB->MaxSetupCount = 0;
4807 pSMB->Reserved = 0;
4808 pSMB->Flags = 0;
4809 pSMB->Timeout = 0;
4810 pSMB->Reserved2 = 0;
4811 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004812 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 offset = param_offset + params;
4814 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4815 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4816 pSMB->DataOffset = cpu_to_le16(offset);
4817 pSMB->SetupCount = 1;
4818 pSMB->Reserved3 = 0;
4819 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4820 byte_count = 3 /* pad */ + params + count;
4821
4822 pSMB->DataCount = cpu_to_le16(count);
4823 pSMB->ParameterCount = cpu_to_le16(params);
4824 pSMB->TotalDataCount = pSMB->DataCount;
4825 pSMB->TotalParameterCount = pSMB->ParameterCount;
4826 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4827 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4828 else
4829 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4830 pSMB->Reserved4 = 0;
4831 pSMB->hdr.smb_buf_length += byte_count;
4832 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4833 pSMB->ByteCount = cpu_to_le16(byte_count);
4834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4836 if (rc) {
4837 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4838 }
4839
4840 cifs_buf_release(pSMB);
4841
4842 if (rc == -EAGAIN)
4843 goto SetTimesRetry;
4844
4845 return rc;
4846}
4847
4848/* Can not be used to set time stamps yet (due to old DOS time format) */
4849/* Can be used to set attributes */
4850#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4851 handling it anyway and NT4 was what we thought it would be needed for
4852 Do not delete it until we prove whether needed for Win9x though */
4853int
4854CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4855 __u16 dos_attrs, const struct nls_table *nls_codepage)
4856{
4857 SETATTR_REQ *pSMB = NULL;
4858 SETATTR_RSP *pSMBr = NULL;
4859 int rc = 0;
4860 int bytes_returned;
4861 int name_len;
4862
4863 cFYI(1, ("In SetAttrLegacy"));
4864
4865SetAttrLgcyRetry:
4866 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4867 (void **) &pSMBr);
4868 if (rc)
4869 return rc;
4870
4871 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4872 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004873 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 PATH_MAX, nls_codepage);
4875 name_len++; /* trailing null */
4876 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004877 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 name_len = strnlen(fileName, PATH_MAX);
4879 name_len++; /* trailing null */
4880 strncpy(pSMB->fileName, fileName, name_len);
4881 }
4882 pSMB->attr = cpu_to_le16(dos_attrs);
4883 pSMB->BufferFormat = 0x04;
4884 pSMB->hdr.smb_buf_length += name_len + 1;
4885 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4886 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4887 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4888 if (rc) {
4889 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4890 }
4891
4892 cifs_buf_release(pSMB);
4893
4894 if (rc == -EAGAIN)
4895 goto SetAttrLgcyRetry;
4896
4897 return rc;
4898}
4899#endif /* temporarily unneeded SetAttr legacy function */
4900
4901int
4902CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004903 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4904 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004905 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906{
4907 TRANSACTION2_SPI_REQ *pSMB = NULL;
4908 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4909 int name_len;
4910 int rc = 0;
4911 int bytes_returned = 0;
4912 FILE_UNIX_BASIC_INFO *data_offset;
4913 __u16 params, param_offset, offset, count, byte_count;
4914
4915 cFYI(1, ("In SetUID/GID/Mode"));
4916setPermsRetry:
4917 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4918 (void **) &pSMBr);
4919 if (rc)
4920 return rc;
4921
4922 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4923 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004924 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004925 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 name_len++; /* trailing null */
4927 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004928 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 name_len = strnlen(fileName, PATH_MAX);
4930 name_len++; /* trailing null */
4931 strncpy(pSMB->FileName, fileName, name_len);
4932 }
4933
4934 params = 6 + name_len;
4935 count = sizeof (FILE_UNIX_BASIC_INFO);
4936 pSMB->MaxParameterCount = cpu_to_le16(2);
4937 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4938 pSMB->MaxSetupCount = 0;
4939 pSMB->Reserved = 0;
4940 pSMB->Flags = 0;
4941 pSMB->Timeout = 0;
4942 pSMB->Reserved2 = 0;
4943 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004944 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 offset = param_offset + params;
4946 data_offset =
4947 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4948 offset);
4949 memset(data_offset, 0, count);
4950 pSMB->DataOffset = cpu_to_le16(offset);
4951 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4952 pSMB->SetupCount = 1;
4953 pSMB->Reserved3 = 0;
4954 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4955 byte_count = 3 /* pad */ + params + count;
4956 pSMB->ParameterCount = cpu_to_le16(params);
4957 pSMB->DataCount = cpu_to_le16(count);
4958 pSMB->TotalParameterCount = pSMB->ParameterCount;
4959 pSMB->TotalDataCount = pSMB->DataCount;
4960 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4961 pSMB->Reserved4 = 0;
4962 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00004963 /* Samba server ignores set of file size to zero due to bugs in some
4964 older clients, but we should be precise - we use SetFileSize to
4965 set file size and do not want to truncate file size to zero
4966 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00004967 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00004968 data_offset->EndOfFile = NO_CHANGE_64;
4969 data_offset->NumOfBytes = NO_CHANGE_64;
4970 data_offset->LastStatusChange = NO_CHANGE_64;
4971 data_offset->LastAccessTime = NO_CHANGE_64;
4972 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 data_offset->Uid = cpu_to_le64(uid);
4974 data_offset->Gid = cpu_to_le64(gid);
4975 /* better to leave device as zero when it is */
4976 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4977 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4978 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00004979
Steve French790fe572007-07-07 19:25:05 +00004980 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00004982 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00004984 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00004986 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00004988 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00004990 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00004992 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4994
4995
4996 pSMB->ByteCount = cpu_to_le16(byte_count);
4997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4999 if (rc) {
5000 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5001 }
5002
5003 if (pSMB)
5004 cifs_buf_release(pSMB);
5005 if (rc == -EAGAIN)
5006 goto setPermsRetry;
5007 return rc;
5008}
5009
Steve French50c2f752007-07-13 00:33:32 +00005010int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005011 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005012 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005013 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014{
5015 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005016 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5017 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005018 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 int bytes_returned;
5020
Steve French50c2f752007-07-13 00:33:32 +00005021 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005023 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 if (rc)
5025 return rc;
5026
5027 pSMB->TotalParameterCount = 0 ;
5028 pSMB->TotalDataCount = 0;
5029 pSMB->MaxParameterCount = cpu_to_le32(2);
5030 /* BB find exact data count max from sess structure BB */
5031 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005032/* BB VERIFY verify which is correct for above BB */
5033 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5034 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5035
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 pSMB->MaxSetupCount = 4;
5037 pSMB->Reserved = 0;
5038 pSMB->ParameterOffset = 0;
5039 pSMB->DataCount = 0;
5040 pSMB->DataOffset = 0;
5041 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5042 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5043 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005044 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5046 pSMB->Reserved2 = 0;
5047 pSMB->CompletionFilter = cpu_to_le32(filter);
5048 pSMB->Fid = netfid; /* file handle always le */
5049 pSMB->ByteCount = 0;
5050
5051 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5052 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5053 if (rc) {
5054 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005055 } else {
5056 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005057 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005058 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005059 sizeof(struct dir_notify_req),
5060 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005061 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005062 dnotify_req->Pid = pSMB->hdr.Pid;
5063 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5064 dnotify_req->Mid = pSMB->hdr.Mid;
5065 dnotify_req->Tid = pSMB->hdr.Tid;
5066 dnotify_req->Uid = pSMB->hdr.Uid;
5067 dnotify_req->netfid = netfid;
5068 dnotify_req->pfile = pfile;
5069 dnotify_req->filter = filter;
5070 dnotify_req->multishot = multishot;
5071 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005072 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005073 &GlobalDnotifyReqList);
5074 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005075 } else
Steve French47c786e2005-10-11 20:03:18 -07005076 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 }
5078 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005079 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080}
5081#ifdef CONFIG_CIFS_XATTR
5082ssize_t
5083CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5084 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005085 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005086 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087{
5088 /* BB assumes one setup word */
5089 TRANSACTION2_QPI_REQ *pSMB = NULL;
5090 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5091 int rc = 0;
5092 int bytes_returned;
5093 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005094 struct fea *temp_fea;
5095 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 __u16 params, byte_count;
5097
5098 cFYI(1, ("In Query All EAs path %s", searchName));
5099QAllEAsRetry:
5100 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5101 (void **) &pSMBr);
5102 if (rc)
5103 return rc;
5104
5105 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5106 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005107 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005108 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 name_len++; /* trailing null */
5110 name_len *= 2;
5111 } else { /* BB improve the check for buffer overruns BB */
5112 name_len = strnlen(searchName, PATH_MAX);
5113 name_len++; /* trailing null */
5114 strncpy(pSMB->FileName, searchName, name_len);
5115 }
5116
Steve French50c2f752007-07-13 00:33:32 +00005117 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 pSMB->TotalDataCount = 0;
5119 pSMB->MaxParameterCount = cpu_to_le16(2);
5120 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5121 pSMB->MaxSetupCount = 0;
5122 pSMB->Reserved = 0;
5123 pSMB->Flags = 0;
5124 pSMB->Timeout = 0;
5125 pSMB->Reserved2 = 0;
5126 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005127 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 pSMB->DataCount = 0;
5129 pSMB->DataOffset = 0;
5130 pSMB->SetupCount = 1;
5131 pSMB->Reserved3 = 0;
5132 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5133 byte_count = params + 1 /* pad */ ;
5134 pSMB->TotalParameterCount = cpu_to_le16(params);
5135 pSMB->ParameterCount = pSMB->TotalParameterCount;
5136 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5137 pSMB->Reserved4 = 0;
5138 pSMB->hdr.smb_buf_length += byte_count;
5139 pSMB->ByteCount = cpu_to_le16(byte_count);
5140
5141 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5142 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5143 if (rc) {
5144 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5145 } else { /* decode response */
5146 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5147
5148 /* BB also check enough total bytes returned */
5149 /* BB we need to improve the validity checking
5150 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005151 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 rc = -EIO; /* bad smb */
5153 /* else if (pFindData){
5154 memcpy((char *) pFindData,
5155 (char *) &pSMBr->hdr.Protocol +
5156 data_offset, kl);
5157 }*/ else {
5158 /* check that length of list is not more than bcc */
5159 /* check that each entry does not go beyond length
5160 of list */
5161 /* check that each element of each entry does not
5162 go beyond end of list */
5163 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005164 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 rc = 0;
5166 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005167 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 ea_response_data = (struct fealist *)
5169 (((char *) &pSMBr->hdr.Protocol) +
5170 data_offset);
5171 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005172 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005173 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005175 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 } else {
5177 /* account for ea list len */
5178 name_len -= 4;
5179 temp_fea = ea_response_data->list;
5180 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005181 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 __u16 value_len;
5183 name_len -= 4;
5184 temp_ptr += 4;
5185 rc += temp_fea->name_len;
5186 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005187 rc = rc + 5 + 1;
5188 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005189 memcpy(EAData, "user.", 5);
5190 EAData += 5;
5191 memcpy(EAData, temp_ptr,
5192 temp_fea->name_len);
5193 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 /* null terminate name */
5195 *EAData = 0;
5196 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005197 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 /* skip copy - calc size only */
5199 } else {
5200 /* stop before overrun buffer */
5201 rc = -ERANGE;
5202 break;
5203 }
5204 name_len -= temp_fea->name_len;
5205 temp_ptr += temp_fea->name_len;
5206 /* account for trailing null */
5207 name_len--;
5208 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005209 value_len =
5210 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 name_len -= value_len;
5212 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005213 /* BB check that temp_ptr is still
5214 within the SMB BB*/
5215
5216 /* no trailing null to account for
5217 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 /* go on to next EA */
5219 temp_fea = (struct fea *)temp_ptr;
5220 }
5221 }
5222 }
5223 }
5224 if (pSMB)
5225 cifs_buf_release(pSMB);
5226 if (rc == -EAGAIN)
5227 goto QAllEAsRetry;
5228
5229 return (ssize_t)rc;
5230}
5231
Steve French50c2f752007-07-13 00:33:32 +00005232ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5233 const unsigned char *searchName, const unsigned char *ea_name,
5234 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005235 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236{
5237 TRANSACTION2_QPI_REQ *pSMB = NULL;
5238 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5239 int rc = 0;
5240 int bytes_returned;
5241 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005242 struct fea *temp_fea;
5243 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 __u16 params, byte_count;
5245
5246 cFYI(1, ("In Query EA path %s", searchName));
5247QEARetry:
5248 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5249 (void **) &pSMBr);
5250 if (rc)
5251 return rc;
5252
5253 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5254 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005255 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005256 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 name_len++; /* trailing null */
5258 name_len *= 2;
5259 } else { /* BB improve the check for buffer overruns BB */
5260 name_len = strnlen(searchName, PATH_MAX);
5261 name_len++; /* trailing null */
5262 strncpy(pSMB->FileName, searchName, name_len);
5263 }
5264
Steve French50c2f752007-07-13 00:33:32 +00005265 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 pSMB->TotalDataCount = 0;
5267 pSMB->MaxParameterCount = cpu_to_le16(2);
5268 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5269 pSMB->MaxSetupCount = 0;
5270 pSMB->Reserved = 0;
5271 pSMB->Flags = 0;
5272 pSMB->Timeout = 0;
5273 pSMB->Reserved2 = 0;
5274 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005275 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 pSMB->DataCount = 0;
5277 pSMB->DataOffset = 0;
5278 pSMB->SetupCount = 1;
5279 pSMB->Reserved3 = 0;
5280 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5281 byte_count = params + 1 /* pad */ ;
5282 pSMB->TotalParameterCount = cpu_to_le16(params);
5283 pSMB->ParameterCount = pSMB->TotalParameterCount;
5284 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5285 pSMB->Reserved4 = 0;
5286 pSMB->hdr.smb_buf_length += byte_count;
5287 pSMB->ByteCount = cpu_to_le16(byte_count);
5288
5289 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5290 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5291 if (rc) {
5292 cFYI(1, ("Send error in Query EA = %d", rc));
5293 } else { /* decode response */
5294 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5295
5296 /* BB also check enough total bytes returned */
5297 /* BB we need to improve the validity checking
5298 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005299 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 rc = -EIO; /* bad smb */
5301 /* else if (pFindData){
5302 memcpy((char *) pFindData,
5303 (char *) &pSMBr->hdr.Protocol +
5304 data_offset, kl);
5305 }*/ else {
5306 /* check that length of list is not more than bcc */
5307 /* check that each entry does not go beyond length
5308 of list */
5309 /* check that each element of each entry does not
5310 go beyond end of list */
5311 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005312 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 rc = -ENODATA;
5314 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005315 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 ea_response_data = (struct fealist *)
5317 (((char *) &pSMBr->hdr.Protocol) +
5318 data_offset);
5319 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005320 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005321 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005323 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 } else {
5325 /* account for ea list len */
5326 name_len -= 4;
5327 temp_fea = ea_response_data->list;
5328 temp_ptr = (char *)temp_fea;
5329 /* loop through checking if we have a matching
5330 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005331 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 __u16 value_len;
5333 name_len -= 4;
5334 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005335 value_len =
5336 le16_to_cpu(temp_fea->value_len);
5337 /* BB validate that value_len falls within SMB,
5338 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005339 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 temp_fea->name_len) == 0) {
5341 /* found a match */
5342 rc = value_len;
5343 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005344 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 memcpy(ea_value,
5346 temp_fea->name+temp_fea->name_len+1,
5347 rc);
Steve French50c2f752007-07-13 00:33:32 +00005348 /* ea values, unlike ea
5349 names, are not null
5350 terminated */
Steve French790fe572007-07-07 19:25:05 +00005351 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 /* skip copy - calc size only */
5353 } else {
Steve French50c2f752007-07-13 00:33:32 +00005354 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 rc = -ERANGE;
5356 }
5357 break;
5358 }
5359 name_len -= temp_fea->name_len;
5360 temp_ptr += temp_fea->name_len;
5361 /* account for trailing null */
5362 name_len--;
5363 temp_ptr++;
5364 name_len -= value_len;
5365 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005366 /* No trailing null to account for in
5367 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 temp_fea = (struct fea *)temp_ptr;
5369 }
Steve French50c2f752007-07-13 00:33:32 +00005370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 }
5372 }
5373 if (pSMB)
5374 cifs_buf_release(pSMB);
5375 if (rc == -EAGAIN)
5376 goto QEARetry;
5377
5378 return (ssize_t)rc;
5379}
5380
5381int
5382CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005383 const char *ea_name, const void *ea_value,
5384 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5385 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386{
5387 struct smb_com_transaction2_spi_req *pSMB = NULL;
5388 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5389 struct fealist *parm_data;
5390 int name_len;
5391 int rc = 0;
5392 int bytes_returned = 0;
5393 __u16 params, param_offset, byte_count, offset, count;
5394
5395 cFYI(1, ("In SetEA"));
5396SetEARetry:
5397 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5398 (void **) &pSMBr);
5399 if (rc)
5400 return rc;
5401
5402 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5403 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005404 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005405 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 name_len++; /* trailing null */
5407 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005408 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 name_len = strnlen(fileName, PATH_MAX);
5410 name_len++; /* trailing null */
5411 strncpy(pSMB->FileName, fileName, name_len);
5412 }
5413
5414 params = 6 + name_len;
5415
5416 /* done calculating parms using name_len of file name,
5417 now use name_len to calculate length of ea name
5418 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005419 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 name_len = 0;
5421 else
Steve French50c2f752007-07-13 00:33:32 +00005422 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423
5424 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5425 pSMB->MaxParameterCount = cpu_to_le16(2);
5426 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5427 pSMB->MaxSetupCount = 0;
5428 pSMB->Reserved = 0;
5429 pSMB->Flags = 0;
5430 pSMB->Timeout = 0;
5431 pSMB->Reserved2 = 0;
5432 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005433 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 offset = param_offset + params;
5435 pSMB->InformationLevel =
5436 cpu_to_le16(SMB_SET_FILE_EA);
5437
5438 parm_data =
5439 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5440 offset);
5441 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5442 pSMB->DataOffset = cpu_to_le16(offset);
5443 pSMB->SetupCount = 1;
5444 pSMB->Reserved3 = 0;
5445 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5446 byte_count = 3 /* pad */ + params + count;
5447 pSMB->DataCount = cpu_to_le16(count);
5448 parm_data->list_len = cpu_to_le32(count);
5449 parm_data->list[0].EA_flags = 0;
5450 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005451 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005453 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005454 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 parm_data->list[0].name[name_len] = 0;
5456 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5457 /* caller ensures that ea_value_len is less than 64K but
5458 we need to ensure that it fits within the smb */
5459
Steve French50c2f752007-07-13 00:33:32 +00005460 /*BB add length check to see if it would fit in
5461 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005462 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5463 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005464 memcpy(parm_data->list[0].name+name_len+1,
5465 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466
5467 pSMB->TotalDataCount = pSMB->DataCount;
5468 pSMB->ParameterCount = cpu_to_le16(params);
5469 pSMB->TotalParameterCount = pSMB->ParameterCount;
5470 pSMB->Reserved4 = 0;
5471 pSMB->hdr.smb_buf_length += byte_count;
5472 pSMB->ByteCount = cpu_to_le16(byte_count);
5473 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5474 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5475 if (rc) {
5476 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5477 }
5478
5479 cifs_buf_release(pSMB);
5480
5481 if (rc == -EAGAIN)
5482 goto SetEARetry;
5483
5484 return rc;
5485}
5486
5487#endif