blob: a6ff406ac6b488cd62751db72b29ab58fde06416 [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 */
Steve French63135e02007-07-17 17:34:02 +0000135 while(tcon->ses->server->tcpStatus ==
136 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000138 (tcon->ses->server->tcpStatus ==
139 CifsGood), 10 * HZ);
140 if (tcon->ses->server->tcpStatus ==
141 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000143 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000145 cFYI(1, ("gave up waiting on "
146 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700148 } /* else "hard" mount - keep retrying
149 until process is killed or server
150 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 } else /* TCP session is reestablished now */
152 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 }
Steve French50c2f752007-07-13 00:33:32 +0000154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 nls_codepage = load_nls_default();
156 /* need to prevent multiple threads trying to
157 simultaneously reconnect the same SMB session */
158 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000159 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000160 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700161 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000162 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000164 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000165 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000167 /* tell server which Unix caps we support */
168 if (tcon->ses->capabilities & CAP_UNIX)
169 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000170 tcon,
Steve French8af18972007-02-14 04:42:51 +0000171 NULL /* we do not know sb */,
Steve French50c2f752007-07-13 00:33:32 +0000172 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700173 /* BB FIXME add code to check if wsize needs
174 update due to negotiated smb buffer size
175 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000176 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 atomic_inc(&tconInfoReconnectCount);
178
179 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000180 /* Removed call to reopen open files here.
181 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700182 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Steve French50c2f752007-07-13 00:33:32 +0000184 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700185 know whether we can continue or not without
186 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000187 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 case SMB_COM_READ_ANDX:
189 case SMB_COM_WRITE_ANDX:
190 case SMB_COM_CLOSE:
191 case SMB_COM_FIND_CLOSE2:
192 case SMB_COM_LOCKING_ANDX: {
193 unload_nls(nls_codepage);
194 return -EAGAIN;
195 }
196 }
197 } else {
198 up(&tcon->ses->sesSem);
199 }
200 unload_nls(nls_codepage);
201
202 } else {
203 return -EIO;
204 }
205 }
Steve French790fe572007-07-07 19:25:05 +0000206 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 return rc;
208
209 *request_buf = cifs_small_buf_get();
210 if (*request_buf == NULL) {
211 /* BB should we add a retry in here if not a writepage? */
212 return -ENOMEM;
213 }
214
Steve French63135e02007-07-17 17:34:02 +0000215 header_assemble((struct smb_hdr *) *request_buf, smb_command,
216 tcon,wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Steve French790fe572007-07-07 19:25:05 +0000218 if (tcon != NULL)
219 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000222}
223
Steve French12b3b8f2006-02-09 21:12:47 +0000224int
Steve French50c2f752007-07-13 00:33:32 +0000225small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000226 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000227{
228 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000229 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000230
Steve French5815449d2006-02-14 01:36:20 +0000231 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000232 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000233 return rc;
234
Steve French04fdabe2006-02-10 05:52:50 +0000235 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000236 buffer->Mid = GetNextMid(ses->server);
237 if (ses->capabilities & CAP_UNICODE)
238 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000239 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000240 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
241
242 /* uid, tid can stay at zero as set in header assemble */
243
Steve French50c2f752007-07-13 00:33:32 +0000244 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000245 this function is used after 1st of session setup requests */
246
247 return rc;
248}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250/* If the return code is zero, this function must fill in request_buf pointer */
251static int
252smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
253 void **request_buf /* returned */ ,
254 void **response_buf /* returned */ )
255{
256 int rc = 0;
257
258 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
259 check for tcp and smb session status done differently
260 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000261 if (tcon) {
262 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800263 /* only tree disconnect, open, and write,
264 (and ulogoff which does not have tcon)
265 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000266 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800267 (smb_command != SMB_COM_OPEN_ANDX) &&
268 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000269 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800270 smb_command));
271 return -ENODEV;
272 }
273 }
274
Steve French790fe572007-07-07 19:25:05 +0000275 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000276 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700278 /* Give Demultiplex thread up to 10 seconds to
279 reconnect, should be greater than cifs socket
280 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000281 while (tcon->ses->server->tcpStatus ==
282 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000284 (tcon->ses->server->tcpStatus ==
285 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000286 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700287 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000289 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000291 cFYI(1, ("gave up waiting on "
292 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700294 } /* else "hard" mount - keep retrying
295 until process is killed or server
296 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 } else /* TCP session is reestablished now */
298 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 nls_codepage = load_nls_default();
301 /* need to prevent multiple threads trying to
302 simultaneously reconnect the same SMB session */
303 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000304 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000305 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700306 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000307 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700309 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
310 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000312 /* tell server which Unix caps we support */
313 if (tcon->ses->capabilities & CAP_UNIX)
314 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000315 tcon,
Steve French8af18972007-02-14 04:42:51 +0000316 NULL /* do not know sb */,
317 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700318 /* BB FIXME add code to check if wsize needs
319 update due to negotiated smb buffer size
320 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000321 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 atomic_inc(&tconInfoReconnectCount);
323
324 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000325 /* Removed call to reopen open files here.
326 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700327 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
Steve French50c2f752007-07-13 00:33:32 +0000329 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700330 know whether we can continue or not without
331 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000332 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 case SMB_COM_READ_ANDX:
334 case SMB_COM_WRITE_ANDX:
335 case SMB_COM_CLOSE:
336 case SMB_COM_FIND_CLOSE2:
337 case SMB_COM_LOCKING_ANDX: {
338 unload_nls(nls_codepage);
339 return -EAGAIN;
340 }
341 }
342 } else {
343 up(&tcon->ses->sesSem);
344 }
345 unload_nls(nls_codepage);
346
347 } else {
348 return -EIO;
349 }
350 }
Steve French790fe572007-07-07 19:25:05 +0000351 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 return rc;
353
354 *request_buf = cifs_buf_get();
355 if (*request_buf == NULL) {
356 /* BB should we add a retry in here if not a writepage? */
357 return -ENOMEM;
358 }
359 /* Although the original thought was we needed the response buf for */
360 /* potential retries of smb operations it turns out we can determine */
361 /* from the mid flags when the request buffer can be resent without */
362 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000363 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000364 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
367 wct /*wct */ );
368
Steve French790fe572007-07-07 19:25:05 +0000369 if (tcon != NULL)
370 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 return rc;
373}
374
Steve French50c2f752007-07-13 00:33:32 +0000375static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377 int rc = -EINVAL;
378 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000379 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 /* check for plausible wct, bcc and t2 data and parm sizes */
382 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000383 if (pSMB->hdr.WordCount >= 10) {
384 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
386 /* check that bcc is at least as big as parms + data */
387 /* check that bcc is less than negotiated smb buffer */
388 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000389 if (total_size < 512) {
Steve French63135e02007-07-17 17:34:02 +0000390 total_size +=
391 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000393 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700394 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000396 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000397 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
399 return 0;
400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 }
402 }
403 }
Steve French50c2f752007-07-13 00:33:32 +0000404 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 sizeof(struct smb_t2_rsp) + 16);
406 return rc;
407}
408int
409CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
410{
411 NEGOTIATE_REQ *pSMB;
412 NEGOTIATE_RSP *pSMBr;
413 int rc = 0;
414 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000415 int i;
Steve French50c2f752007-07-13 00:33:32 +0000416 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000418 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100419 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Steve French790fe572007-07-07 19:25:05 +0000421 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 server = ses->server;
423 else {
424 rc = -EIO;
425 return rc;
426 }
427 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
428 (void **) &pSMB, (void **) &pSMBr);
429 if (rc)
430 return rc;
Steve French750d1152006-06-27 06:28:30 +0000431
432 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000433 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000434 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000435 else /* if override flags set only sign/seal OR them with global auth */
436 secFlags = extended_security | ses->overrideSecFlg;
437
Steve French762e5ab2007-06-28 18:41:42 +0000438 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000439
Steve French1982c342005-08-17 12:38:22 -0700440 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000441 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
442 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000443 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French50c2f752007-07-13 00:33:32 +0000444
Steve French39798772006-05-31 22:40:51 +0000445 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000446 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000447 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
448 count += strlen(protocols[i].name) + 1;
449 /* null at end of source and target buffers anyway */
450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 pSMB->hdr.smb_buf_length += count;
452 pSMB->ByteCount = cpu_to_le16(count);
453
454 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
455 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000456 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000457 goto neg_err_exit;
458
Al Viro733f99a2006-10-14 16:48:26 +0100459 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000460 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000461 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000462 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000463 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000464 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000465 could not negotiate a common dialect */
466 rc = -EOPNOTSUPP;
467 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000468#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000469 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100470 && ((dialect == LANMAN_PROT)
471 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000472 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000473 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000474
Steve French790fe572007-07-07 19:25:05 +0000475 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000476 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000477 server->secType = LANMAN;
478 else {
479 cERROR(1, ("mount failed weak security disabled"
480 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000481 rc = -EOPNOTSUPP;
482 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000483 }
Steve French254e55e2006-06-04 05:53:15 +0000484 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
485 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
486 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000487 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000488 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
489 /* even though we do not use raw we might as well set this
490 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000491 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000492 server->maxRw = 0xFF00;
493 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
494 } else {
495 server->maxRw = 0;/* we do not need to use raw anyway */
496 server->capabilities = CAP_MPX_MODE;
497 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000498 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000499 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000500 /* OS/2 often does not set timezone therefore
501 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000502 * Could deviate slightly from the right zone.
503 * Smallest defined timezone difference is 15 minutes
504 * (i.e. Nepal). Rounding up/down is done to match
505 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000506 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000507 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000508 struct timespec ts, utc;
509 utc = CURRENT_TIME;
510 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
511 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000512 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
513 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000514 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000515 val = (int)(utc.tv_sec - ts.tv_sec);
516 seconds = val < 0 ? -val : val;
Steve French947a5062006-10-02 05:55:25 +0000517 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000518 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000519 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000520 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000521 if (val < 0)
Steve Frenchb815f1e2006-10-02 05:53:29 +0000522 result = - result;
523 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000524 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000525 server->timeAdj = (int)tmp;
526 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000527 }
Steve French790fe572007-07-07 19:25:05 +0000528 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000529
Steve French39798772006-05-31 22:40:51 +0000530
Steve French254e55e2006-06-04 05:53:15 +0000531 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000532 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000533
Steve French50c2f752007-07-13 00:33:32 +0000534 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000535 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000536 memcpy(server->cryptKey, rsp->EncryptionKey,
537 CIFS_CRYPTO_KEY_SIZE);
538 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
539 rc = -EIO; /* need cryptkey unless plain text */
540 goto neg_err_exit;
541 }
Steve French39798772006-05-31 22:40:51 +0000542
Steve French790fe572007-07-07 19:25:05 +0000543 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000544 /* we will not end up setting signing flags - as no signing
545 was in LANMAN and server did not return the flags on */
546 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000547#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000548 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000549 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000550 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000551 rc = -EOPNOTSUPP;
552#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000553 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000554 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000555 /* unknown wct */
556 rc = -EOPNOTSUPP;
557 goto neg_err_exit;
558 }
559 /* else wct == 17 NTLM */
560 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000561 if ((server->secMode & SECMODE_USER) == 0)
562 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000563
Steve French790fe572007-07-07 19:25:05 +0000564 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000565#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000566 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000567#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000568 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000569 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000570
Steve French790fe572007-07-07 19:25:05 +0000571 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000572 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000573 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000574 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000575 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000576 server->secType = NTLMv2;
577 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000578
Steve French254e55e2006-06-04 05:53:15 +0000579 /* one byte, so no need to convert this or EncryptionKeyLen from
580 little endian */
581 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
582 /* probably no need to store and check maxvcs */
583 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000585 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
586 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
587 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
588 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000589 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
590 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000591 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
592 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
593 CIFS_CRYPTO_KEY_SIZE);
594 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
595 && (pSMBr->EncryptionKeyLength == 0)) {
596 /* decode security blob */
597 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
598 rc = -EIO; /* no crypt key only if plain text pwd */
599 goto neg_err_exit;
600 }
601
602 /* BB might be helpful to save off the domain of server here */
603
Steve French50c2f752007-07-13 00:33:32 +0000604 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000605 (server->capabilities & CAP_EXTENDED_SECURITY)) {
606 count = pSMBr->ByteCount;
607 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000609 else if (count == 16) {
610 server->secType = RawNTLMSSP;
611 if (server->socketUseCount.counter > 1) {
612 if (memcmp(server->server_GUID,
613 pSMBr->u.extended_response.
614 GUID, 16) != 0) {
615 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000617 pSMBr->u.extended_response.GUID,
618 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 }
Steve French254e55e2006-06-04 05:53:15 +0000620 } else
621 memcpy(server->server_GUID,
622 pSMBr->u.extended_response.GUID, 16);
623 } else {
624 rc = decode_negTokenInit(pSMBr->u.extended_response.
625 SecurityBlob,
626 count - 16,
627 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000628 if (rc == 1) {
Steve French254e55e2006-06-04 05:53:15 +0000629 /* BB Need to fill struct for sessetup here */
630 rc = -EOPNOTSUPP;
631 } else {
632 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
Steve French254e55e2006-06-04 05:53:15 +0000635 } else
636 server->capabilities &= ~CAP_EXTENDED_SECURITY;
637
Steve French6344a422006-06-12 04:18:35 +0000638#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000639signing_check:
Steve French6344a422006-06-12 04:18:35 +0000640#endif
Steve French762e5ab2007-06-28 18:41:42 +0000641 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
642 /* MUST_SIGN already includes the MAY_SIGN FLAG
643 so if this is zero it means that signing is disabled */
644 cFYI(1, ("Signing disabled"));
Steve French790fe572007-07-07 19:25:05 +0000645 if (server->secMode & SECMODE_SIGN_REQUIRED)
Steve French762e5ab2007-06-28 18:41:42 +0000646 cERROR(1, ("Server requires "
647 "/proc/fs/cifs/PacketSigningEnabled "
648 "to be on"));
Steve French50c2f752007-07-13 00:33:32 +0000649 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000650 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000651 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
652 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000653 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000654 if ((server->secMode &
655 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
656 cERROR(1,
657 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000658 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000659 } else
660 server->secMode |= SECMODE_SIGN_REQUIRED;
661 } else {
662 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000663 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000664 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000665 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 }
Steve French50c2f752007-07-13 00:33:32 +0000667
668neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700669 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000670
Steve French790fe572007-07-07 19:25:05 +0000671 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 return rc;
673}
674
675int
676CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
677{
678 struct smb_hdr *smb_buffer;
679 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
680 int rc = 0;
681 int length;
682
683 cFYI(1, ("In tree disconnect"));
684 /*
685 * If last user of the connection and
686 * connection alive - disconnect it
687 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000688 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 * to be freed and kernel thread woken up).
690 */
691 if (tcon)
692 down(&tcon->tconSem);
693 else
694 return -EIO;
695
696 atomic_dec(&tcon->useCount);
697 if (atomic_read(&tcon->useCount) > 0) {
698 up(&tcon->tconSem);
699 return -EBUSY;
700 }
701
Steve French50c2f752007-07-13 00:33:32 +0000702 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000704 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000706 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 }
708
Steve French790fe572007-07-07 19:25:05 +0000709 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 up(&tcon->tconSem);
711 return -EIO;
712 }
Steve French50c2f752007-07-13 00:33:32 +0000713 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700714 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 if (rc) {
716 up(&tcon->tconSem);
717 return rc;
718 } else {
719 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
722 &length, 0);
723 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700724 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 if (smb_buffer)
727 cifs_small_buf_release(smb_buffer);
728 up(&tcon->tconSem);
729
Steve French50c2f752007-07-13 00:33:32 +0000730 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 closed on server already e.g. due to tcp session crashing */
732 if (rc == -EAGAIN)
733 rc = 0;
734
735 return rc;
736}
737
738int
739CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
740{
741 struct smb_hdr *smb_buffer_response;
742 LOGOFF_ANDX_REQ *pSMB;
743 int rc = 0;
744 int length;
745
746 cFYI(1, ("In SMBLogoff for session disconnect"));
747 if (ses)
748 down(&ses->sesSem);
749 else
750 return -EIO;
751
752 atomic_dec(&ses->inUse);
753 if (atomic_read(&ses->inUse) > 0) {
754 up(&ses->sesSem);
755 return -EBUSY;
756 }
757 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
758 if (rc) {
759 up(&ses->sesSem);
760 return rc;
761 }
762
763 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000764
Steve French790fe572007-07-07 19:25:05 +0000765 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700766 pSMB->hdr.Mid = GetNextMid(ses->server);
767
Steve French790fe572007-07-07 19:25:05 +0000768 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
770 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
771 }
772
773 pSMB->hdr.Uid = ses->Suid;
774
775 pSMB->AndXCommand = 0xFF;
776 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
777 smb_buffer_response, &length, 0);
778 if (ses->server) {
779 atomic_dec(&ses->server->socketUseCount);
780 if (atomic_read(&ses->server->socketUseCount) == 0) {
781 spin_lock(&GlobalMid_Lock);
782 ses->server->tcpStatus = CifsExiting;
783 spin_unlock(&GlobalMid_Lock);
784 rc = -ESHUTDOWN;
785 }
786 }
Steve Frencha59c6582005-08-17 12:12:19 -0700787 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700788 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000791 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 error */
793 if (rc == -EAGAIN)
794 rc = 0;
795 return rc;
796}
797
798int
Steve French2d785a52007-07-15 01:48:57 +0000799CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
800 __u16 type, const struct nls_table *nls_codepage, int remap)
801{
802 TRANSACTION2_SPI_REQ *pSMB = NULL;
803 TRANSACTION2_SPI_RSP *pSMBr = NULL;
804 struct unlink_psx_rq *pRqD;
805 int name_len;
806 int rc = 0;
807 int bytes_returned = 0;
808 __u16 params, param_offset, offset, byte_count;
809
810 cFYI(1, ("In POSIX delete"));
811PsxDelete:
812 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
813 (void **) &pSMBr);
814 if (rc)
815 return rc;
816
817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
818 name_len =
819 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
820 PATH_MAX, nls_codepage, remap);
821 name_len++; /* trailing null */
822 name_len *= 2;
823 } else { /* BB add path length overrun check */
824 name_len = strnlen(fileName, PATH_MAX);
825 name_len++; /* trailing null */
826 strncpy(pSMB->FileName, fileName, name_len);
827 }
828
829 params = 6 + name_len;
830 pSMB->MaxParameterCount = cpu_to_le16(2);
831 pSMB->MaxDataCount = 0; /* BB double check this with jra */
832 pSMB->MaxSetupCount = 0;
833 pSMB->Reserved = 0;
834 pSMB->Flags = 0;
835 pSMB->Timeout = 0;
836 pSMB->Reserved2 = 0;
837 param_offset = offsetof(struct smb_com_transaction2_spi_req,
838 InformationLevel) - 4;
839 offset = param_offset + params;
840
841 /* Setup pointer to Request Data (inode type) */
842 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
843 pRqD->type = cpu_to_le16(type);
844 pSMB->ParameterOffset = cpu_to_le16(param_offset);
845 pSMB->DataOffset = cpu_to_le16(offset);
846 pSMB->SetupCount = 1;
847 pSMB->Reserved3 = 0;
848 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
849 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
850
851 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
852 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
853 pSMB->ParameterCount = cpu_to_le16(params);
854 pSMB->TotalParameterCount = pSMB->ParameterCount;
855 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
856 pSMB->Reserved4 = 0;
857 pSMB->hdr.smb_buf_length += byte_count;
858 pSMB->ByteCount = cpu_to_le16(byte_count);
859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
861 if (rc) {
862 cFYI(1, ("Posix delete returned %d", rc));
863 }
864 cifs_buf_release(pSMB);
865
866 cifs_stats_inc(&tcon->num_deletes);
867
868 if (rc == -EAGAIN)
869 goto PsxDelete;
870
871 return rc;
872}
873
874int
Steve French737b7582005-04-28 22:41:06 -0700875CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
876 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 DELETE_FILE_REQ *pSMB = NULL;
879 DELETE_FILE_RSP *pSMBr = NULL;
880 int rc = 0;
881 int bytes_returned;
882 int name_len;
883
884DelFileRetry:
885 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
886 (void **) &pSMBr);
887 if (rc)
888 return rc;
889
890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
891 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000892 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700893 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 name_len++; /* trailing null */
895 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700896 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 name_len = strnlen(fileName, PATH_MAX);
898 name_len++; /* trailing null */
899 strncpy(pSMB->fileName, fileName, name_len);
900 }
901 pSMB->SearchAttributes =
902 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
903 pSMB->BufferFormat = 0x04;
904 pSMB->hdr.smb_buf_length += name_len + 1;
905 pSMB->ByteCount = cpu_to_le16(name_len + 1);
906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700908 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (rc) {
910 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
913 cifs_buf_release(pSMB);
914 if (rc == -EAGAIN)
915 goto DelFileRetry;
916
917 return rc;
918}
919
920int
Steve French50c2f752007-07-13 00:33:32 +0000921CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700922 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
924 DELETE_DIRECTORY_REQ *pSMB = NULL;
925 DELETE_DIRECTORY_RSP *pSMBr = NULL;
926 int rc = 0;
927 int bytes_returned;
928 int name_len;
929
930 cFYI(1, ("In CIFSSMBRmDir"));
931RmDirRetry:
932 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
933 (void **) &pSMBr);
934 if (rc)
935 return rc;
936
937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700938 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
939 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 name_len++; /* trailing null */
941 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700942 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len = strnlen(dirName, PATH_MAX);
944 name_len++; /* trailing null */
945 strncpy(pSMB->DirName, dirName, name_len);
946 }
947
948 pSMB->BufferFormat = 0x04;
949 pSMB->hdr.smb_buf_length += name_len + 1;
950 pSMB->ByteCount = cpu_to_le16(name_len + 1);
951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700953 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 if (rc) {
955 cFYI(1, ("Error in RMDir = %d", rc));
956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 cifs_buf_release(pSMB);
959 if (rc == -EAGAIN)
960 goto RmDirRetry;
961 return rc;
962}
963
964int
965CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700966 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
968 int rc = 0;
969 CREATE_DIRECTORY_REQ *pSMB = NULL;
970 CREATE_DIRECTORY_RSP *pSMBr = NULL;
971 int bytes_returned;
972 int name_len;
973
974 cFYI(1, ("In CIFSSMBMkDir"));
975MkDirRetry:
976 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
977 (void **) &pSMBr);
978 if (rc)
979 return rc;
980
981 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000982 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700983 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 name_len++; /* trailing null */
985 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700986 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 name_len = strnlen(name, PATH_MAX);
988 name_len++; /* trailing null */
989 strncpy(pSMB->DirName, name, name_len);
990 }
991
992 pSMB->BufferFormat = 0x04;
993 pSMB->hdr.smb_buf_length += name_len + 1;
994 pSMB->ByteCount = cpu_to_le16(name_len + 1);
995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700997 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (rc) {
999 cFYI(1, ("Error in Mkdir = %d", rc));
1000 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001001
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 cifs_buf_release(pSMB);
1003 if (rc == -EAGAIN)
1004 goto MkDirRetry;
1005 return rc;
1006}
1007
Steve French2dd29d32007-04-23 22:07:35 +00001008int
1009CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1010 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001011 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001012 const struct nls_table *nls_codepage, int remap)
1013{
1014 TRANSACTION2_SPI_REQ *pSMB = NULL;
1015 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1016 int name_len;
1017 int rc = 0;
1018 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001019 __u16 params, param_offset, offset, byte_count, count;
1020 OPEN_PSX_REQ * pdata;
1021 OPEN_PSX_RSP * psx_rsp;
1022
1023 cFYI(1, ("In POSIX Create"));
1024PsxCreat:
1025 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1026 (void **) &pSMBr);
1027 if (rc)
1028 return rc;
1029
1030 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1031 name_len =
1032 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1033 PATH_MAX, nls_codepage, remap);
1034 name_len++; /* trailing null */
1035 name_len *= 2;
1036 } else { /* BB improve the check for buffer overruns BB */
1037 name_len = strnlen(name, PATH_MAX);
1038 name_len++; /* trailing null */
1039 strncpy(pSMB->FileName, name, name_len);
1040 }
1041
1042 params = 6 + name_len;
1043 count = sizeof(OPEN_PSX_REQ);
1044 pSMB->MaxParameterCount = cpu_to_le16(2);
1045 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1046 pSMB->MaxSetupCount = 0;
1047 pSMB->Reserved = 0;
1048 pSMB->Flags = 0;
1049 pSMB->Timeout = 0;
1050 pSMB->Reserved2 = 0;
1051 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001052 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001053 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001054 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1055 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
1056 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001057 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001058 pdata->OpenFlags = cpu_to_le32(*pOplock);
1059 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1060 pSMB->DataOffset = cpu_to_le16(offset);
1061 pSMB->SetupCount = 1;
1062 pSMB->Reserved3 = 0;
1063 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1064 byte_count = 3 /* pad */ + params + count;
1065
1066 pSMB->DataCount = cpu_to_le16(count);
1067 pSMB->ParameterCount = cpu_to_le16(params);
1068 pSMB->TotalDataCount = pSMB->DataCount;
1069 pSMB->TotalParameterCount = pSMB->ParameterCount;
1070 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1071 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001072 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001073 pSMB->ByteCount = cpu_to_le16(byte_count);
1074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1076 if (rc) {
1077 cFYI(1, ("Posix create returned %d", rc));
1078 goto psx_create_err;
1079 }
1080
Steve French790fe572007-07-07 19:25:05 +00001081 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001082 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1083
1084 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1085 rc = -EIO; /* bad smb */
1086 goto psx_create_err;
1087 }
1088
1089 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001090 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001091 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001092
Steve French2dd29d32007-04-23 22:07:35 +00001093 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001094 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001095 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1096 /* Let caller know file was created so we can set the mode. */
1097 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001098 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001099 *pOplock |= CIFS_CREATE_ACTION;
1100 /* check to make sure response data is there */
Steve French790fe572007-07-07 19:25:05 +00001101 if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001102 pRetData->Type = -1; /* unknown */
1103#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001104 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001105#endif
1106 } else {
Steve French790fe572007-07-07 19:25:05 +00001107 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001108 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001109 cERROR(1, ("Open response data too small"));
Steve French2dd29d32007-04-23 22:07:35 +00001110 pRetData->Type = -1;
1111 goto psx_create_err;
1112 }
Steve French50c2f752007-07-13 00:33:32 +00001113 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001114 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French2dd29d32007-04-23 22:07:35 +00001115 sizeof (FILE_UNIX_BASIC_INFO));
1116 }
Steve French2dd29d32007-04-23 22:07:35 +00001117
1118psx_create_err:
1119 cifs_buf_release(pSMB);
1120
1121 cifs_stats_inc(&tcon->num_mkdirs);
1122
1123 if (rc == -EAGAIN)
1124 goto PsxCreat;
1125
Steve French50c2f752007-07-13 00:33:32 +00001126 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001127}
1128
Steve Frencha9d02ad2005-08-24 23:06:05 -07001129static __u16 convert_disposition(int disposition)
1130{
1131 __u16 ofun = 0;
1132
1133 switch (disposition) {
1134 case FILE_SUPERSEDE:
1135 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1136 break;
1137 case FILE_OPEN:
1138 ofun = SMBOPEN_OAPPEND;
1139 break;
1140 case FILE_CREATE:
1141 ofun = SMBOPEN_OCREATE;
1142 break;
1143 case FILE_OPEN_IF:
1144 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1145 break;
1146 case FILE_OVERWRITE:
1147 ofun = SMBOPEN_OTRUNC;
1148 break;
1149 case FILE_OVERWRITE_IF:
1150 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1151 break;
1152 default:
Steve French790fe572007-07-07 19:25:05 +00001153 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001154 ofun = SMBOPEN_OAPPEND; /* regular open */
1155 }
1156 return ofun;
1157}
1158
1159int
1160SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1161 const char *fileName, const int openDisposition,
1162 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001163 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 const struct nls_table *nls_codepage, int remap)
1165{
1166 int rc = -EACCES;
1167 OPENX_REQ *pSMB = NULL;
1168 OPENX_RSP *pSMBr = NULL;
1169 int bytes_returned;
1170 int name_len;
1171 __u16 count;
1172
1173OldOpenRetry:
1174 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1175 (void **) &pSMBr);
1176 if (rc)
1177 return rc;
1178
1179 pSMB->AndXCommand = 0xFF; /* none */
1180
1181 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1182 count = 1; /* account for one byte pad to word boundary */
1183 name_len =
1184 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1185 fileName, PATH_MAX, nls_codepage, remap);
1186 name_len++; /* trailing null */
1187 name_len *= 2;
1188 } else { /* BB improve check for buffer overruns BB */
1189 count = 0; /* no pad */
1190 name_len = strnlen(fileName, PATH_MAX);
1191 name_len++; /* trailing null */
1192 strncpy(pSMB->fileName, fileName, name_len);
1193 }
1194 if (*pOplock & REQ_OPLOCK)
1195 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1196 else if (*pOplock & REQ_BATCHOPLOCK) {
1197 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1198 }
1199 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1200 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1201 /* 0 = read
1202 1 = write
1203 2 = rw
1204 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001205 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 pSMB->Mode = cpu_to_le16(2);
1207 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1208 /* set file as system file if special file such
1209 as fifo and server expecting SFU style and
1210 no Unix extensions */
1211
Steve French790fe572007-07-07 19:25:05 +00001212 if (create_options & CREATE_OPTION_SPECIAL)
1213 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1214 else
Steve French3e87d802005-09-18 20:49:21 -07001215 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216
1217 /* if ((omode & S_IWUGO) == 0)
1218 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1219 /* Above line causes problems due to vfs splitting create into two
1220 pieces - need to set mode after file created not while it is
1221 being created */
1222
1223 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001224/* pSMB->CreateOptions = cpu_to_le32(create_options &
1225 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001227
1228 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001229 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 count += name_len;
1231 pSMB->hdr.smb_buf_length += count;
1232
1233 pSMB->ByteCount = cpu_to_le16(count);
1234 /* long_op set to 1 to allow for oplock break timeouts */
1235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001236 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 cifs_stats_inc(&tcon->num_opens);
1238 if (rc) {
1239 cFYI(1, ("Error in Open = %d", rc));
1240 } else {
1241 /* BB verify if wct == 15 */
1242
1243/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1244
1245 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1246 /* Let caller know file was created so we can set the mode. */
1247 /* Do we care about the CreateAction in any other cases? */
1248 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001249/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 *pOplock |= CIFS_CREATE_ACTION; */
1251 /* BB FIXME END */
1252
Steve French790fe572007-07-07 19:25:05 +00001253 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1255 pfile_info->LastAccessTime = 0; /* BB fixme */
1256 pfile_info->LastWriteTime = 0; /* BB fixme */
1257 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001258 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001259 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001261 pfile_info->AllocationSize =
1262 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1263 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->NumberOfLinks = cpu_to_le32(1);
1265 }
1266 }
1267
1268 cifs_buf_release(pSMB);
1269 if (rc == -EAGAIN)
1270 goto OldOpenRetry;
1271 return rc;
1272}
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274int
1275CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1276 const char *fileName, const int openDisposition,
1277 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001278 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001279 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280{
1281 int rc = -EACCES;
1282 OPEN_REQ *pSMB = NULL;
1283 OPEN_RSP *pSMBr = NULL;
1284 int bytes_returned;
1285 int name_len;
1286 __u16 count;
1287
1288openRetry:
1289 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1290 (void **) &pSMBr);
1291 if (rc)
1292 return rc;
1293
1294 pSMB->AndXCommand = 0xFF; /* none */
1295
1296 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1297 count = 1; /* account for one byte pad to word boundary */
1298 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001299 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001300 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 name_len++; /* trailing null */
1302 name_len *= 2;
1303 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001304 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 count = 0; /* no pad */
1306 name_len = strnlen(fileName, PATH_MAX);
1307 name_len++; /* trailing null */
1308 pSMB->NameLength = cpu_to_le16(name_len);
1309 strncpy(pSMB->fileName, fileName, name_len);
1310 }
1311 if (*pOplock & REQ_OPLOCK)
1312 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1313 else if (*pOplock & REQ_BATCHOPLOCK) {
1314 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1315 }
1316 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1317 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001318 /* set file as system file if special file such
1319 as fifo and server expecting SFU style and
1320 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001321 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001322 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1323 else
1324 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 /* XP does not handle ATTR_POSIX_SEMANTICS */
1326 /* but it helps speed up case sensitive checks for other
1327 servers such as Samba */
1328 if (tcon->ses->capabilities & CAP_UNIX)
1329 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1330
1331 /* if ((omode & S_IWUGO) == 0)
1332 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1333 /* Above line causes problems due to vfs splitting create into two
1334 pieces - need to set mode after file created not while it is
1335 being created */
1336 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1337 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001338 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001339 /* BB Expirement with various impersonation levels and verify */
1340 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 pSMB->SecurityFlags =
1342 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1343
1344 count += name_len;
1345 pSMB->hdr.smb_buf_length += count;
1346
1347 pSMB->ByteCount = cpu_to_le16(count);
1348 /* long_op set to 1 to allow for oplock break timeouts */
1349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1350 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001351 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 if (rc) {
1353 cFYI(1, ("Error in Open = %d", rc));
1354 } else {
Steve French09d1db52005-04-28 22:41:08 -07001355 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1357 /* Let caller know file was created so we can set the mode. */
1358 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001359 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001360 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001361 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001362 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 36 /* CreationTime to Attributes */);
1364 /* the file_info buf is endian converted by caller */
1365 pfile_info->AllocationSize = pSMBr->AllocationSize;
1366 pfile_info->EndOfFile = pSMBr->EndOfFile;
1367 pfile_info->NumberOfLinks = cpu_to_le32(1);
1368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 cifs_buf_release(pSMB);
1372 if (rc == -EAGAIN)
1373 goto openRetry;
1374 return rc;
1375}
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377int
Steve French50c2f752007-07-13 00:33:32 +00001378CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1379 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1380 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
1382 int rc = -EACCES;
1383 READ_REQ *pSMB = NULL;
1384 READ_RSP *pSMBr = NULL;
1385 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001386 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001387 int resp_buf_type = 0;
1388 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
Steve French790fe572007-07-07 19:25:05 +00001390 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1391 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001392 wct = 12;
1393 else
1394 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001397 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 if (rc)
1399 return rc;
1400
1401 /* tcon and ses pointer are checked in smb_init */
1402 if (tcon->ses->server == NULL)
1403 return -ECONNABORTED;
1404
Steve Frenchec637e32005-12-12 20:53:18 -08001405 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 pSMB->Fid = netfid;
1407 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001408 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001409 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001410 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001411 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001412
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 pSMB->Remaining = 0;
1414 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1415 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001416 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001417 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1418 else {
1419 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001420 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001421 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001422 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001423 }
Steve Frenchec637e32005-12-12 20:53:18 -08001424
1425 iov[0].iov_base = (char *)pSMB;
1426 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve French50c2f752007-07-13 00:33:32 +00001427 rc = SendReceive2(xid, tcon->ses, iov,
Steve Frenchec637e32005-12-12 20:53:18 -08001428 1 /* num iovecs */,
Steve French50c2f752007-07-13 00:33:32 +00001429 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001430 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001431 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 if (rc) {
1433 cERROR(1, ("Send error in read = %d", rc));
1434 } else {
1435 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1436 data_length = data_length << 16;
1437 data_length += le16_to_cpu(pSMBr->DataLength);
1438 *nbytes = data_length;
1439
1440 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001441 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001443 cFYI(1, ("bad length %d for count %d",
1444 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 rc = -EIO;
1446 *nbytes = 0;
1447 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001448 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 le16_to_cpu(pSMBr->DataOffset);
Steve French790fe572007-07-07 19:25:05 +00001450/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001451 cERROR(1,("Faulting on read rc = %d",rc));
1452 rc = -EFAULT;
Steve Frenchec637e32005-12-12 20:53:18 -08001453 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001454 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001455 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 }
1457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Steve French4b8f9302006-02-26 16:41:18 +00001459/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001460 if (*buf) {
1461 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001462 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001463 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001464 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001465 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001466 /* return buffer to caller to free */
1467 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001468 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001469 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001470 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001471 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001472 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001473
1474 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 since file handle passed in no longer valid */
1476 return rc;
1477}
1478
Steve Frenchec637e32005-12-12 20:53:18 -08001479
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480int
1481CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1482 const int netfid, const unsigned int count,
1483 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001484 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485{
1486 int rc = -EACCES;
1487 WRITE_REQ *pSMB = NULL;
1488 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001489 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 __u32 bytes_sent;
1491 __u16 byte_count;
1492
1493 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001494 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001495 return -ECONNABORTED;
1496
Steve French790fe572007-07-07 19:25:05 +00001497 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001498 wct = 14;
1499 else
1500 wct = 12;
1501
1502 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 (void **) &pSMBr);
1504 if (rc)
1505 return rc;
1506 /* tcon and ses pointer are checked in smb_init */
1507 if (tcon->ses->server == NULL)
1508 return -ECONNABORTED;
1509
1510 pSMB->AndXCommand = 0xFF; /* none */
1511 pSMB->Fid = netfid;
1512 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001513 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001514 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001515 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001516 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001517
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 pSMB->Reserved = 0xFFFFFFFF;
1519 pSMB->WriteMode = 0;
1520 pSMB->Remaining = 0;
1521
Steve French50c2f752007-07-13 00:33:32 +00001522 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 can send more if LARGE_WRITE_X capability returned by the server and if
1524 our buffer is big enough or if we convert to iovecs on socket writes
1525 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001526 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1528 } else {
1529 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1530 & ~0xFF;
1531 }
1532
1533 if (bytes_sent > count)
1534 bytes_sent = count;
1535 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001536 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001537 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001538 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001539 else if (ubuf) {
1540 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 cifs_buf_release(pSMB);
1542 return -EFAULT;
1543 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001544 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 /* No buffer */
1546 cifs_buf_release(pSMB);
1547 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001548 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001549 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001550 byte_count = bytes_sent + 1; /* pad */
1551 else /* wct == 12 */ {
1552 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1555 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001557
Steve French790fe572007-07-07 19:25:05 +00001558 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001559 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001560 else { /* old style write has byte count 4 bytes earlier
1561 so 4 bytes pad */
1562 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001563 (struct smb_com_writex_req *)pSMB;
1564 pSMBW->ByteCount = cpu_to_le16(byte_count);
1565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
1567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1568 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001569 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 if (rc) {
1571 cFYI(1, ("Send error in write = %d", rc));
1572 *nbytes = 0;
1573 } else {
1574 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1575 *nbytes = (*nbytes) << 16;
1576 *nbytes += le16_to_cpu(pSMBr->Count);
1577 }
1578
1579 cifs_buf_release(pSMB);
1580
Steve French50c2f752007-07-13 00:33:32 +00001581 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 since file handle passed in no longer valid */
1583
1584 return rc;
1585}
1586
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001587int
1588CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001590 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1591 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592{
1593 int rc = -EACCES;
1594 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001595 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001596 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001597 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
Steve French790fe572007-07-07 19:25:05 +00001599 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001600
Steve French790fe572007-07-07 19:25:05 +00001601 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001602 wct = 14;
1603 else
1604 wct = 12;
1605 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 if (rc)
1607 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 /* tcon and ses pointer are checked in smb_init */
1609 if (tcon->ses->server == NULL)
1610 return -ECONNABORTED;
1611
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001612 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 pSMB->Fid = netfid;
1614 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001615 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001616 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001617 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001618 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 pSMB->Reserved = 0xFFFFFFFF;
1620 pSMB->WriteMode = 0;
1621 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001624 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Steve French3e844692005-10-03 13:37:24 -07001626 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1627 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001628 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001629 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001630 pSMB->hdr.smb_buf_length += count+1;
1631 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001632 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1633 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001634 pSMB->ByteCount = cpu_to_le16(count + 1);
1635 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001636 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001637 (struct smb_com_writex_req *)pSMB;
1638 pSMBW->ByteCount = cpu_to_le16(count + 5);
1639 }
Steve French3e844692005-10-03 13:37:24 -07001640 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001641 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001642 iov[0].iov_len = smb_hdr_len + 4;
1643 else /* wct == 12 pad bigger by four bytes */
1644 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001645
Steve French3e844692005-10-03 13:37:24 -07001646
Steve Frenchec637e32005-12-12 20:53:18 -08001647 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001648 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001649 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001651 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001653 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001654 /* presumably this can not happen, but best to be safe */
1655 rc = -EIO;
1656 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001657 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001658 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001659 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1660 *nbytes = (*nbytes) << 16;
1661 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
Steve French4b8f9302006-02-26 16:41:18 +00001664/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001665 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001666 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001667 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001668 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Steve French50c2f752007-07-13 00:33:32 +00001670 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 since file handle passed in no longer valid */
1672
1673 return rc;
1674}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001675
1676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677int
1678CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1679 const __u16 smb_file_id, const __u64 len,
1680 const __u64 offset, const __u32 numUnlock,
1681 const __u32 numLock, const __u8 lockType, const int waitFlag)
1682{
1683 int rc = 0;
1684 LOCK_REQ *pSMB = NULL;
1685 LOCK_RSP *pSMBr = NULL;
1686 int bytes_returned;
1687 int timeout = 0;
1688 __u16 count;
1689
Steve French50c2f752007-07-13 00:33:32 +00001690 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001691 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1692
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 if (rc)
1694 return rc;
1695
Steve French46810cb2005-04-28 22:41:09 -07001696 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1697
Steve French790fe572007-07-07 19:25:05 +00001698 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 timeout = -1; /* no response expected */
1700 pSMB->Timeout = 0;
1701 } else if (waitFlag == TRUE) {
1702 timeout = 3; /* blocking operation, no timeout */
1703 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1704 } else {
1705 pSMB->Timeout = 0;
1706 }
1707
1708 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1709 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1710 pSMB->LockType = lockType;
1711 pSMB->AndXCommand = 0xFF; /* none */
1712 pSMB->Fid = smb_file_id; /* netfid stays le */
1713
Steve French790fe572007-07-07 19:25:05 +00001714 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1716 /* BB where to store pid high? */
1717 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1718 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1719 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1720 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1721 count = sizeof(LOCKING_ANDX_RANGE);
1722 } else {
1723 /* oplock break */
1724 count = 0;
1725 }
1726 pSMB->hdr.smb_buf_length += count;
1727 pSMB->ByteCount = cpu_to_le16(count);
1728
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001729 if (waitFlag) {
1730 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1731 (struct smb_hdr *) pSMBr, &bytes_returned);
1732 } else {
1733 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001735 }
Steve Frencha4544342005-08-24 13:59:35 -07001736 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 if (rc) {
1738 cFYI(1, ("Send error in Lock = %d", rc));
1739 }
Steve French46810cb2005-04-28 22:41:09 -07001740 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
Steve French50c2f752007-07-13 00:33:32 +00001742 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 since file handle passed in no longer valid */
1744 return rc;
1745}
1746
1747int
Steve French08547b02006-02-28 22:39:25 +00001748CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1749 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001750 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001751 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001752{
1753 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1754 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001755 struct cifs_posix_lock *parm_data;
1756 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001757 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001758 int bytes_returned = 0;
1759 __u16 params, param_offset, offset, byte_count, count;
1760
1761 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001762
Steve French790fe572007-07-07 19:25:05 +00001763 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001764 return EINVAL;
1765
Steve French08547b02006-02-28 22:39:25 +00001766 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1767
1768 if (rc)
1769 return rc;
1770
1771 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1772
Steve French50c2f752007-07-13 00:33:32 +00001773 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001774 pSMB->MaxSetupCount = 0;
1775 pSMB->Reserved = 0;
1776 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001777 pSMB->Reserved2 = 0;
1778 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1779 offset = param_offset + params;
1780
Steve French08547b02006-02-28 22:39:25 +00001781 count = sizeof(struct cifs_posix_lock);
1782 pSMB->MaxParameterCount = cpu_to_le16(2);
1783 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1784 pSMB->SetupCount = 1;
1785 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001786 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001787 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1788 else
1789 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1790 byte_count = 3 /* pad */ + params + count;
1791 pSMB->DataCount = cpu_to_le16(count);
1792 pSMB->ParameterCount = cpu_to_le16(params);
1793 pSMB->TotalDataCount = pSMB->DataCount;
1794 pSMB->TotalParameterCount = pSMB->ParameterCount;
1795 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001796 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001797 (((char *) &pSMB->hdr.Protocol) + offset);
1798
1799 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001800 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001801 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001802 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001803 pSMB->Timeout = cpu_to_le32(-1);
1804 } else
1805 pSMB->Timeout = 0;
1806
Steve French08547b02006-02-28 22:39:25 +00001807 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001808 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001809 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001810
1811 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001812 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001813 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1814 pSMB->Reserved4 = 0;
1815 pSMB->hdr.smb_buf_length += byte_count;
1816 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001817 if (waitFlag) {
1818 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1819 (struct smb_hdr *) pSMBr, &bytes_returned);
1820 } else {
1821 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001822 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001823 }
1824
Steve French08547b02006-02-28 22:39:25 +00001825 if (rc) {
1826 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001827 } else if (get_flag) {
1828 /* lock structure can be returned on get */
1829 __u16 data_offset;
1830 __u16 data_count;
1831 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001832
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001833 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1834 rc = -EIO; /* bad smb */
1835 goto plk_err_exit;
1836 }
Steve French790fe572007-07-07 19:25:05 +00001837 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001838 rc = -EINVAL;
1839 goto plk_err_exit;
1840 }
1841 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1842 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001843 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001844 rc = -EIO;
1845 goto plk_err_exit;
1846 }
1847 parm_data = (struct cifs_posix_lock *)
1848 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001849 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001850 pLockData->fl_type = F_UNLCK;
1851 }
Steve French50c2f752007-07-13 00:33:32 +00001852
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001853plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001854 if (pSMB)
1855 cifs_small_buf_release(pSMB);
1856
1857 /* Note: On -EAGAIN error only caller can retry on handle based calls
1858 since file handle passed in no longer valid */
1859
1860 return rc;
1861}
1862
1863
1864int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1866{
1867 int rc = 0;
1868 CLOSE_REQ *pSMB = NULL;
1869 CLOSE_RSP *pSMBr = NULL;
1870 int bytes_returned;
1871 cFYI(1, ("In CIFSSMBClose"));
1872
1873/* do not retry on dead session on close */
1874 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001875 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 return 0;
1877 if (rc)
1878 return rc;
1879
1880 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1881
1882 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001883 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 pSMB->ByteCount = 0;
1885 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1886 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001887 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001889 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 /* EINTR is expected when user ctl-c to kill app */
1891 cERROR(1, ("Send error in Close = %d", rc));
1892 }
1893 }
1894
1895 cifs_small_buf_release(pSMB);
1896
1897 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001898 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 rc = 0;
1900
1901 return rc;
1902}
1903
1904int
1905CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1906 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001907 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908{
1909 int rc = 0;
1910 RENAME_REQ *pSMB = NULL;
1911 RENAME_RSP *pSMBr = NULL;
1912 int bytes_returned;
1913 int name_len, name_len2;
1914 __u16 count;
1915
1916 cFYI(1, ("In CIFSSMBRename"));
1917renameRetry:
1918 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1919 (void **) &pSMBr);
1920 if (rc)
1921 return rc;
1922
1923 pSMB->BufferFormat = 0x04;
1924 pSMB->SearchAttributes =
1925 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1926 ATTR_DIRECTORY);
1927
1928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1929 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001930 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001931 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 name_len++; /* trailing null */
1933 name_len *= 2;
1934 pSMB->OldFileName[name_len] = 0x04; /* pad */
1935 /* protocol requires ASCII signature byte on Unicode string */
1936 pSMB->OldFileName[name_len + 1] = 0x00;
1937 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001938 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001939 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1941 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001942 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 name_len = strnlen(fromName, PATH_MAX);
1944 name_len++; /* trailing null */
1945 strncpy(pSMB->OldFileName, fromName, name_len);
1946 name_len2 = strnlen(toName, PATH_MAX);
1947 name_len2++; /* trailing null */
1948 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1949 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1950 name_len2++; /* trailing null */
1951 name_len2++; /* signature byte */
1952 }
1953
1954 count = 1 /* 1st signature byte */ + name_len + name_len2;
1955 pSMB->hdr.smb_buf_length += count;
1956 pSMB->ByteCount = cpu_to_le16(count);
1957
1958 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1959 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001960 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (rc) {
1962 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 cifs_buf_release(pSMB);
1966
1967 if (rc == -EAGAIN)
1968 goto renameRetry;
1969
1970 return rc;
1971}
1972
Steve French50c2f752007-07-13 00:33:32 +00001973int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1974 int netfid, char *target_name,
1975 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976{
1977 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1978 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001979 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 char *data_offset;
1981 char dummy_string[30];
1982 int rc = 0;
1983 int bytes_returned = 0;
1984 int len_of_str;
1985 __u16 params, param_offset, offset, count, byte_count;
1986
1987 cFYI(1, ("Rename to File by handle"));
1988 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1989 (void **) &pSMBr);
1990 if (rc)
1991 return rc;
1992
1993 params = 6;
1994 pSMB->MaxSetupCount = 0;
1995 pSMB->Reserved = 0;
1996 pSMB->Flags = 0;
1997 pSMB->Timeout = 0;
1998 pSMB->Reserved2 = 0;
1999 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2000 offset = param_offset + params;
2001
2002 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2003 rename_info = (struct set_file_rename *) data_offset;
2004 pSMB->MaxParameterCount = cpu_to_le16(2);
2005 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2006 pSMB->SetupCount = 1;
2007 pSMB->Reserved3 = 0;
2008 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2009 byte_count = 3 /* pad */ + params;
2010 pSMB->ParameterCount = cpu_to_le16(params);
2011 pSMB->TotalParameterCount = pSMB->ParameterCount;
2012 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2013 pSMB->DataOffset = cpu_to_le16(offset);
2014 /* construct random name ".cifs_tmp<inodenum><mid>" */
2015 rename_info->overwrite = cpu_to_le32(1);
2016 rename_info->root_fid = 0;
2017 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002018 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002019 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2020 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002021 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002023 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002024 target_name, PATH_MAX, nls_codepage,
2025 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 }
2027 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2028 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2029 byte_count += count;
2030 pSMB->DataCount = cpu_to_le16(count);
2031 pSMB->TotalDataCount = pSMB->DataCount;
2032 pSMB->Fid = netfid;
2033 pSMB->InformationLevel =
2034 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2035 pSMB->Reserved4 = 0;
2036 pSMB->hdr.smb_buf_length += byte_count;
2037 pSMB->ByteCount = cpu_to_le16(byte_count);
2038 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002039 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002040 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002042 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 cifs_buf_release(pSMB);
2046
2047 /* Note: On -EAGAIN error only caller can retry on handle based calls
2048 since file handle passed in no longer valid */
2049
2050 return rc;
2051}
2052
2053int
Steve French50c2f752007-07-13 00:33:32 +00002054CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2055 const __u16 target_tid, const char *toName, const int flags,
2056 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057{
2058 int rc = 0;
2059 COPY_REQ *pSMB = NULL;
2060 COPY_RSP *pSMBr = NULL;
2061 int bytes_returned;
2062 int name_len, name_len2;
2063 __u16 count;
2064
2065 cFYI(1, ("In CIFSSMBCopy"));
2066copyRetry:
2067 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2068 (void **) &pSMBr);
2069 if (rc)
2070 return rc;
2071
2072 pSMB->BufferFormat = 0x04;
2073 pSMB->Tid2 = target_tid;
2074
2075 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2076
2077 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002078 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002079 fromName, PATH_MAX, nls_codepage,
2080 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 name_len++; /* trailing null */
2082 name_len *= 2;
2083 pSMB->OldFileName[name_len] = 0x04; /* pad */
2084 /* protocol requires ASCII signature byte on Unicode string */
2085 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002086 name_len2 =
2087 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002088 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2090 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002091 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 name_len = strnlen(fromName, PATH_MAX);
2093 name_len++; /* trailing null */
2094 strncpy(pSMB->OldFileName, fromName, name_len);
2095 name_len2 = strnlen(toName, PATH_MAX);
2096 name_len2++; /* trailing null */
2097 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2098 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2099 name_len2++; /* trailing null */
2100 name_len2++; /* signature byte */
2101 }
2102
2103 count = 1 /* 1st signature byte */ + name_len + name_len2;
2104 pSMB->hdr.smb_buf_length += count;
2105 pSMB->ByteCount = cpu_to_le16(count);
2106
2107 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2108 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2109 if (rc) {
2110 cFYI(1, ("Send error in copy = %d with %d files copied",
2111 rc, le16_to_cpu(pSMBr->CopyCount)));
2112 }
2113 if (pSMB)
2114 cifs_buf_release(pSMB);
2115
2116 if (rc == -EAGAIN)
2117 goto copyRetry;
2118
2119 return rc;
2120}
2121
2122int
2123CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2124 const char *fromName, const char *toName,
2125 const struct nls_table *nls_codepage)
2126{
2127 TRANSACTION2_SPI_REQ *pSMB = NULL;
2128 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2129 char *data_offset;
2130 int name_len;
2131 int name_len_target;
2132 int rc = 0;
2133 int bytes_returned = 0;
2134 __u16 params, param_offset, offset, byte_count;
2135
2136 cFYI(1, ("In Symlink Unix style"));
2137createSymLinkRetry:
2138 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2139 (void **) &pSMBr);
2140 if (rc)
2141 return rc;
2142
2143 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2144 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002145 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 /* find define for this maxpathcomponent */
2147 , nls_codepage);
2148 name_len++; /* trailing null */
2149 name_len *= 2;
2150
Steve French50c2f752007-07-13 00:33:32 +00002151 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 name_len = strnlen(fromName, PATH_MAX);
2153 name_len++; /* trailing null */
2154 strncpy(pSMB->FileName, fromName, name_len);
2155 }
2156 params = 6 + name_len;
2157 pSMB->MaxSetupCount = 0;
2158 pSMB->Reserved = 0;
2159 pSMB->Flags = 0;
2160 pSMB->Timeout = 0;
2161 pSMB->Reserved2 = 0;
2162 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002163 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 offset = param_offset + params;
2165
2166 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2167 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2168 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002169 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 /* find define for this maxpathcomponent */
2171 , nls_codepage);
2172 name_len_target++; /* trailing null */
2173 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002174 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 name_len_target = strnlen(toName, PATH_MAX);
2176 name_len_target++; /* trailing null */
2177 strncpy(data_offset, toName, name_len_target);
2178 }
2179
2180 pSMB->MaxParameterCount = cpu_to_le16(2);
2181 /* BB find exact max on data count below from sess */
2182 pSMB->MaxDataCount = cpu_to_le16(1000);
2183 pSMB->SetupCount = 1;
2184 pSMB->Reserved3 = 0;
2185 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2186 byte_count = 3 /* pad */ + params + name_len_target;
2187 pSMB->DataCount = cpu_to_le16(name_len_target);
2188 pSMB->ParameterCount = cpu_to_le16(params);
2189 pSMB->TotalDataCount = pSMB->DataCount;
2190 pSMB->TotalParameterCount = pSMB->ParameterCount;
2191 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2192 pSMB->DataOffset = cpu_to_le16(offset);
2193 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2194 pSMB->Reserved4 = 0;
2195 pSMB->hdr.smb_buf_length += byte_count;
2196 pSMB->ByteCount = cpu_to_le16(byte_count);
2197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002199 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002201 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 }
2203
2204 if (pSMB)
2205 cifs_buf_release(pSMB);
2206
2207 if (rc == -EAGAIN)
2208 goto createSymLinkRetry;
2209
2210 return rc;
2211}
2212
2213int
2214CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2215 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002216 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217{
2218 TRANSACTION2_SPI_REQ *pSMB = NULL;
2219 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2220 char *data_offset;
2221 int name_len;
2222 int name_len_target;
2223 int rc = 0;
2224 int bytes_returned = 0;
2225 __u16 params, param_offset, offset, byte_count;
2226
2227 cFYI(1, ("In Create Hard link Unix style"));
2228createHardLinkRetry:
2229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2230 (void **) &pSMBr);
2231 if (rc)
2232 return rc;
2233
2234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002235 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002236 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 name_len++; /* trailing null */
2238 name_len *= 2;
2239
Steve French50c2f752007-07-13 00:33:32 +00002240 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 name_len = strnlen(toName, PATH_MAX);
2242 name_len++; /* trailing null */
2243 strncpy(pSMB->FileName, toName, name_len);
2244 }
2245 params = 6 + name_len;
2246 pSMB->MaxSetupCount = 0;
2247 pSMB->Reserved = 0;
2248 pSMB->Flags = 0;
2249 pSMB->Timeout = 0;
2250 pSMB->Reserved2 = 0;
2251 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002252 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 offset = param_offset + params;
2254
2255 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2256 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2257 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002258 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002259 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 name_len_target++; /* trailing null */
2261 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002262 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 name_len_target = strnlen(fromName, PATH_MAX);
2264 name_len_target++; /* trailing null */
2265 strncpy(data_offset, fromName, name_len_target);
2266 }
2267
2268 pSMB->MaxParameterCount = cpu_to_le16(2);
2269 /* BB find exact max on data count below from sess*/
2270 pSMB->MaxDataCount = cpu_to_le16(1000);
2271 pSMB->SetupCount = 1;
2272 pSMB->Reserved3 = 0;
2273 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2274 byte_count = 3 /* pad */ + params + name_len_target;
2275 pSMB->ParameterCount = cpu_to_le16(params);
2276 pSMB->TotalParameterCount = pSMB->ParameterCount;
2277 pSMB->DataCount = cpu_to_le16(name_len_target);
2278 pSMB->TotalDataCount = pSMB->DataCount;
2279 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2280 pSMB->DataOffset = cpu_to_le16(offset);
2281 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2282 pSMB->Reserved4 = 0;
2283 pSMB->hdr.smb_buf_length += byte_count;
2284 pSMB->ByteCount = cpu_to_le16(byte_count);
2285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002287 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 if (rc) {
2289 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2290 }
2291
2292 cifs_buf_release(pSMB);
2293 if (rc == -EAGAIN)
2294 goto createHardLinkRetry;
2295
2296 return rc;
2297}
2298
2299int
2300CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2301 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002302 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303{
2304 int rc = 0;
2305 NT_RENAME_REQ *pSMB = NULL;
2306 RENAME_RSP *pSMBr = NULL;
2307 int bytes_returned;
2308 int name_len, name_len2;
2309 __u16 count;
2310
2311 cFYI(1, ("In CIFSCreateHardLink"));
2312winCreateHardLinkRetry:
2313
2314 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2315 (void **) &pSMBr);
2316 if (rc)
2317 return rc;
2318
2319 pSMB->SearchAttributes =
2320 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2321 ATTR_DIRECTORY);
2322 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2323 pSMB->ClusterCount = 0;
2324
2325 pSMB->BufferFormat = 0x04;
2326
2327 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2328 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002329 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002330 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 name_len++; /* trailing null */
2332 name_len *= 2;
2333 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002334 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002336 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002337 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2339 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002340 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 name_len = strnlen(fromName, PATH_MAX);
2342 name_len++; /* trailing null */
2343 strncpy(pSMB->OldFileName, fromName, name_len);
2344 name_len2 = strnlen(toName, PATH_MAX);
2345 name_len2++; /* trailing null */
2346 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2347 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2348 name_len2++; /* trailing null */
2349 name_len2++; /* signature byte */
2350 }
2351
2352 count = 1 /* string type byte */ + name_len + name_len2;
2353 pSMB->hdr.smb_buf_length += count;
2354 pSMB->ByteCount = cpu_to_le16(count);
2355
2356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002358 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 if (rc) {
2360 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2361 }
2362 cifs_buf_release(pSMB);
2363 if (rc == -EAGAIN)
2364 goto winCreateHardLinkRetry;
2365
2366 return rc;
2367}
2368
2369int
2370CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2371 const unsigned char *searchName,
2372 char *symlinkinfo, const int buflen,
2373 const struct nls_table *nls_codepage)
2374{
2375/* SMB_QUERY_FILE_UNIX_LINK */
2376 TRANSACTION2_QPI_REQ *pSMB = NULL;
2377 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2378 int rc = 0;
2379 int bytes_returned;
2380 int name_len;
2381 __u16 params, byte_count;
2382
2383 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2384
2385querySymLinkRetry:
2386 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2387 (void **) &pSMBr);
2388 if (rc)
2389 return rc;
2390
2391 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2392 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002393 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2394 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 name_len++; /* trailing null */
2396 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002397 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 name_len = strnlen(searchName, PATH_MAX);
2399 name_len++; /* trailing null */
2400 strncpy(pSMB->FileName, searchName, name_len);
2401 }
2402
2403 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2404 pSMB->TotalDataCount = 0;
2405 pSMB->MaxParameterCount = cpu_to_le16(2);
2406 /* BB find exact max data count below from sess structure BB */
2407 pSMB->MaxDataCount = cpu_to_le16(4000);
2408 pSMB->MaxSetupCount = 0;
2409 pSMB->Reserved = 0;
2410 pSMB->Flags = 0;
2411 pSMB->Timeout = 0;
2412 pSMB->Reserved2 = 0;
2413 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002414 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 pSMB->DataCount = 0;
2416 pSMB->DataOffset = 0;
2417 pSMB->SetupCount = 1;
2418 pSMB->Reserved3 = 0;
2419 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2420 byte_count = params + 1 /* pad */ ;
2421 pSMB->TotalParameterCount = cpu_to_le16(params);
2422 pSMB->ParameterCount = pSMB->TotalParameterCount;
2423 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2424 pSMB->Reserved4 = 0;
2425 pSMB->hdr.smb_buf_length += byte_count;
2426 pSMB->ByteCount = cpu_to_le16(byte_count);
2427
2428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2430 if (rc) {
2431 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2432 } else {
2433 /* decode response */
2434
2435 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2436 if (rc || (pSMBr->ByteCount < 2))
2437 /* BB also check enough total bytes returned */
2438 rc = -EIO; /* bad smb */
2439 else {
2440 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2441 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2442
2443 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2444 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002445 &pSMBr->hdr.Protocol + data_offset),
2446 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002447 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002449 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2450 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 name_len, nls_codepage);
2452 } else {
2453 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002454 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 data_offset,
2456 min_t(const int, buflen, count));
2457 }
2458 symlinkinfo[buflen] = 0;
2459 /* just in case so calling code does not go off the end of buffer */
2460 }
2461 }
2462 cifs_buf_release(pSMB);
2463 if (rc == -EAGAIN)
2464 goto querySymLinkRetry;
2465 return rc;
2466}
2467
Steve French0a4b92c2006-01-12 15:44:21 -08002468/* Initialize NT TRANSACT SMB into small smb request buffer.
2469 This assumes that all NT TRANSACTS that we init here have
2470 total parm and data under about 400 bytes (to fit in small cifs
2471 buffer size), which is the case so far, it easily fits. NB:
2472 Setup words themselves and ByteCount
2473 MaxSetupCount (size of returned setup area) and
2474 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002475static int
Steve French0a4b92c2006-01-12 15:44:21 -08002476smb_init_ntransact(const __u16 sub_command, const int setup_count,
2477 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002478 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002479{
2480 int rc;
2481 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002482 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002483
2484 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2485 (void **)&pSMB);
2486 if (rc)
2487 return rc;
2488 *ret_buf = (void *)pSMB;
2489 pSMB->Reserved = 0;
2490 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2491 pSMB->TotalDataCount = 0;
2492 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2493 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2494 pSMB->ParameterCount = pSMB->TotalParameterCount;
2495 pSMB->DataCount = pSMB->TotalDataCount;
2496 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2497 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2498 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2499 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2500 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2501 pSMB->SubCommand = cpu_to_le16(sub_command);
2502 return 0;
2503}
2504
2505static int
Steve French50c2f752007-07-13 00:33:32 +00002506validate_ntransact(char *buf, char **ppparm, char **ppdata,
2507 int *pdatalen, int *pparmlen)
Steve French0a4b92c2006-01-12 15:44:21 -08002508{
Steve French50c2f752007-07-13 00:33:32 +00002509 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002510 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002511 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002512
Steve French790fe572007-07-07 19:25:05 +00002513 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002514 return -EINVAL;
2515
2516 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2517
2518 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002519 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002520 (char *)&pSMBr->ByteCount;
2521
Steve French0a4b92c2006-01-12 15:44:21 -08002522 data_offset = le32_to_cpu(pSMBr->DataOffset);
2523 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002524 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002525 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2526
2527 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2528 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2529
2530 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002531 if (*ppparm > end_of_smb) {
2532 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002533 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002534 } else if (parm_count + *ppparm > end_of_smb) {
2535 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002536 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002537 } else if (*ppdata > end_of_smb) {
2538 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002539 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002540 } else if (data_count + *ppdata > end_of_smb) {
Steve French0a4b92c2006-01-12 15:44:21 -08002541 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002542 *ppdata, data_count, (data_count + *ppdata),
2543 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002544 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002545 } else if (parm_count + data_count > pSMBr->ByteCount) {
2546 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002547 return -EINVAL;
2548 }
2549 return 0;
2550}
2551
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552int
2553CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2554 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002555 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 const struct nls_table *nls_codepage)
2557{
2558 int rc = 0;
2559 int bytes_returned;
2560 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002561 struct smb_com_transaction_ioctl_req *pSMB;
2562 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
2564 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2565 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2566 (void **) &pSMBr);
2567 if (rc)
2568 return rc;
2569
2570 pSMB->TotalParameterCount = 0 ;
2571 pSMB->TotalDataCount = 0;
2572 pSMB->MaxParameterCount = cpu_to_le32(2);
2573 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002574 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2575 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 pSMB->MaxSetupCount = 4;
2577 pSMB->Reserved = 0;
2578 pSMB->ParameterOffset = 0;
2579 pSMB->DataCount = 0;
2580 pSMB->DataOffset = 0;
2581 pSMB->SetupCount = 4;
2582 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2583 pSMB->ParameterCount = pSMB->TotalParameterCount;
2584 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2585 pSMB->IsFsctl = 1; /* FSCTL */
2586 pSMB->IsRootFlag = 0;
2587 pSMB->Fid = fid; /* file handle always le */
2588 pSMB->ByteCount = 0;
2589
2590 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2591 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2592 if (rc) {
2593 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2594 } else { /* decode response */
2595 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2596 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2597 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2598 /* BB also check enough total bytes returned */
2599 rc = -EIO; /* bad smb */
2600 else {
Steve French790fe572007-07-07 19:25:05 +00002601 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002602 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002603 pSMBr->ByteCount +
2604 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
Steve French50c2f752007-07-13 00:33:32 +00002606 struct reparse_data *reparse_buf =
2607 (struct reparse_data *)
2608 ((char *)&pSMBr->hdr.Protocol
2609 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002610 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 rc = -EIO;
2612 goto qreparse_out;
2613 }
Steve French790fe572007-07-07 19:25:05 +00002614 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 reparse_buf->TargetNameOffset +
2616 reparse_buf->TargetNameLen) >
2617 end_of_smb) {
Steve French63135e02007-07-17 17:34:02 +00002618 cFYI(1,("reparse buf goes beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 rc = -EIO;
2620 goto qreparse_out;
2621 }
Steve French50c2f752007-07-13 00:33:32 +00002622
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2624 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002625 (reparse_buf->LinkNamesBuf +
2626 reparse_buf->TargetNameOffset),
2627 min(buflen/2,
2628 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002630 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 reparse_buf->TargetNameOffset),
2632 name_len, nls_codepage);
2633 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002634 strncpy(symlinkinfo,
2635 reparse_buf->LinkNamesBuf +
2636 reparse_buf->TargetNameOffset,
2637 min_t(const int, buflen,
2638 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 }
2640 } else {
2641 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002642 cFYI(1, ("Invalid return data count on "
2643 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 }
2645 symlinkinfo[buflen] = 0; /* just in case so the caller
2646 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002647 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 }
2649 }
2650qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002651 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
2653 /* Note: On -EAGAIN error only caller can retry on handle based calls
2654 since file handle passed in no longer valid */
2655
2656 return rc;
2657}
2658
2659#ifdef CONFIG_CIFS_POSIX
2660
2661/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002662static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2663 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664{
2665 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002666 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2667 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2668 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2670
2671 return;
2672}
2673
2674/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002675static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2676 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677{
2678 int size = 0;
2679 int i;
2680 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002681 struct cifs_posix_ace *pACE;
2682 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2683 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
2685 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2686 return -EOPNOTSUPP;
2687
Steve French790fe572007-07-07 19:25:05 +00002688 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 count = le16_to_cpu(cifs_acl->access_entry_count);
2690 pACE = &cifs_acl->ace_array[0];
2691 size = sizeof(struct cifs_posix_acl);
2692 size += sizeof(struct cifs_posix_ace) * count;
2693 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002694 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002695 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2696 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 return -EINVAL;
2698 }
Steve French790fe572007-07-07 19:25:05 +00002699 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 count = le16_to_cpu(cifs_acl->access_entry_count);
2701 size = sizeof(struct cifs_posix_acl);
2702 size += sizeof(struct cifs_posix_ace) * count;
2703/* skip past access ACEs to get to default ACEs */
2704 pACE = &cifs_acl->ace_array[count];
2705 count = le16_to_cpu(cifs_acl->default_entry_count);
2706 size += sizeof(struct cifs_posix_ace) * count;
2707 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002708 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 return -EINVAL;
2710 } else {
2711 /* illegal type */
2712 return -EINVAL;
2713 }
2714
2715 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002716 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002717 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002718 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 return -ERANGE;
2720 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002721 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002722 for (i = 0; i < count ; i++) {
2723 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2724 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 }
2726 }
2727 return size;
2728}
2729
Steve French50c2f752007-07-13 00:33:32 +00002730static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2731 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732{
2733 __u16 rc = 0; /* 0 = ACL converted ok */
2734
Steve Frenchff7feac2005-11-15 16:45:16 -08002735 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2736 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002738 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 /* Probably no need to le convert -1 on any arch but can not hurt */
2740 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002741 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002742 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002743 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 return rc;
2745}
2746
2747/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002748static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2749 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750{
2751 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002752 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2753 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 int count;
2755 int i;
2756
Steve French790fe572007-07-07 19:25:05 +00002757 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 return 0;
2759
2760 count = posix_acl_xattr_count((size_t)buflen);
Steve French63135e02007-07-17 17:34:02 +00002761 cFYI(1,("setting acl with %d entries from buf of length %d and "
2762 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002763 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002764 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002765 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002766 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 return 0;
2768 }
2769 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002770 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002771 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002772 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002773 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 else {
Steve French50c2f752007-07-13 00:33:32 +00002775 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 return 0;
2777 }
Steve French50c2f752007-07-13 00:33:32 +00002778 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2780 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002781 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 /* ACE not converted */
2783 break;
2784 }
2785 }
Steve French790fe572007-07-07 19:25:05 +00002786 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2788 rc += sizeof(struct cifs_posix_acl);
2789 /* BB add check to make sure ACL does not overflow SMB */
2790 }
2791 return rc;
2792}
2793
2794int
2795CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002796 const unsigned char *searchName,
2797 char *acl_inf, const int buflen, const int acl_type,
2798 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799{
2800/* SMB_QUERY_POSIX_ACL */
2801 TRANSACTION2_QPI_REQ *pSMB = NULL;
2802 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2803 int rc = 0;
2804 int bytes_returned;
2805 int name_len;
2806 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002807
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2809
2810queryAclRetry:
2811 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2812 (void **) &pSMBr);
2813 if (rc)
2814 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002815
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2817 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002818 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002819 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 name_len++; /* trailing null */
2821 name_len *= 2;
2822 pSMB->FileName[name_len] = 0;
2823 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002824 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 name_len = strnlen(searchName, PATH_MAX);
2826 name_len++; /* trailing null */
2827 strncpy(pSMB->FileName, searchName, name_len);
2828 }
2829
2830 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2831 pSMB->TotalDataCount = 0;
2832 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002833 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 pSMB->MaxDataCount = cpu_to_le16(4000);
2835 pSMB->MaxSetupCount = 0;
2836 pSMB->Reserved = 0;
2837 pSMB->Flags = 0;
2838 pSMB->Timeout = 0;
2839 pSMB->Reserved2 = 0;
2840 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002841 offsetof(struct smb_com_transaction2_qpi_req,
2842 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 pSMB->DataCount = 0;
2844 pSMB->DataOffset = 0;
2845 pSMB->SetupCount = 1;
2846 pSMB->Reserved3 = 0;
2847 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2848 byte_count = params + 1 /* pad */ ;
2849 pSMB->TotalParameterCount = cpu_to_le16(params);
2850 pSMB->ParameterCount = pSMB->TotalParameterCount;
2851 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2852 pSMB->Reserved4 = 0;
2853 pSMB->hdr.smb_buf_length += byte_count;
2854 pSMB->ByteCount = cpu_to_le16(byte_count);
2855
2856 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2857 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002858 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 if (rc) {
2860 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2861 } else {
2862 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002863
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2865 if (rc || (pSMBr->ByteCount < 2))
2866 /* BB also check enough total bytes returned */
2867 rc = -EIO; /* bad smb */
2868 else {
2869 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2870 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2871 rc = cifs_copy_posix_acl(acl_inf,
2872 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002873 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 }
2875 }
2876 cifs_buf_release(pSMB);
2877 if (rc == -EAGAIN)
2878 goto queryAclRetry;
2879 return rc;
2880}
2881
2882int
2883CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002884 const unsigned char *fileName,
2885 const char *local_acl, const int buflen,
2886 const int acl_type,
2887 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888{
2889 struct smb_com_transaction2_spi_req *pSMB = NULL;
2890 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2891 char *parm_data;
2892 int name_len;
2893 int rc = 0;
2894 int bytes_returned = 0;
2895 __u16 params, byte_count, data_count, param_offset, offset;
2896
2897 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2898setAclRetry:
2899 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002900 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 if (rc)
2902 return rc;
2903 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2904 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002905 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002906 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 name_len++; /* trailing null */
2908 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002909 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 name_len = strnlen(fileName, PATH_MAX);
2911 name_len++; /* trailing null */
2912 strncpy(pSMB->FileName, fileName, name_len);
2913 }
2914 params = 6 + name_len;
2915 pSMB->MaxParameterCount = cpu_to_le16(2);
2916 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2917 pSMB->MaxSetupCount = 0;
2918 pSMB->Reserved = 0;
2919 pSMB->Flags = 0;
2920 pSMB->Timeout = 0;
2921 pSMB->Reserved2 = 0;
2922 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002923 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 offset = param_offset + params;
2925 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2926 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2927
2928 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002929 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
Steve French790fe572007-07-07 19:25:05 +00002931 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 rc = -EOPNOTSUPP;
2933 goto setACLerrorExit;
2934 }
2935 pSMB->DataOffset = cpu_to_le16(offset);
2936 pSMB->SetupCount = 1;
2937 pSMB->Reserved3 = 0;
2938 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2939 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2940 byte_count = 3 /* pad */ + params + data_count;
2941 pSMB->DataCount = cpu_to_le16(data_count);
2942 pSMB->TotalDataCount = pSMB->DataCount;
2943 pSMB->ParameterCount = cpu_to_le16(params);
2944 pSMB->TotalParameterCount = pSMB->ParameterCount;
2945 pSMB->Reserved4 = 0;
2946 pSMB->hdr.smb_buf_length += byte_count;
2947 pSMB->ByteCount = cpu_to_le16(byte_count);
2948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 if (rc) {
2951 cFYI(1, ("Set POSIX ACL returned %d", rc));
2952 }
2953
2954setACLerrorExit:
2955 cifs_buf_release(pSMB);
2956 if (rc == -EAGAIN)
2957 goto setAclRetry;
2958 return rc;
2959}
2960
Steve Frenchf654bac2005-04-28 22:41:04 -07002961/* BB fix tabs in this function FIXME BB */
2962int
2963CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002964 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002965{
Steve French50c2f752007-07-13 00:33:32 +00002966 int rc = 0;
2967 struct smb_t2_qfi_req *pSMB = NULL;
2968 struct smb_t2_qfi_rsp *pSMBr = NULL;
2969 int bytes_returned;
2970 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002971
Steve French790fe572007-07-07 19:25:05 +00002972 cFYI(1, ("In GetExtAttr"));
2973 if (tcon == NULL)
2974 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002975
2976GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002977 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2978 (void **) &pSMBr);
2979 if (rc)
2980 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002981
Steve French790fe572007-07-07 19:25:05 +00002982 params = 2 /* level */ +2 /* fid */;
2983 pSMB->t2.TotalDataCount = 0;
2984 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2985 /* BB find exact max data count below from sess structure BB */
2986 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2987 pSMB->t2.MaxSetupCount = 0;
2988 pSMB->t2.Reserved = 0;
2989 pSMB->t2.Flags = 0;
2990 pSMB->t2.Timeout = 0;
2991 pSMB->t2.Reserved2 = 0;
2992 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2993 Fid) - 4);
2994 pSMB->t2.DataCount = 0;
2995 pSMB->t2.DataOffset = 0;
2996 pSMB->t2.SetupCount = 1;
2997 pSMB->t2.Reserved3 = 0;
2998 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2999 byte_count = params + 1 /* pad */ ;
3000 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3001 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3002 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3003 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003004 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003005 pSMB->hdr.smb_buf_length += byte_count;
3006 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003007
Steve French790fe572007-07-07 19:25:05 +00003008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3010 if (rc) {
3011 cFYI(1, ("error %d in GetExtAttr", rc));
3012 } else {
3013 /* decode response */
3014 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3015 if (rc || (pSMBr->ByteCount < 2))
3016 /* BB also check enough total bytes returned */
3017 /* If rc should we check for EOPNOSUPP and
3018 disable the srvino flag? or in caller? */
3019 rc = -EIO; /* bad smb */
3020 else {
3021 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3022 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3023 struct file_chattr_info *pfinfo;
3024 /* BB Do we need a cast or hash here ? */
3025 if (count != 16) {
3026 cFYI(1, ("Illegal size ret in GetExtAttr"));
3027 rc = -EIO;
3028 goto GetExtAttrOut;
3029 }
3030 pfinfo = (struct file_chattr_info *)
3031 (data_offset + (char *) &pSMBr->hdr.Protocol);
3032 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003033 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003034 }
3035 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003036GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003037 cifs_buf_release(pSMB);
3038 if (rc == -EAGAIN)
3039 goto GetExtAttrRetry;
3040 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003041}
3042
Steve Frenchf654bac2005-04-28 22:41:04 -07003043#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
Steve Frencheeac8042006-01-13 21:34:58 -08003045
3046/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01003047static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00003048 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08003049/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01003050static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00003051 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08003052
Steve French0a4b92c2006-01-12 15:44:21 -08003053/* Convert CIFS ACL to POSIX form */
Steve French50c2f752007-07-13 00:33:32 +00003054static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08003055{
Steve French0a4b92c2006-01-12 15:44:21 -08003056 return 0;
3057}
3058
3059/* Get Security Descriptor (by handle) from remote server for a file or dir */
3060int
3061CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French50c2f752007-07-13 00:33:32 +00003062 /* BB fix up return info */ char *acl_inf, const int buflen,
Steve French0a4b92c2006-01-12 15:44:21 -08003063 const int acl_type /* ACCESS/DEFAULT not sure implication */)
3064{
3065 int rc = 0;
3066 int buf_type = 0;
3067 QUERY_SEC_DESC_REQ * pSMB;
3068 struct kvec iov[1];
3069
3070 cFYI(1, ("GetCifsACL"));
3071
Steve French50c2f752007-07-13 00:33:32 +00003072 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003073 8 /* parm len */, tcon, (void **) &pSMB);
3074 if (rc)
3075 return rc;
3076
3077 pSMB->MaxParameterCount = cpu_to_le32(4);
3078 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3079 pSMB->MaxSetupCount = 0;
3080 pSMB->Fid = fid; /* file handle always le */
3081 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3082 CIFS_ACL_DACL);
3083 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3084 pSMB->hdr.smb_buf_length += 11;
3085 iov[0].iov_base = (char *)pSMB;
3086 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3087
3088 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3089 cifs_stats_inc(&tcon->num_acl_get);
3090 if (rc) {
3091 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3092 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003093 struct cifs_sid *psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003094 __le32 * parm;
3095 int parm_len;
3096 int data_len;
3097 int acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003098 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08003099
3100/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003101 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French0a4b92c2006-01-12 15:44:21 -08003102 (char **)&psec_desc,
3103 &parm_len, &data_len);
Steve French790fe572007-07-07 19:25:05 +00003104 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003105 goto qsec_out;
3106 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3107
Steve French50c2f752007-07-13 00:33:32 +00003108 cERROR(1, ("smb %p parm %p data %p",
3109 pSMBr, parm, psec_desc)); /* BB removeme BB */
Steve French0a4b92c2006-01-12 15:44:21 -08003110
3111 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3112 rc = -EIO; /* bad smb */
3113 goto qsec_out;
3114 }
3115
3116/* BB check that data area is minimum length and as big as acl_len */
3117
3118 acl_len = le32_to_cpu(*(__le32 *)parm);
Steve French790fe572007-07-07 19:25:05 +00003119 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003120
3121 parse_sec_desc(psec_desc, acl_len);
3122 }
3123qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003124 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003125 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003126 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003127 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003128/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003129 return rc;
3130}
3131
Steve French6b8edfe2005-08-23 20:26:03 -07003132/* Legacy Query Path Information call for lookup to old servers such
3133 as Win9x/WinME */
3134int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003135 const unsigned char *searchName,
3136 FILE_ALL_INFO *pFinfo,
3137 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003138{
3139 QUERY_INFORMATION_REQ * pSMB;
3140 QUERY_INFORMATION_RSP * pSMBr;
3141 int rc = 0;
3142 int bytes_returned;
3143 int name_len;
3144
Steve French50c2f752007-07-13 00:33:32 +00003145 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003146QInfRetry:
3147 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003148 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003149 if (rc)
3150 return rc;
3151
3152 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3153 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003154 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3155 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003156 name_len++; /* trailing null */
3157 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003158 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003159 name_len = strnlen(searchName, PATH_MAX);
3160 name_len++; /* trailing null */
3161 strncpy(pSMB->FileName, searchName, name_len);
3162 }
3163 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003164 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003165 pSMB->hdr.smb_buf_length += (__u16) name_len;
3166 pSMB->ByteCount = cpu_to_le16(name_len);
3167
3168 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003169 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003170 if (rc) {
3171 cFYI(1, ("Send error in QueryInfo = %d", rc));
3172 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003173 struct timespec ts;
3174 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3175 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003176 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003177 ts.tv_nsec = 0;
3178 ts.tv_sec = time;
3179 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003180 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003181 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3182 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003183 pFinfo->AllocationSize =
3184 cpu_to_le64(le32_to_cpu(pSMBr->size));
3185 pFinfo->EndOfFile = pFinfo->AllocationSize;
3186 pFinfo->Attributes =
3187 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003188 } else
3189 rc = -EIO; /* bad buffer passed in */
3190
3191 cifs_buf_release(pSMB);
3192
3193 if (rc == -EAGAIN)
3194 goto QInfRetry;
3195
3196 return rc;
3197}
3198
3199
3200
3201
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202int
3203CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3204 const unsigned char *searchName,
3205 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003206 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003207 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208{
3209/* level 263 SMB_QUERY_FILE_ALL_INFO */
3210 TRANSACTION2_QPI_REQ *pSMB = NULL;
3211 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3212 int rc = 0;
3213 int bytes_returned;
3214 int name_len;
3215 __u16 params, byte_count;
3216
3217/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3218QPathInfoRetry:
3219 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3220 (void **) &pSMBr);
3221 if (rc)
3222 return rc;
3223
3224 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3225 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003226 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003227 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 name_len++; /* trailing null */
3229 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003230 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 name_len = strnlen(searchName, PATH_MAX);
3232 name_len++; /* trailing null */
3233 strncpy(pSMB->FileName, searchName, name_len);
3234 }
3235
Steve French50c2f752007-07-13 00:33:32 +00003236 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 pSMB->TotalDataCount = 0;
3238 pSMB->MaxParameterCount = cpu_to_le16(2);
3239 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3240 pSMB->MaxSetupCount = 0;
3241 pSMB->Reserved = 0;
3242 pSMB->Flags = 0;
3243 pSMB->Timeout = 0;
3244 pSMB->Reserved2 = 0;
3245 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003246 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 pSMB->DataCount = 0;
3248 pSMB->DataOffset = 0;
3249 pSMB->SetupCount = 1;
3250 pSMB->Reserved3 = 0;
3251 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3252 byte_count = params + 1 /* pad */ ;
3253 pSMB->TotalParameterCount = cpu_to_le16(params);
3254 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003255 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003256 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3257 else
3258 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 pSMB->Reserved4 = 0;
3260 pSMB->hdr.smb_buf_length += byte_count;
3261 pSMB->ByteCount = cpu_to_le16(byte_count);
3262
3263 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3264 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3265 if (rc) {
3266 cFYI(1, ("Send error in QPathInfo = %d", rc));
3267 } else { /* decode response */
3268 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3269
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003270 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3271 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003272 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003274 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003275 rc = -EIO; /* 24 or 26 expected but we do not read
3276 last field */
3277 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003278 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003280 if (legacy) /* we do not read the last field, EAsize,
3281 fortunately since it varies by subdialect
3282 and on Set vs. Get, is two bytes or 4
3283 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003284 size = sizeof(FILE_INFO_STANDARD);
3285 else
3286 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 memcpy((char *) pFindData,
3288 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003289 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 } else
3291 rc = -ENOMEM;
3292 }
3293 cifs_buf_release(pSMB);
3294 if (rc == -EAGAIN)
3295 goto QPathInfoRetry;
3296
3297 return rc;
3298}
3299
3300int
3301CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3302 const unsigned char *searchName,
3303 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003304 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305{
3306/* SMB_QUERY_FILE_UNIX_BASIC */
3307 TRANSACTION2_QPI_REQ *pSMB = NULL;
3308 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3309 int rc = 0;
3310 int bytes_returned = 0;
3311 int name_len;
3312 __u16 params, byte_count;
3313
3314 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3315UnixQPathInfoRetry:
3316 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3317 (void **) &pSMBr);
3318 if (rc)
3319 return rc;
3320
3321 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3322 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003323 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003324 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 name_len++; /* trailing null */
3326 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003327 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 name_len = strnlen(searchName, PATH_MAX);
3329 name_len++; /* trailing null */
3330 strncpy(pSMB->FileName, searchName, name_len);
3331 }
3332
Steve French50c2f752007-07-13 00:33:32 +00003333 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 pSMB->TotalDataCount = 0;
3335 pSMB->MaxParameterCount = cpu_to_le16(2);
3336 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003337 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 pSMB->MaxSetupCount = 0;
3339 pSMB->Reserved = 0;
3340 pSMB->Flags = 0;
3341 pSMB->Timeout = 0;
3342 pSMB->Reserved2 = 0;
3343 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003344 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 pSMB->DataCount = 0;
3346 pSMB->DataOffset = 0;
3347 pSMB->SetupCount = 1;
3348 pSMB->Reserved3 = 0;
3349 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3350 byte_count = params + 1 /* pad */ ;
3351 pSMB->TotalParameterCount = cpu_to_le16(params);
3352 pSMB->ParameterCount = pSMB->TotalParameterCount;
3353 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3354 pSMB->Reserved4 = 0;
3355 pSMB->hdr.smb_buf_length += byte_count;
3356 pSMB->ByteCount = cpu_to_le16(byte_count);
3357
3358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3360 if (rc) {
3361 cFYI(1, ("Send error in QPathInfo = %d", rc));
3362 } else { /* decode response */
3363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3364
3365 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3366 rc = -EIO; /* bad smb */
3367 } else {
3368 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3369 memcpy((char *) pFindData,
3370 (char *) &pSMBr->hdr.Protocol +
3371 data_offset,
3372 sizeof (FILE_UNIX_BASIC_INFO));
3373 }
3374 }
3375 cifs_buf_release(pSMB);
3376 if (rc == -EAGAIN)
3377 goto UnixQPathInfoRetry;
3378
3379 return rc;
3380}
3381
3382#if 0 /* function unused at present */
3383int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3384 const char *searchName, FILE_ALL_INFO * findData,
3385 const struct nls_table *nls_codepage)
3386{
3387/* level 257 SMB_ */
3388 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3389 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3390 int rc = 0;
3391 int bytes_returned;
3392 int name_len;
3393 __u16 params, byte_count;
3394
3395 cFYI(1, ("In FindUnique"));
3396findUniqueRetry:
3397 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3398 (void **) &pSMBr);
3399 if (rc)
3400 return rc;
3401
3402 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3403 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003404 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3405 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 name_len++; /* trailing null */
3407 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003408 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 name_len = strnlen(searchName, PATH_MAX);
3410 name_len++; /* trailing null */
3411 strncpy(pSMB->FileName, searchName, name_len);
3412 }
3413
3414 params = 12 + name_len /* includes null */ ;
3415 pSMB->TotalDataCount = 0; /* no EAs */
3416 pSMB->MaxParameterCount = cpu_to_le16(2);
3417 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3418 pSMB->MaxSetupCount = 0;
3419 pSMB->Reserved = 0;
3420 pSMB->Flags = 0;
3421 pSMB->Timeout = 0;
3422 pSMB->Reserved2 = 0;
3423 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003424 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 pSMB->DataCount = 0;
3426 pSMB->DataOffset = 0;
3427 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3428 pSMB->Reserved3 = 0;
3429 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3430 byte_count = params + 1 /* pad */ ;
3431 pSMB->TotalParameterCount = cpu_to_le16(params);
3432 pSMB->ParameterCount = pSMB->TotalParameterCount;
3433 pSMB->SearchAttributes =
3434 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3435 ATTR_DIRECTORY);
3436 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3437 pSMB->SearchFlags = cpu_to_le16(1);
3438 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3439 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3440 pSMB->hdr.smb_buf_length += byte_count;
3441 pSMB->ByteCount = cpu_to_le16(byte_count);
3442
3443 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3444 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3445
3446 if (rc) {
3447 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3448 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003449 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 /* BB fill in */
3451 }
3452
3453 cifs_buf_release(pSMB);
3454 if (rc == -EAGAIN)
3455 goto findUniqueRetry;
3456
3457 return rc;
3458}
3459#endif /* end unused (temporarily) function */
3460
3461/* xid, tcon, searchName and codepage are input parms, rest are returned */
3462int
3463CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003464 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003466 __u16 *pnetfid,
3467 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468{
3469/* level 257 SMB_ */
3470 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3471 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3472 T2_FFIRST_RSP_PARMS * parms;
3473 int rc = 0;
3474 int bytes_returned = 0;
3475 int name_len;
3476 __u16 params, byte_count;
3477
Steve French50c2f752007-07-13 00:33:32 +00003478 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479
3480findFirstRetry:
3481 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3482 (void **) &pSMBr);
3483 if (rc)
3484 return rc;
3485
3486 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3487 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003488 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003489 PATH_MAX, nls_codepage, remap);
3490 /* We can not add the asterik earlier in case
3491 it got remapped to 0xF03A as if it were part of the
3492 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003494 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003495 pSMB->FileName[name_len+1] = 0;
3496 pSMB->FileName[name_len+2] = '*';
3497 pSMB->FileName[name_len+3] = 0;
3498 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3500 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003501 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 } else { /* BB add check for overrun of SMB buf BB */
3503 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003505 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 free buffer exit; BB */
3507 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003508 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003509 pSMB->FileName[name_len+1] = '*';
3510 pSMB->FileName[name_len+2] = 0;
3511 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 }
3513
3514 params = 12 + name_len /* includes null */ ;
3515 pSMB->TotalDataCount = 0; /* no EAs */
3516 pSMB->MaxParameterCount = cpu_to_le16(10);
3517 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3518 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3519 pSMB->MaxSetupCount = 0;
3520 pSMB->Reserved = 0;
3521 pSMB->Flags = 0;
3522 pSMB->Timeout = 0;
3523 pSMB->Reserved2 = 0;
3524 byte_count = params + 1 /* pad */ ;
3525 pSMB->TotalParameterCount = cpu_to_le16(params);
3526 pSMB->ParameterCount = pSMB->TotalParameterCount;
3527 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003528 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3529 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 pSMB->DataCount = 0;
3531 pSMB->DataOffset = 0;
3532 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3533 pSMB->Reserved3 = 0;
3534 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3535 pSMB->SearchAttributes =
3536 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3537 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003538 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3539 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 CIFS_SEARCH_RETURN_RESUME);
3541 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3542
3543 /* BB what should we set StorageType to? Does it matter? BB */
3544 pSMB->SearchStorageType = 0;
3545 pSMB->hdr.smb_buf_length += byte_count;
3546 pSMB->ByteCount = cpu_to_le16(byte_count);
3547
3548 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3549 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003550 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551
Steve French88274812006-03-09 22:21:45 +00003552 if (rc) {/* BB add logic to retry regular search if Unix search
3553 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 /* BB Add code to handle unsupported level rc */
3555 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003556
Steve French88274812006-03-09 22:21:45 +00003557 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
3559 /* BB eventually could optimize out free and realloc of buf */
3560 /* for this case */
3561 if (rc == -EAGAIN)
3562 goto findFirstRetry;
3563 } else { /* decode response */
3564 /* BB remember to free buffer if error BB */
3565 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003566 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3568 psrch_inf->unicode = TRUE;
3569 else
3570 psrch_inf->unicode = FALSE;
3571
3572 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003573 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003574 psrch_inf->srch_entries_start =
3575 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3578 le16_to_cpu(pSMBr->t2.ParameterOffset));
3579
Steve French790fe572007-07-07 19:25:05 +00003580 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 psrch_inf->endOfSearch = TRUE;
3582 else
3583 psrch_inf->endOfSearch = FALSE;
3584
Steve French50c2f752007-07-13 00:33:32 +00003585 psrch_inf->entries_in_buffer =
3586 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003587 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 *pnetfid = parms->SearchHandle;
3590 } else {
3591 cifs_buf_release(pSMB);
3592 }
3593 }
3594
3595 return rc;
3596}
3597
3598int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003599 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600{
3601 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3602 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3603 T2_FNEXT_RSP_PARMS * parms;
3604 char *response_data;
3605 int rc = 0;
3606 int bytes_returned, name_len;
3607 __u16 params, byte_count;
3608
3609 cFYI(1, ("In FindNext"));
3610
Steve French790fe572007-07-07 19:25:05 +00003611 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 return -ENOENT;
3613
3614 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3615 (void **) &pSMBr);
3616 if (rc)
3617 return rc;
3618
Steve French50c2f752007-07-13 00:33:32 +00003619 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 byte_count = 0;
3621 pSMB->TotalDataCount = 0; /* no EAs */
3622 pSMB->MaxParameterCount = cpu_to_le16(8);
3623 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003624 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3625 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 pSMB->MaxSetupCount = 0;
3627 pSMB->Reserved = 0;
3628 pSMB->Flags = 0;
3629 pSMB->Timeout = 0;
3630 pSMB->Reserved2 = 0;
3631 pSMB->ParameterOffset = cpu_to_le16(
3632 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3633 pSMB->DataCount = 0;
3634 pSMB->DataOffset = 0;
3635 pSMB->SetupCount = 1;
3636 pSMB->Reserved3 = 0;
3637 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3638 pSMB->SearchHandle = searchHandle; /* always kept as le */
3639 pSMB->SearchCount =
3640 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3641 /* test for Unix extensions */
3642/* if (tcon->ses->capabilities & CAP_UNIX) {
3643 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3644 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3645 } else {
3646 pSMB->InformationLevel =
3647 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3648 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3649 } */
3650 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3651 pSMB->ResumeKey = psrch_inf->resume_key;
3652 pSMB->SearchFlags =
3653 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3654
3655 name_len = psrch_inf->resume_name_len;
3656 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003657 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3659 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003660 /* 14 byte parm len above enough for 2 byte null terminator */
3661 pSMB->ResumeFileName[name_len] = 0;
3662 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 } else {
3664 rc = -EINVAL;
3665 goto FNext2_err_exit;
3666 }
3667 byte_count = params + 1 /* pad */ ;
3668 pSMB->TotalParameterCount = cpu_to_le16(params);
3669 pSMB->ParameterCount = pSMB->TotalParameterCount;
3670 pSMB->hdr.smb_buf_length += byte_count;
3671 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003672
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3674 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003675 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 if (rc) {
3677 if (rc == -EBADF) {
3678 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003679 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 } else
3681 cFYI(1, ("FindNext returned = %d", rc));
3682 } else { /* decode response */
3683 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003684
Steve French790fe572007-07-07 19:25:05 +00003685 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 /* BB fixme add lock for file (srch_info) struct here */
3687 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3688 psrch_inf->unicode = TRUE;
3689 else
3690 psrch_inf->unicode = FALSE;
3691 response_data = (char *) &pSMBr->hdr.Protocol +
3692 le16_to_cpu(pSMBr->t2.ParameterOffset);
3693 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3694 response_data = (char *)&pSMBr->hdr.Protocol +
3695 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003696 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003697 cifs_small_buf_release(
3698 psrch_inf->ntwrk_buf_start);
3699 else
3700 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 psrch_inf->srch_entries_start = response_data;
3702 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003703 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003704 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 psrch_inf->endOfSearch = TRUE;
3706 else
3707 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003708 psrch_inf->entries_in_buffer =
3709 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 psrch_inf->index_of_last_entry +=
3711 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003712/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3713 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714
3715 /* BB fixme add unlock here */
3716 }
3717
3718 }
3719
3720 /* BB On error, should we leave previous search buf (and count and
3721 last entry fields) intact or free the previous one? */
3722
3723 /* Note: On -EAGAIN error only caller can retry on handle based calls
3724 since file handle passed in no longer valid */
3725FNext2_err_exit:
3726 if (rc != 0)
3727 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 return rc;
3729}
3730
3731int
Steve French50c2f752007-07-13 00:33:32 +00003732CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3733 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734{
3735 int rc = 0;
3736 FINDCLOSE_REQ *pSMB = NULL;
3737 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3738 int bytes_returned;
3739
3740 cFYI(1, ("In CIFSSMBFindClose"));
3741 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3742
3743 /* no sense returning error if session restarted
3744 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003745 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 return 0;
3747 if (rc)
3748 return rc;
3749
3750 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3751 pSMB->FileID = searchHandle;
3752 pSMB->ByteCount = 0;
3753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3754 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3755 if (rc) {
3756 cERROR(1, ("Send error in FindClose = %d", rc));
3757 }
Steve Frencha4544342005-08-24 13:59:35 -07003758 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 cifs_small_buf_release(pSMB);
3760
3761 /* Since session is dead, search handle closed on server already */
3762 if (rc == -EAGAIN)
3763 rc = 0;
3764
3765 return rc;
3766}
3767
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768int
3769CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003770 const unsigned char *searchName,
3771 __u64 * inode_number,
3772 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773{
3774 int rc = 0;
3775 TRANSACTION2_QPI_REQ *pSMB = NULL;
3776 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3777 int name_len, bytes_returned;
3778 __u16 params, byte_count;
3779
Steve French50c2f752007-07-13 00:33:32 +00003780 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003781 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003782 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
3784GetInodeNumberRetry:
3785 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003786 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 if (rc)
3788 return rc;
3789
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3791 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003792 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003793 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 name_len++; /* trailing null */
3795 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003796 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 name_len = strnlen(searchName, PATH_MAX);
3798 name_len++; /* trailing null */
3799 strncpy(pSMB->FileName, searchName, name_len);
3800 }
3801
3802 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3803 pSMB->TotalDataCount = 0;
3804 pSMB->MaxParameterCount = cpu_to_le16(2);
3805 /* BB find exact max data count below from sess structure BB */
3806 pSMB->MaxDataCount = cpu_to_le16(4000);
3807 pSMB->MaxSetupCount = 0;
3808 pSMB->Reserved = 0;
3809 pSMB->Flags = 0;
3810 pSMB->Timeout = 0;
3811 pSMB->Reserved2 = 0;
3812 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003813 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 pSMB->DataCount = 0;
3815 pSMB->DataOffset = 0;
3816 pSMB->SetupCount = 1;
3817 pSMB->Reserved3 = 0;
3818 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3819 byte_count = params + 1 /* pad */ ;
3820 pSMB->TotalParameterCount = cpu_to_le16(params);
3821 pSMB->ParameterCount = pSMB->TotalParameterCount;
3822 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3823 pSMB->Reserved4 = 0;
3824 pSMB->hdr.smb_buf_length += byte_count;
3825 pSMB->ByteCount = cpu_to_le16(byte_count);
3826
3827 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3828 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3829 if (rc) {
3830 cFYI(1, ("error %d in QueryInternalInfo", rc));
3831 } else {
3832 /* decode response */
3833 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3834 if (rc || (pSMBr->ByteCount < 2))
3835 /* BB also check enough total bytes returned */
3836 /* If rc should we check for EOPNOSUPP and
3837 disable the srvino flag? or in caller? */
3838 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003839 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3841 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003842 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003844 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3846 rc = -EIO;
3847 goto GetInodeNumOut;
3848 }
3849 pfinfo = (struct file_internal_info *)
3850 (data_offset + (char *) &pSMBr->hdr.Protocol);
3851 *inode_number = pfinfo->UniqueId;
3852 }
3853 }
3854GetInodeNumOut:
3855 cifs_buf_release(pSMB);
3856 if (rc == -EAGAIN)
3857 goto GetInodeNumberRetry;
3858 return rc;
3859}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860
3861int
3862CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3863 const unsigned char *searchName,
3864 unsigned char **targetUNCs,
3865 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003866 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867{
3868/* TRANS2_GET_DFS_REFERRAL */
3869 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3870 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003871 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 int rc = 0;
3873 int bytes_returned;
3874 int name_len;
3875 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003876 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 __u16 params, byte_count;
3878 *number_of_UNC_in_array = 0;
3879 *targetUNCs = NULL;
3880
3881 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3882 if (ses == NULL)
3883 return -ENODEV;
3884getDFSRetry:
3885 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3886 (void **) &pSMBr);
3887 if (rc)
3888 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003889
3890 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003891 but should never be null here anyway */
3892 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 pSMB->hdr.Tid = ses->ipc_tid;
3894 pSMB->hdr.Uid = ses->Suid;
3895 if (ses->capabilities & CAP_STATUS32) {
3896 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3897 }
3898 if (ses->capabilities & CAP_DFS) {
3899 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3900 }
3901
3902 if (ses->capabilities & CAP_UNICODE) {
3903 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3904 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003905 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003906 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 name_len++; /* trailing null */
3908 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003909 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 name_len = strnlen(searchName, PATH_MAX);
3911 name_len++; /* trailing null */
3912 strncpy(pSMB->RequestFileName, searchName, name_len);
3913 }
3914
Steve French790fe572007-07-07 19:25:05 +00003915 if (ses->server) {
3916 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003917 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3918 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3919 }
3920
Steve French50c2f752007-07-13 00:33:32 +00003921 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003922
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 params = 2 /* level */ + name_len /*includes null */ ;
3924 pSMB->TotalDataCount = 0;
3925 pSMB->DataCount = 0;
3926 pSMB->DataOffset = 0;
3927 pSMB->MaxParameterCount = 0;
3928 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3929 pSMB->MaxSetupCount = 0;
3930 pSMB->Reserved = 0;
3931 pSMB->Flags = 0;
3932 pSMB->Timeout = 0;
3933 pSMB->Reserved2 = 0;
3934 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003935 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 pSMB->SetupCount = 1;
3937 pSMB->Reserved3 = 0;
3938 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3939 byte_count = params + 3 /* pad */ ;
3940 pSMB->ParameterCount = cpu_to_le16(params);
3941 pSMB->TotalParameterCount = pSMB->ParameterCount;
3942 pSMB->MaxReferralLevel = cpu_to_le16(3);
3943 pSMB->hdr.smb_buf_length += byte_count;
3944 pSMB->ByteCount = cpu_to_le16(byte_count);
3945
3946 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3948 if (rc) {
3949 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3950 } else { /* decode response */
3951/* BB Add logic to parse referrals here */
3952 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3953
Steve French50c2f752007-07-13 00:33:32 +00003954 /* BB Also check if enough total bytes returned? */
3955 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 rc = -EIO; /* bad smb */
3957 else {
Steve French50c2f752007-07-13 00:33:32 +00003958 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3960
3961 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003962 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003964 referrals =
3965 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 (8 /* sizeof start of data block */ +
3967 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003968 (char *) &pSMBr->hdr.Protocol);
Steve French63135e02007-07-17 17:34:02 +00003969 cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \n"
3970 "for referral one refer size: 0x%x srv "
3971 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003972 le16_to_cpu(pSMBr->NumberOfReferrals),
3973 le16_to_cpu(pSMBr->DFSFlags),
3974 le16_to_cpu(referrals->ReferralSize),
3975 le16_to_cpu(referrals->ServerType),
3976 le16_to_cpu(referrals->ReferralFlags),
3977 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 /* BB This field is actually two bytes in from start of
3979 data block so we could do safety check that DataBlock
3980 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003981 *number_of_UNC_in_array =
3982 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
3984 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003985 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 *number_of_UNC_in_array = 1;
3987
3988 /* get the length of the strings describing refs */
3989 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003990 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003992 __u16 offset =
3993 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003995 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 not try to copy any more */
3997 *number_of_UNC_in_array = i;
3998 break;
Steve French50c2f752007-07-13 00:33:32 +00003999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 temp = ((char *)referrals) + offset;
4001
4002 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004003 name_len += UniStrnlen((wchar_t *)temp,
4004 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 } else {
Steve French50c2f752007-07-13 00:33:32 +00004006 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 }
4008 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004009 /* BB add check that referral pointer does
4010 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 }
4012 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004013 *targetUNCs =
4014 kmalloc(name_len+1+(*number_of_UNC_in_array),
4015 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004016 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 rc = -ENOMEM;
4018 goto GetDFSRefExit;
4019 }
4020 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004021 referrals = (struct dfs_referral_level_3 *)
4022 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 (char *) &pSMBr->hdr.Protocol);
4024
Steve French50c2f752007-07-13 00:33:32 +00004025 for (i = 0; i < *number_of_UNC_in_array; i++) {
4026 temp = ((char *)referrals) +
4027 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4029 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004030 (__le16 *) temp,
4031 name_len,
4032 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 } else {
Steve French50c2f752007-07-13 00:33:32 +00004034 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 }
4036 /* BB update target_uncs pointers */
4037 referrals++;
4038 }
4039 temp = *targetUNCs;
4040 temp[name_len] = 0;
4041 }
4042
4043 }
4044GetDFSRefExit:
4045 if (pSMB)
4046 cifs_buf_release(pSMB);
4047
4048 if (rc == -EAGAIN)
4049 goto getDFSRetry;
4050
4051 return rc;
4052}
4053
Steve French20962432005-09-21 22:05:57 -07004054/* Query File System Info such as free space to old servers such as Win 9x */
4055int
4056SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4057{
4058/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4059 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4060 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4061 FILE_SYSTEM_ALLOC_INFO *response_data;
4062 int rc = 0;
4063 int bytes_returned = 0;
4064 __u16 params, byte_count;
4065
4066 cFYI(1, ("OldQFSInfo"));
4067oldQFSInfoRetry:
4068 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4069 (void **) &pSMBr);
4070 if (rc)
4071 return rc;
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);
4080 pSMB->MaxDataCount = cpu_to_le16(1000);
4081 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(
4090 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4091 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_INFO_ALLOCATION);
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) {
4103 cFYI(1, ("Send error in QFSInfo = %d", rc));
4104 } else { /* decode response */
4105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4106
4107 if (rc || (pSMBr->ByteCount < 18))
4108 rc = -EIO; /* bad smb */
4109 else {
4110 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004111 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004112 pSMBr->ByteCount, data_offset));
4113
Steve French50c2f752007-07-13 00:33:32 +00004114 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004115 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4116 FSData->f_bsize =
4117 le16_to_cpu(response_data->BytesPerSector) *
4118 le32_to_cpu(response_data->
4119 SectorsPerAllocationUnit);
4120 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004121 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004122 FSData->f_bfree = FSData->f_bavail =
4123 le32_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 oldQFSInfoRetry;
4135
4136 return rc;
4137}
4138
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139int
Steve French737b7582005-04-28 22:41:06 -07004140CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141{
4142/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4143 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4144 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4145 FILE_SYSTEM_INFO *response_data;
4146 int rc = 0;
4147 int bytes_returned = 0;
4148 __u16 params, byte_count;
4149
4150 cFYI(1, ("In QFSInfo"));
4151QFSInfoRetry:
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);
Steve French20962432005-09-21 22:05:57 -07004160 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 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_SIZE_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) {
Steve French20962432005-09-21 22:05:57 -07004183 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004185 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
Steve French20962432005-09-21 22:05:57 -07004187 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 rc = -EIO; /* bad smb */
4189 else {
4190 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191
4192 response_data =
4193 (FILE_SYSTEM_INFO
4194 *) (((char *) &pSMBr->hdr.Protocol) +
4195 data_offset);
4196 FSData->f_bsize =
4197 le32_to_cpu(response_data->BytesPerSector) *
4198 le32_to_cpu(response_data->
4199 SectorsPerAllocationUnit);
4200 FSData->f_blocks =
4201 le64_to_cpu(response_data->TotalAllocationUnits);
4202 FSData->f_bfree = FSData->f_bavail =
4203 le64_to_cpu(response_data->FreeAllocationUnits);
4204 cFYI(1,
4205 ("Blocks: %lld Free: %lld Block size %ld",
4206 (unsigned long long)FSData->f_blocks,
4207 (unsigned long long)FSData->f_bfree,
4208 FSData->f_bsize));
4209 }
4210 }
4211 cifs_buf_release(pSMB);
4212
4213 if (rc == -EAGAIN)
4214 goto QFSInfoRetry;
4215
4216 return rc;
4217}
4218
4219int
Steve French737b7582005-04-28 22:41:06 -07004220CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221{
4222/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4223 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4224 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4225 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4226 int rc = 0;
4227 int bytes_returned = 0;
4228 __u16 params, byte_count;
4229
4230 cFYI(1, ("In QFSAttributeInfo"));
4231QFSAttributeRetry:
4232 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4233 (void **) &pSMBr);
4234 if (rc)
4235 return rc;
4236
4237 params = 2; /* level */
4238 pSMB->TotalDataCount = 0;
4239 pSMB->MaxParameterCount = cpu_to_le16(2);
4240 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4241 pSMB->MaxSetupCount = 0;
4242 pSMB->Reserved = 0;
4243 pSMB->Flags = 0;
4244 pSMB->Timeout = 0;
4245 pSMB->Reserved2 = 0;
4246 byte_count = params + 1 /* pad */ ;
4247 pSMB->TotalParameterCount = cpu_to_le16(params);
4248 pSMB->ParameterCount = pSMB->TotalParameterCount;
4249 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004250 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 pSMB->DataCount = 0;
4252 pSMB->DataOffset = 0;
4253 pSMB->SetupCount = 1;
4254 pSMB->Reserved3 = 0;
4255 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4256 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4257 pSMB->hdr.smb_buf_length += byte_count;
4258 pSMB->ByteCount = cpu_to_le16(byte_count);
4259
4260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4261 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4262 if (rc) {
4263 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4264 } else { /* decode response */
4265 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4266
Steve French50c2f752007-07-13 00:33:32 +00004267 if (rc || (pSMBr->ByteCount < 13)) {
4268 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 rc = -EIO; /* bad smb */
4270 } else {
4271 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4272 response_data =
4273 (FILE_SYSTEM_ATTRIBUTE_INFO
4274 *) (((char *) &pSMBr->hdr.Protocol) +
4275 data_offset);
4276 memcpy(&tcon->fsAttrInfo, response_data,
4277 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4278 }
4279 }
4280 cifs_buf_release(pSMB);
4281
4282 if (rc == -EAGAIN)
4283 goto QFSAttributeRetry;
4284
4285 return rc;
4286}
4287
4288int
Steve French737b7582005-04-28 22:41:06 -07004289CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290{
4291/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4292 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4293 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4294 FILE_SYSTEM_DEVICE_INFO *response_data;
4295 int rc = 0;
4296 int bytes_returned = 0;
4297 __u16 params, byte_count;
4298
4299 cFYI(1, ("In QFSDeviceInfo"));
4300QFSDeviceRetry:
4301 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4302 (void **) &pSMBr);
4303 if (rc)
4304 return rc;
4305
4306 params = 2; /* level */
4307 pSMB->TotalDataCount = 0;
4308 pSMB->MaxParameterCount = cpu_to_le16(2);
4309 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4310 pSMB->MaxSetupCount = 0;
4311 pSMB->Reserved = 0;
4312 pSMB->Flags = 0;
4313 pSMB->Timeout = 0;
4314 pSMB->Reserved2 = 0;
4315 byte_count = params + 1 /* pad */ ;
4316 pSMB->TotalParameterCount = cpu_to_le16(params);
4317 pSMB->ParameterCount = pSMB->TotalParameterCount;
4318 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004319 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
4321 pSMB->DataCount = 0;
4322 pSMB->DataOffset = 0;
4323 pSMB->SetupCount = 1;
4324 pSMB->Reserved3 = 0;
4325 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4326 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4327 pSMB->hdr.smb_buf_length += byte_count;
4328 pSMB->ByteCount = cpu_to_le16(byte_count);
4329
4330 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4331 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4332 if (rc) {
4333 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4334 } else { /* decode response */
4335 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4336
4337 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4338 rc = -EIO; /* bad smb */
4339 else {
4340 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4341 response_data =
Steve French737b7582005-04-28 22:41:06 -07004342 (FILE_SYSTEM_DEVICE_INFO *)
4343 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 data_offset);
4345 memcpy(&tcon->fsDevInfo, response_data,
4346 sizeof (FILE_SYSTEM_DEVICE_INFO));
4347 }
4348 }
4349 cifs_buf_release(pSMB);
4350
4351 if (rc == -EAGAIN)
4352 goto QFSDeviceRetry;
4353
4354 return rc;
4355}
4356
4357int
Steve French737b7582005-04-28 22:41:06 -07004358CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359{
4360/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4361 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4362 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4363 FILE_SYSTEM_UNIX_INFO *response_data;
4364 int rc = 0;
4365 int bytes_returned = 0;
4366 __u16 params, byte_count;
4367
4368 cFYI(1, ("In QFSUnixInfo"));
4369QFSUnixRetry:
4370 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4371 (void **) &pSMBr);
4372 if (rc)
4373 return rc;
4374
4375 params = 2; /* level */
4376 pSMB->TotalDataCount = 0;
4377 pSMB->DataCount = 0;
4378 pSMB->DataOffset = 0;
4379 pSMB->MaxParameterCount = cpu_to_le16(2);
4380 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4381 pSMB->MaxSetupCount = 0;
4382 pSMB->Reserved = 0;
4383 pSMB->Flags = 0;
4384 pSMB->Timeout = 0;
4385 pSMB->Reserved2 = 0;
4386 byte_count = params + 1 /* pad */ ;
4387 pSMB->ParameterCount = cpu_to_le16(params);
4388 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004389 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4390 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 pSMB->SetupCount = 1;
4392 pSMB->Reserved3 = 0;
4393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4394 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4395 pSMB->hdr.smb_buf_length += byte_count;
4396 pSMB->ByteCount = cpu_to_le16(byte_count);
4397
4398 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4399 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4400 if (rc) {
4401 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4402 } else { /* decode response */
4403 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4404
4405 if (rc || (pSMBr->ByteCount < 13)) {
4406 rc = -EIO; /* bad smb */
4407 } else {
4408 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4409 response_data =
4410 (FILE_SYSTEM_UNIX_INFO
4411 *) (((char *) &pSMBr->hdr.Protocol) +
4412 data_offset);
4413 memcpy(&tcon->fsUnixInfo, response_data,
4414 sizeof (FILE_SYSTEM_UNIX_INFO));
4415 }
4416 }
4417 cifs_buf_release(pSMB);
4418
4419 if (rc == -EAGAIN)
4420 goto QFSUnixRetry;
4421
4422
4423 return rc;
4424}
4425
Jeremy Allisonac670552005-06-22 17:26:35 -07004426int
Steve French45abc6e2005-06-23 13:42:03 -05004427CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004428{
4429/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4430 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4431 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4432 int rc = 0;
4433 int bytes_returned = 0;
4434 __u16 params, param_offset, offset, byte_count;
4435
4436 cFYI(1, ("In SETFSUnixInfo"));
4437SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004438 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004439 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4440 (void **) &pSMBr);
4441 if (rc)
4442 return rc;
4443
4444 params = 4; /* 2 bytes zero followed by info level. */
4445 pSMB->MaxSetupCount = 0;
4446 pSMB->Reserved = 0;
4447 pSMB->Flags = 0;
4448 pSMB->Timeout = 0;
4449 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004450 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4451 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004452 offset = param_offset + params;
4453
4454 pSMB->MaxParameterCount = cpu_to_le16(4);
4455 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4456 pSMB->SetupCount = 1;
4457 pSMB->Reserved3 = 0;
4458 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4459 byte_count = 1 /* pad */ + params + 12;
4460
4461 pSMB->DataCount = cpu_to_le16(12);
4462 pSMB->ParameterCount = cpu_to_le16(params);
4463 pSMB->TotalDataCount = pSMB->DataCount;
4464 pSMB->TotalParameterCount = pSMB->ParameterCount;
4465 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4466 pSMB->DataOffset = cpu_to_le16(offset);
4467
4468 /* Params. */
4469 pSMB->FileNum = 0;
4470 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4471
4472 /* Data. */
4473 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4474 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4475 pSMB->ClientUnixCap = cpu_to_le64(cap);
4476
4477 pSMB->hdr.smb_buf_length += byte_count;
4478 pSMB->ByteCount = cpu_to_le16(byte_count);
4479
4480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4482 if (rc) {
4483 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4484 } else { /* decode response */
4485 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4486 if (rc) {
4487 rc = -EIO; /* bad smb */
4488 }
4489 }
4490 cifs_buf_release(pSMB);
4491
4492 if (rc == -EAGAIN)
4493 goto SETFSUnixRetry;
4494
4495 return rc;
4496}
4497
4498
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499
4500int
4501CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004502 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503{
4504/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4505 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4506 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4507 FILE_SYSTEM_POSIX_INFO *response_data;
4508 int rc = 0;
4509 int bytes_returned = 0;
4510 __u16 params, byte_count;
4511
4512 cFYI(1, ("In QFSPosixInfo"));
4513QFSPosixRetry:
4514 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4515 (void **) &pSMBr);
4516 if (rc)
4517 return rc;
4518
4519 params = 2; /* level */
4520 pSMB->TotalDataCount = 0;
4521 pSMB->DataCount = 0;
4522 pSMB->DataOffset = 0;
4523 pSMB->MaxParameterCount = cpu_to_le16(2);
4524 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4525 pSMB->MaxSetupCount = 0;
4526 pSMB->Reserved = 0;
4527 pSMB->Flags = 0;
4528 pSMB->Timeout = 0;
4529 pSMB->Reserved2 = 0;
4530 byte_count = params + 1 /* pad */ ;
4531 pSMB->ParameterCount = cpu_to_le16(params);
4532 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004533 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4534 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 pSMB->SetupCount = 1;
4536 pSMB->Reserved3 = 0;
4537 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4538 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4539 pSMB->hdr.smb_buf_length += byte_count;
4540 pSMB->ByteCount = cpu_to_le16(byte_count);
4541
4542 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4543 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4544 if (rc) {
4545 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4546 } else { /* decode response */
4547 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4548
4549 if (rc || (pSMBr->ByteCount < 13)) {
4550 rc = -EIO; /* bad smb */
4551 } else {
4552 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4553 response_data =
4554 (FILE_SYSTEM_POSIX_INFO
4555 *) (((char *) &pSMBr->hdr.Protocol) +
4556 data_offset);
4557 FSData->f_bsize =
4558 le32_to_cpu(response_data->BlockSize);
4559 FSData->f_blocks =
4560 le64_to_cpu(response_data->TotalBlocks);
4561 FSData->f_bfree =
4562 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004563 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 FSData->f_bavail = FSData->f_bfree;
4565 } else {
4566 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004567 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 }
Steve French790fe572007-07-07 19:25:05 +00004569 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004571 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004572 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004574 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 }
4576 }
4577 cifs_buf_release(pSMB);
4578
4579 if (rc == -EAGAIN)
4580 goto QFSPosixRetry;
4581
4582 return rc;
4583}
4584
4585
Steve French50c2f752007-07-13 00:33:32 +00004586/* We can not use write of zero bytes trick to
4587 set file size due to need for large file support. Also note that
4588 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 routine which is only needed to work around a sharing violation bug
4590 in Samba which this routine can run into */
4591
4592int
4593CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004594 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004595 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596{
4597 struct smb_com_transaction2_spi_req *pSMB = NULL;
4598 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4599 struct file_end_of_file_info *parm_data;
4600 int name_len;
4601 int rc = 0;
4602 int bytes_returned = 0;
4603 __u16 params, byte_count, data_count, param_offset, offset;
4604
4605 cFYI(1, ("In SetEOF"));
4606SetEOFRetry:
4607 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4608 (void **) &pSMBr);
4609 if (rc)
4610 return rc;
4611
4612 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4613 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004614 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004615 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 name_len++; /* trailing null */
4617 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004618 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 name_len = strnlen(fileName, PATH_MAX);
4620 name_len++; /* trailing null */
4621 strncpy(pSMB->FileName, fileName, name_len);
4622 }
4623 params = 6 + name_len;
4624 data_count = sizeof (struct file_end_of_file_info);
4625 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004626 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 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_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004633 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004635 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004636 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4637 pSMB->InformationLevel =
4638 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4639 else
4640 pSMB->InformationLevel =
4641 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4642 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4644 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004645 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 else
4647 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004648 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 }
4650
4651 parm_data =
4652 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4653 offset);
4654 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4655 pSMB->DataOffset = cpu_to_le16(offset);
4656 pSMB->SetupCount = 1;
4657 pSMB->Reserved3 = 0;
4658 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4659 byte_count = 3 /* pad */ + params + data_count;
4660 pSMB->DataCount = cpu_to_le16(data_count);
4661 pSMB->TotalDataCount = pSMB->DataCount;
4662 pSMB->ParameterCount = cpu_to_le16(params);
4663 pSMB->TotalParameterCount = pSMB->ParameterCount;
4664 pSMB->Reserved4 = 0;
4665 pSMB->hdr.smb_buf_length += byte_count;
4666 parm_data->FileSize = cpu_to_le64(size);
4667 pSMB->ByteCount = cpu_to_le16(byte_count);
4668 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4669 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4670 if (rc) {
4671 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4672 }
4673
4674 cifs_buf_release(pSMB);
4675
4676 if (rc == -EAGAIN)
4677 goto SetEOFRetry;
4678
4679 return rc;
4680}
4681
4682int
Steve French50c2f752007-07-13 00:33:32 +00004683CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4684 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685{
4686 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4687 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4688 char *data_offset;
4689 struct file_end_of_file_info *parm_data;
4690 int rc = 0;
4691 int bytes_returned = 0;
4692 __u16 params, param_offset, offset, byte_count, count;
4693
4694 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4695 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004696 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4697
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 if (rc)
4699 return rc;
4700
Steve Frenchcd634992005-04-28 22:41:10 -07004701 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4702
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4704 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004705
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 params = 6;
4707 pSMB->MaxSetupCount = 0;
4708 pSMB->Reserved = 0;
4709 pSMB->Flags = 0;
4710 pSMB->Timeout = 0;
4711 pSMB->Reserved2 = 0;
4712 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4713 offset = param_offset + params;
4714
Steve French50c2f752007-07-13 00:33:32 +00004715 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716
4717 count = sizeof(struct file_end_of_file_info);
4718 pSMB->MaxParameterCount = cpu_to_le16(2);
4719 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4720 pSMB->SetupCount = 1;
4721 pSMB->Reserved3 = 0;
4722 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4723 byte_count = 3 /* pad */ + params + count;
4724 pSMB->DataCount = cpu_to_le16(count);
4725 pSMB->ParameterCount = cpu_to_le16(params);
4726 pSMB->TotalDataCount = pSMB->DataCount;
4727 pSMB->TotalParameterCount = pSMB->ParameterCount;
4728 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4729 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004730 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4731 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 pSMB->DataOffset = cpu_to_le16(offset);
4733 parm_data->FileSize = cpu_to_le64(size);
4734 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004735 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4737 pSMB->InformationLevel =
4738 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4739 else
4740 pSMB->InformationLevel =
4741 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004742 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4744 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004745 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 else
4747 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004748 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 }
4750 pSMB->Reserved4 = 0;
4751 pSMB->hdr.smb_buf_length += byte_count;
4752 pSMB->ByteCount = cpu_to_le16(byte_count);
4753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4754 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4755 if (rc) {
4756 cFYI(1,
4757 ("Send error in SetFileInfo (SetFileSize) = %d",
4758 rc));
4759 }
4760
4761 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004762 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Steve French50c2f752007-07-13 00:33:32 +00004764 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 since file handle passed in no longer valid */
4766
4767 return rc;
4768}
4769
Steve French50c2f752007-07-13 00:33:32 +00004770/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 an open handle, rather than by pathname - this is awkward due to
4772 potential access conflicts on the open, but it is unavoidable for these
4773 old servers since the only other choice is to go from 100 nanosecond DCE
4774 time and resort to the original setpathinfo level which takes the ancient
4775 DOS time format with 2 second granularity */
4776int
Steve French50c2f752007-07-13 00:33:32 +00004777CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4778 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779{
4780 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4781 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4782 char *data_offset;
4783 int rc = 0;
4784 int bytes_returned = 0;
4785 __u16 params, param_offset, offset, byte_count, count;
4786
4787 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004788 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4789
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 if (rc)
4791 return rc;
4792
Steve Frenchcd634992005-04-28 22:41:10 -07004793 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4794
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 /* At this point there is no need to override the current pid
4796 with the pid of the opener, but that could change if we someday
4797 use an existing handle (rather than opening one on the fly) */
4798 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4799 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004800
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 params = 6;
4802 pSMB->MaxSetupCount = 0;
4803 pSMB->Reserved = 0;
4804 pSMB->Flags = 0;
4805 pSMB->Timeout = 0;
4806 pSMB->Reserved2 = 0;
4807 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4808 offset = param_offset + params;
4809
Steve French50c2f752007-07-13 00:33:32 +00004810 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811
4812 count = sizeof (FILE_BASIC_INFO);
4813 pSMB->MaxParameterCount = cpu_to_le16(2);
4814 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4815 pSMB->SetupCount = 1;
4816 pSMB->Reserved3 = 0;
4817 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4818 byte_count = 3 /* pad */ + params + count;
4819 pSMB->DataCount = cpu_to_le16(count);
4820 pSMB->ParameterCount = cpu_to_le16(params);
4821 pSMB->TotalDataCount = pSMB->DataCount;
4822 pSMB->TotalParameterCount = pSMB->ParameterCount;
4823 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4824 pSMB->DataOffset = cpu_to_le16(offset);
4825 pSMB->Fid = fid;
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 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004833 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4836 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004837 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 }
4839
Steve Frenchcd634992005-04-28 22:41:10 -07004840 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841
Steve French50c2f752007-07-13 00:33:32 +00004842 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 since file handle passed in no longer valid */
4844
4845 return rc;
4846}
4847
4848
4849int
4850CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004851 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004852 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853{
4854 TRANSACTION2_SPI_REQ *pSMB = NULL;
4855 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4856 int name_len;
4857 int rc = 0;
4858 int bytes_returned = 0;
4859 char *data_offset;
4860 __u16 params, param_offset, offset, byte_count, count;
4861
4862 cFYI(1, ("In SetTimes"));
4863
4864SetTimesRetry:
4865 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4866 (void **) &pSMBr);
4867 if (rc)
4868 return rc;
4869
4870 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4871 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004872 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004873 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 name_len++; /* trailing null */
4875 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004876 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 name_len = strnlen(fileName, PATH_MAX);
4878 name_len++; /* trailing null */
4879 strncpy(pSMB->FileName, fileName, name_len);
4880 }
4881
4882 params = 6 + name_len;
4883 count = sizeof (FILE_BASIC_INFO);
4884 pSMB->MaxParameterCount = cpu_to_le16(2);
4885 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4886 pSMB->MaxSetupCount = 0;
4887 pSMB->Reserved = 0;
4888 pSMB->Flags = 0;
4889 pSMB->Timeout = 0;
4890 pSMB->Reserved2 = 0;
4891 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004892 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 offset = param_offset + params;
4894 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4895 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4896 pSMB->DataOffset = cpu_to_le16(offset);
4897 pSMB->SetupCount = 1;
4898 pSMB->Reserved3 = 0;
4899 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4900 byte_count = 3 /* pad */ + params + count;
4901
4902 pSMB->DataCount = cpu_to_le16(count);
4903 pSMB->ParameterCount = cpu_to_le16(params);
4904 pSMB->TotalDataCount = pSMB->DataCount;
4905 pSMB->TotalParameterCount = pSMB->ParameterCount;
4906 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4907 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4908 else
4909 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4910 pSMB->Reserved4 = 0;
4911 pSMB->hdr.smb_buf_length += byte_count;
4912 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4913 pSMB->ByteCount = cpu_to_le16(byte_count);
4914 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4915 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4916 if (rc) {
4917 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4918 }
4919
4920 cifs_buf_release(pSMB);
4921
4922 if (rc == -EAGAIN)
4923 goto SetTimesRetry;
4924
4925 return rc;
4926}
4927
4928/* Can not be used to set time stamps yet (due to old DOS time format) */
4929/* Can be used to set attributes */
4930#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4931 handling it anyway and NT4 was what we thought it would be needed for
4932 Do not delete it until we prove whether needed for Win9x though */
4933int
4934CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4935 __u16 dos_attrs, const struct nls_table *nls_codepage)
4936{
4937 SETATTR_REQ *pSMB = NULL;
4938 SETATTR_RSP *pSMBr = NULL;
4939 int rc = 0;
4940 int bytes_returned;
4941 int name_len;
4942
4943 cFYI(1, ("In SetAttrLegacy"));
4944
4945SetAttrLgcyRetry:
4946 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4947 (void **) &pSMBr);
4948 if (rc)
4949 return rc;
4950
4951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4952 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004953 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 PATH_MAX, nls_codepage);
4955 name_len++; /* trailing null */
4956 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004957 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958 name_len = strnlen(fileName, PATH_MAX);
4959 name_len++; /* trailing null */
4960 strncpy(pSMB->fileName, fileName, name_len);
4961 }
4962 pSMB->attr = cpu_to_le16(dos_attrs);
4963 pSMB->BufferFormat = 0x04;
4964 pSMB->hdr.smb_buf_length += name_len + 1;
4965 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4966 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4967 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4968 if (rc) {
4969 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4970 }
4971
4972 cifs_buf_release(pSMB);
4973
4974 if (rc == -EAGAIN)
4975 goto SetAttrLgcyRetry;
4976
4977 return rc;
4978}
4979#endif /* temporarily unneeded SetAttr legacy function */
4980
4981int
4982CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004983 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4984 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004985 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986{
4987 TRANSACTION2_SPI_REQ *pSMB = NULL;
4988 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4989 int name_len;
4990 int rc = 0;
4991 int bytes_returned = 0;
4992 FILE_UNIX_BASIC_INFO *data_offset;
4993 __u16 params, param_offset, offset, count, byte_count;
4994
4995 cFYI(1, ("In SetUID/GID/Mode"));
4996setPermsRetry:
4997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4998 (void **) &pSMBr);
4999 if (rc)
5000 return rc;
5001
5002 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5003 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005004 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005005 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 name_len++; /* trailing null */
5007 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005008 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 name_len = strnlen(fileName, PATH_MAX);
5010 name_len++; /* trailing null */
5011 strncpy(pSMB->FileName, fileName, name_len);
5012 }
5013
5014 params = 6 + name_len;
5015 count = sizeof (FILE_UNIX_BASIC_INFO);
5016 pSMB->MaxParameterCount = cpu_to_le16(2);
5017 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5018 pSMB->MaxSetupCount = 0;
5019 pSMB->Reserved = 0;
5020 pSMB->Flags = 0;
5021 pSMB->Timeout = 0;
5022 pSMB->Reserved2 = 0;
5023 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005024 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 offset = param_offset + params;
5026 data_offset =
5027 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5028 offset);
5029 memset(data_offset, 0, count);
5030 pSMB->DataOffset = cpu_to_le16(offset);
5031 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5032 pSMB->SetupCount = 1;
5033 pSMB->Reserved3 = 0;
5034 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5035 byte_count = 3 /* pad */ + params + count;
5036 pSMB->ParameterCount = cpu_to_le16(params);
5037 pSMB->DataCount = cpu_to_le16(count);
5038 pSMB->TotalParameterCount = pSMB->ParameterCount;
5039 pSMB->TotalDataCount = pSMB->DataCount;
5040 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5041 pSMB->Reserved4 = 0;
5042 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005043 /* Samba server ignores set of file size to zero due to bugs in some
5044 older clients, but we should be precise - we use SetFileSize to
5045 set file size and do not want to truncate file size to zero
5046 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005047 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005048 data_offset->EndOfFile = NO_CHANGE_64;
5049 data_offset->NumOfBytes = NO_CHANGE_64;
5050 data_offset->LastStatusChange = NO_CHANGE_64;
5051 data_offset->LastAccessTime = NO_CHANGE_64;
5052 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 data_offset->Uid = cpu_to_le64(uid);
5054 data_offset->Gid = cpu_to_le64(gid);
5055 /* better to leave device as zero when it is */
5056 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5057 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5058 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005059
Steve French790fe572007-07-07 19:25:05 +00005060 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005062 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005064 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005066 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005068 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005070 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005072 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5074
5075
5076 pSMB->ByteCount = cpu_to_le16(byte_count);
5077 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5078 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5079 if (rc) {
5080 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5081 }
5082
5083 if (pSMB)
5084 cifs_buf_release(pSMB);
5085 if (rc == -EAGAIN)
5086 goto setPermsRetry;
5087 return rc;
5088}
5089
Steve French50c2f752007-07-13 00:33:32 +00005090int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005091 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005092 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005093 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094{
5095 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005096 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5097 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005098 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 int bytes_returned;
5100
Steve French50c2f752007-07-13 00:33:32 +00005101 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005103 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 if (rc)
5105 return rc;
5106
5107 pSMB->TotalParameterCount = 0 ;
5108 pSMB->TotalDataCount = 0;
5109 pSMB->MaxParameterCount = cpu_to_le32(2);
5110 /* BB find exact data count max from sess structure BB */
5111 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005112/* BB VERIFY verify which is correct for above BB */
5113 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5114 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5115
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 pSMB->MaxSetupCount = 4;
5117 pSMB->Reserved = 0;
5118 pSMB->ParameterOffset = 0;
5119 pSMB->DataCount = 0;
5120 pSMB->DataOffset = 0;
5121 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5122 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5123 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005124 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5126 pSMB->Reserved2 = 0;
5127 pSMB->CompletionFilter = cpu_to_le32(filter);
5128 pSMB->Fid = netfid; /* file handle always le */
5129 pSMB->ByteCount = 0;
5130
5131 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5132 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5133 if (rc) {
5134 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005135 } else {
5136 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005137 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005138 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005139 sizeof(struct dir_notify_req),
5140 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005141 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005142 dnotify_req->Pid = pSMB->hdr.Pid;
5143 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5144 dnotify_req->Mid = pSMB->hdr.Mid;
5145 dnotify_req->Tid = pSMB->hdr.Tid;
5146 dnotify_req->Uid = pSMB->hdr.Uid;
5147 dnotify_req->netfid = netfid;
5148 dnotify_req->pfile = pfile;
5149 dnotify_req->filter = filter;
5150 dnotify_req->multishot = multishot;
5151 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005152 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005153 &GlobalDnotifyReqList);
5154 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005155 } else
Steve French47c786e2005-10-11 20:03:18 -07005156 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 }
5158 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005159 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160}
5161#ifdef CONFIG_CIFS_XATTR
5162ssize_t
5163CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5164 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005165 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005166 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167{
5168 /* BB assumes one setup word */
5169 TRANSACTION2_QPI_REQ *pSMB = NULL;
5170 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5171 int rc = 0;
5172 int bytes_returned;
5173 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005174 struct fea *temp_fea;
5175 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 __u16 params, byte_count;
5177
5178 cFYI(1, ("In Query All EAs path %s", searchName));
5179QAllEAsRetry:
5180 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5181 (void **) &pSMBr);
5182 if (rc)
5183 return rc;
5184
5185 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5186 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005187 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005188 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 name_len++; /* trailing null */
5190 name_len *= 2;
5191 } else { /* BB improve the check for buffer overruns BB */
5192 name_len = strnlen(searchName, PATH_MAX);
5193 name_len++; /* trailing null */
5194 strncpy(pSMB->FileName, searchName, name_len);
5195 }
5196
Steve French50c2f752007-07-13 00:33:32 +00005197 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 pSMB->TotalDataCount = 0;
5199 pSMB->MaxParameterCount = cpu_to_le16(2);
5200 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5201 pSMB->MaxSetupCount = 0;
5202 pSMB->Reserved = 0;
5203 pSMB->Flags = 0;
5204 pSMB->Timeout = 0;
5205 pSMB->Reserved2 = 0;
5206 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005207 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 pSMB->DataCount = 0;
5209 pSMB->DataOffset = 0;
5210 pSMB->SetupCount = 1;
5211 pSMB->Reserved3 = 0;
5212 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5213 byte_count = params + 1 /* pad */ ;
5214 pSMB->TotalParameterCount = cpu_to_le16(params);
5215 pSMB->ParameterCount = pSMB->TotalParameterCount;
5216 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5217 pSMB->Reserved4 = 0;
5218 pSMB->hdr.smb_buf_length += byte_count;
5219 pSMB->ByteCount = cpu_to_le16(byte_count);
5220
5221 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5222 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5223 if (rc) {
5224 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5225 } else { /* decode response */
5226 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5227
5228 /* BB also check enough total bytes returned */
5229 /* BB we need to improve the validity checking
5230 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005231 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 rc = -EIO; /* bad smb */
5233 /* else if (pFindData){
5234 memcpy((char *) pFindData,
5235 (char *) &pSMBr->hdr.Protocol +
5236 data_offset, kl);
5237 }*/ else {
5238 /* check that length of list is not more than bcc */
5239 /* check that each entry does not go beyond length
5240 of list */
5241 /* check that each element of each entry does not
5242 go beyond end of list */
5243 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005244 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 rc = 0;
5246 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005247 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 ea_response_data = (struct fealist *)
5249 (((char *) &pSMBr->hdr.Protocol) +
5250 data_offset);
5251 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005252 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005253 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005255 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 } else {
5257 /* account for ea list len */
5258 name_len -= 4;
5259 temp_fea = ea_response_data->list;
5260 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005261 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 __u16 value_len;
5263 name_len -= 4;
5264 temp_ptr += 4;
5265 rc += temp_fea->name_len;
5266 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005267 rc = rc + 5 + 1;
5268 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005269 memcpy(EAData, "user.", 5);
5270 EAData += 5;
5271 memcpy(EAData, temp_ptr,
5272 temp_fea->name_len);
5273 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 /* null terminate name */
5275 *EAData = 0;
5276 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005277 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 /* skip copy - calc size only */
5279 } else {
5280 /* stop before overrun buffer */
5281 rc = -ERANGE;
5282 break;
5283 }
5284 name_len -= temp_fea->name_len;
5285 temp_ptr += temp_fea->name_len;
5286 /* account for trailing null */
5287 name_len--;
5288 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005289 value_len =
5290 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 name_len -= value_len;
5292 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005293 /* BB check that temp_ptr is still
5294 within the SMB BB*/
5295
5296 /* no trailing null to account for
5297 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 /* go on to next EA */
5299 temp_fea = (struct fea *)temp_ptr;
5300 }
5301 }
5302 }
5303 }
5304 if (pSMB)
5305 cifs_buf_release(pSMB);
5306 if (rc == -EAGAIN)
5307 goto QAllEAsRetry;
5308
5309 return (ssize_t)rc;
5310}
5311
Steve French50c2f752007-07-13 00:33:32 +00005312ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5313 const unsigned char *searchName, const unsigned char *ea_name,
5314 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005315 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316{
5317 TRANSACTION2_QPI_REQ *pSMB = NULL;
5318 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5319 int rc = 0;
5320 int bytes_returned;
5321 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005322 struct fea *temp_fea;
5323 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 __u16 params, byte_count;
5325
5326 cFYI(1, ("In Query EA path %s", searchName));
5327QEARetry:
5328 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5329 (void **) &pSMBr);
5330 if (rc)
5331 return rc;
5332
5333 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5334 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005335 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005336 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337 name_len++; /* trailing null */
5338 name_len *= 2;
5339 } else { /* BB improve the check for buffer overruns BB */
5340 name_len = strnlen(searchName, PATH_MAX);
5341 name_len++; /* trailing null */
5342 strncpy(pSMB->FileName, searchName, name_len);
5343 }
5344
Steve French50c2f752007-07-13 00:33:32 +00005345 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 pSMB->TotalDataCount = 0;
5347 pSMB->MaxParameterCount = cpu_to_le16(2);
5348 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5349 pSMB->MaxSetupCount = 0;
5350 pSMB->Reserved = 0;
5351 pSMB->Flags = 0;
5352 pSMB->Timeout = 0;
5353 pSMB->Reserved2 = 0;
5354 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005355 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 pSMB->DataCount = 0;
5357 pSMB->DataOffset = 0;
5358 pSMB->SetupCount = 1;
5359 pSMB->Reserved3 = 0;
5360 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5361 byte_count = params + 1 /* pad */ ;
5362 pSMB->TotalParameterCount = cpu_to_le16(params);
5363 pSMB->ParameterCount = pSMB->TotalParameterCount;
5364 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5365 pSMB->Reserved4 = 0;
5366 pSMB->hdr.smb_buf_length += byte_count;
5367 pSMB->ByteCount = cpu_to_le16(byte_count);
5368
5369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5371 if (rc) {
5372 cFYI(1, ("Send error in Query EA = %d", rc));
5373 } else { /* decode response */
5374 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5375
5376 /* BB also check enough total bytes returned */
5377 /* BB we need to improve the validity checking
5378 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005379 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 rc = -EIO; /* bad smb */
5381 /* else if (pFindData){
5382 memcpy((char *) pFindData,
5383 (char *) &pSMBr->hdr.Protocol +
5384 data_offset, kl);
5385 }*/ else {
5386 /* check that length of list is not more than bcc */
5387 /* check that each entry does not go beyond length
5388 of list */
5389 /* check that each element of each entry does not
5390 go beyond end of list */
5391 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005392 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 rc = -ENODATA;
5394 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005395 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 ea_response_data = (struct fealist *)
5397 (((char *) &pSMBr->hdr.Protocol) +
5398 data_offset);
5399 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005400 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005401 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005403 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 } else {
5405 /* account for ea list len */
5406 name_len -= 4;
5407 temp_fea = ea_response_data->list;
5408 temp_ptr = (char *)temp_fea;
5409 /* loop through checking if we have a matching
5410 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005411 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 __u16 value_len;
5413 name_len -= 4;
5414 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005415 value_len =
5416 le16_to_cpu(temp_fea->value_len);
5417 /* BB validate that value_len falls within SMB,
5418 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005419 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 temp_fea->name_len) == 0) {
5421 /* found a match */
5422 rc = value_len;
5423 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005424 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 memcpy(ea_value,
5426 temp_fea->name+temp_fea->name_len+1,
5427 rc);
Steve French50c2f752007-07-13 00:33:32 +00005428 /* ea values, unlike ea
5429 names, are not null
5430 terminated */
Steve French790fe572007-07-07 19:25:05 +00005431 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 /* skip copy - calc size only */
5433 } else {
Steve French50c2f752007-07-13 00:33:32 +00005434 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 rc = -ERANGE;
5436 }
5437 break;
5438 }
5439 name_len -= temp_fea->name_len;
5440 temp_ptr += temp_fea->name_len;
5441 /* account for trailing null */
5442 name_len--;
5443 temp_ptr++;
5444 name_len -= value_len;
5445 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005446 /* No trailing null to account for in
5447 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 temp_fea = (struct fea *)temp_ptr;
5449 }
Steve French50c2f752007-07-13 00:33:32 +00005450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 }
5452 }
5453 if (pSMB)
5454 cifs_buf_release(pSMB);
5455 if (rc == -EAGAIN)
5456 goto QEARetry;
5457
5458 return (ssize_t)rc;
5459}
5460
5461int
5462CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005463 const char *ea_name, const void *ea_value,
5464 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5465 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466{
5467 struct smb_com_transaction2_spi_req *pSMB = NULL;
5468 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5469 struct fealist *parm_data;
5470 int name_len;
5471 int rc = 0;
5472 int bytes_returned = 0;
5473 __u16 params, param_offset, byte_count, offset, count;
5474
5475 cFYI(1, ("In SetEA"));
5476SetEARetry:
5477 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5478 (void **) &pSMBr);
5479 if (rc)
5480 return rc;
5481
5482 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5483 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005484 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005485 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 name_len++; /* trailing null */
5487 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005488 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 name_len = strnlen(fileName, PATH_MAX);
5490 name_len++; /* trailing null */
5491 strncpy(pSMB->FileName, fileName, name_len);
5492 }
5493
5494 params = 6 + name_len;
5495
5496 /* done calculating parms using name_len of file name,
5497 now use name_len to calculate length of ea name
5498 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005499 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 name_len = 0;
5501 else
Steve French50c2f752007-07-13 00:33:32 +00005502 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503
5504 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5505 pSMB->MaxParameterCount = cpu_to_le16(2);
5506 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5507 pSMB->MaxSetupCount = 0;
5508 pSMB->Reserved = 0;
5509 pSMB->Flags = 0;
5510 pSMB->Timeout = 0;
5511 pSMB->Reserved2 = 0;
5512 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005513 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 offset = param_offset + params;
5515 pSMB->InformationLevel =
5516 cpu_to_le16(SMB_SET_FILE_EA);
5517
5518 parm_data =
5519 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5520 offset);
5521 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5522 pSMB->DataOffset = cpu_to_le16(offset);
5523 pSMB->SetupCount = 1;
5524 pSMB->Reserved3 = 0;
5525 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5526 byte_count = 3 /* pad */ + params + count;
5527 pSMB->DataCount = cpu_to_le16(count);
5528 parm_data->list_len = cpu_to_le32(count);
5529 parm_data->list[0].EA_flags = 0;
5530 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005531 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005533 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005534 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 parm_data->list[0].name[name_len] = 0;
5536 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5537 /* caller ensures that ea_value_len is less than 64K but
5538 we need to ensure that it fits within the smb */
5539
Steve French50c2f752007-07-13 00:33:32 +00005540 /*BB add length check to see if it would fit in
5541 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005542 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5543 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005544 memcpy(parm_data->list[0].name+name_len+1,
5545 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546
5547 pSMB->TotalDataCount = pSMB->DataCount;
5548 pSMB->ParameterCount = cpu_to_le16(params);
5549 pSMB->TotalParameterCount = pSMB->ParameterCount;
5550 pSMB->Reserved4 = 0;
5551 pSMB->hdr.smb_buf_length += byte_count;
5552 pSMB->ByteCount = cpu_to_le16(byte_count);
5553 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5554 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5555 if (rc) {
5556 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5557 }
5558
5559 cifs_buf_release(pSMB);
5560
5561 if (rc == -EAGAIN)
5562 goto SetEARetry;
5563
5564 return rc;
5565}
5566
5567#endif