blob: 9c04ad404553b3c006dc8c5261abb19d40abb99f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchad7a2922008-02-07 23:25:02 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
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"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
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);
Steve French26f57362007-08-30 22:09:15 +000097 if (open_file)
Steve French4b18f2a2008-04-29 00:06:05 +000098 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
Steve Frenchad7a2922008-02-07 23:25:02 +0000105/* Allocate and return pointer to an SMB request buffer, and set basic
106 SMB information in the SMB header. If the return code is zero, this
107 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108static int
109small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000110 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
112 int rc = 0;
113
114 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
115 check for tcp and smb session status done differently
116 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000117 if (tcon) {
118 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800119 /* only tree disconnect, open, and write,
120 (and ulogoff which does not have tcon)
121 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000122 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000123 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800124 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000125 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800126 smb_command));
127 return -ENODEV;
128 }
129 }
Steve French790fe572007-07-07 19:25:05 +0000130 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000131 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000133 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700134 reconnect, should be greater than cifs socket
135 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000136 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000137 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000139 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000140 CifsGood), 10 * HZ);
141 if (tcon->ses->server->tcpStatus ==
142 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000144 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000146 cFYI(1, ("gave up waiting on "
147 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700149 } /* else "hard" mount - keep retrying
150 until process is killed or server
151 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 } else /* TCP session is reestablished now */
153 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 }
Steve French50c2f752007-07-13 00:33:32 +0000155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 nls_codepage = load_nls_default();
157 /* need to prevent multiple threads trying to
158 simultaneously reconnect the same SMB session */
159 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000160 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000161 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700162 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000163 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000165 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000166 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700168 /* BB FIXME add code to check if wsize needs
169 update due to negotiated smb buffer size
170 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000171 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000173 /* tell server Unix caps we support */
174 if (tcon->ses->capabilities & CAP_UNIX)
175 reset_cifs_unix_caps(
176 0 /* no xid */,
177 tcon,
178 NULL /* we do not know sb */,
179 NULL /* no vol info */);
180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000183 /* Removed call to reopen open files here.
184 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700185 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Steve French50c2f752007-07-13 00:33:32 +0000187 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700188 know whether we can continue or not without
189 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000190 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 case SMB_COM_READ_ANDX:
192 case SMB_COM_WRITE_ANDX:
193 case SMB_COM_CLOSE:
194 case SMB_COM_FIND_CLOSE2:
195 case SMB_COM_LOCKING_ANDX: {
196 unload_nls(nls_codepage);
197 return -EAGAIN;
198 }
199 }
200 } else {
201 up(&tcon->ses->sesSem);
202 }
203 unload_nls(nls_codepage);
204
205 } else {
206 return -EIO;
207 }
208 }
Steve French790fe572007-07-07 19:25:05 +0000209 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 return rc;
211
212 *request_buf = cifs_small_buf_get();
213 if (*request_buf == NULL) {
214 /* BB should we add a retry in here if not a writepage? */
215 return -ENOMEM;
216 }
217
Steve French63135e02007-07-17 17:34:02 +0000218 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000219 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Steve French790fe572007-07-07 19:25:05 +0000221 if (tcon != NULL)
222 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000225}
226
Steve French12b3b8f2006-02-09 21:12:47 +0000227int
Steve French50c2f752007-07-13 00:33:32 +0000228small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000229 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000230{
231 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000232 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000233
Steve French5815449d2006-02-14 01:36:20 +0000234 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000235 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000236 return rc;
237
Steve French04fdabe2006-02-10 05:52:50 +0000238 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000239 buffer->Mid = GetNextMid(ses->server);
240 if (ses->capabilities & CAP_UNICODE)
241 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000242 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000243 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
244
245 /* uid, tid can stay at zero as set in header assemble */
246
Steve French50c2f752007-07-13 00:33:32 +0000247 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000248 this function is used after 1st of session setup requests */
249
250 return rc;
251}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253/* If the return code is zero, this function must fill in request_buf pointer */
254static int
255smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
256 void **request_buf /* returned */ ,
257 void **response_buf /* returned */ )
258{
259 int rc = 0;
260
261 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
262 check for tcp and smb session status done differently
263 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000264 if (tcon) {
265 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800266 /* only tree disconnect, open, and write,
267 (and ulogoff which does not have tcon)
268 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000269 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800270 (smb_command != SMB_COM_OPEN_ANDX) &&
271 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000272 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800273 smb_command));
274 return -ENODEV;
275 }
276 }
277
Steve French790fe572007-07-07 19:25:05 +0000278 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000279 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700281 /* Give Demultiplex thread up to 10 seconds to
282 reconnect, should be greater than cifs socket
283 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000284 while (tcon->ses->server->tcpStatus ==
285 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000287 (tcon->ses->server->tcpStatus ==
288 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000289 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700290 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000292 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000294 cFYI(1, ("gave up waiting on "
295 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700297 } /* else "hard" mount - keep retrying
298 until process is killed or server
299 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 } else /* TCP session is reestablished now */
301 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 nls_codepage = load_nls_default();
304 /* need to prevent multiple threads trying to
305 simultaneously reconnect the same SMB session */
306 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000307 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000308 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700309 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000310 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700312 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
313 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700315 /* BB FIXME add code to check if wsize needs
316 update due to negotiated smb buffer size
317 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000318 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000320 /* tell server Unix caps we support */
321 if (tcon->ses->capabilities & CAP_UNIX)
322 reset_cifs_unix_caps(
323 0 /* no xid */,
324 tcon,
325 NULL /* do not know sb */,
326 NULL /* no vol info */);
327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000330 /* Removed call to reopen open files here.
331 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700332 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Steve French50c2f752007-07-13 00:33:32 +0000334 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700335 know whether we can continue or not without
336 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000337 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 case SMB_COM_READ_ANDX:
339 case SMB_COM_WRITE_ANDX:
340 case SMB_COM_CLOSE:
341 case SMB_COM_FIND_CLOSE2:
342 case SMB_COM_LOCKING_ANDX: {
343 unload_nls(nls_codepage);
344 return -EAGAIN;
345 }
346 }
347 } else {
348 up(&tcon->ses->sesSem);
349 }
350 unload_nls(nls_codepage);
351
352 } else {
353 return -EIO;
354 }
355 }
Steve French790fe572007-07-07 19:25:05 +0000356 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return rc;
358
359 *request_buf = cifs_buf_get();
360 if (*request_buf == NULL) {
361 /* BB should we add a retry in here if not a writepage? */
362 return -ENOMEM;
363 }
364 /* Although the original thought was we needed the response buf for */
365 /* potential retries of smb operations it turns out we can determine */
366 /* from the mid flags when the request buffer can be resent without */
367 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000368 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000369 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000372 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
Steve French790fe572007-07-07 19:25:05 +0000374 if (tcon != NULL)
375 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return rc;
378}
379
Steve French50c2f752007-07-13 00:33:32 +0000380static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
382 int rc = -EINVAL;
383 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000384 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
386 /* check for plausible wct, bcc and t2 data and parm sizes */
387 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000388 if (pSMB->hdr.WordCount >= 10) {
389 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
391 /* check that bcc is at least as big as parms + data */
392 /* check that bcc is less than negotiated smb buffer */
393 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000394 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000395 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000396 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000398 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700399 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000401 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000402 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
404 return 0;
405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 }
407 }
408 }
Steve French50c2f752007-07-13 00:33:32 +0000409 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 sizeof(struct smb_t2_rsp) + 16);
411 return rc;
412}
413int
414CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
415{
416 NEGOTIATE_REQ *pSMB;
417 NEGOTIATE_RSP *pSMBr;
418 int rc = 0;
419 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000420 int i;
Steve French50c2f752007-07-13 00:33:32 +0000421 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000423 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100424 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Steve French790fe572007-07-07 19:25:05 +0000426 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 server = ses->server;
428 else {
429 rc = -EIO;
430 return rc;
431 }
432 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
433 (void **) &pSMB, (void **) &pSMBr);
434 if (rc)
435 return rc;
Steve French750d1152006-06-27 06:28:30 +0000436
437 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000438 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000439 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000440 else /* if override flags set only sign/seal OR them with global auth */
441 secFlags = extended_security | ses->overrideSecFlg;
442
Steve French762e5ab2007-06-28 18:41:42 +0000443 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000444
Steve French1982c342005-08-17 12:38:22 -0700445 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000446 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000447
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000448 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000449 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000450 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
451 cFYI(1, ("Kerberos only mechanism, enable extended security"));
452 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
453 }
Steve French50c2f752007-07-13 00:33:32 +0000454
Steve French39798772006-05-31 22:40:51 +0000455 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000456 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000457 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
458 count += strlen(protocols[i].name) + 1;
459 /* null at end of source and target buffers anyway */
460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 pSMB->hdr.smb_buf_length += count;
462 pSMB->ByteCount = cpu_to_le16(count);
463
464 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000466 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000467 goto neg_err_exit;
468
Al Viro733f99a2006-10-14 16:48:26 +0100469 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000470 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000471 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000472 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000473 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000474 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000475 could not negotiate a common dialect */
476 rc = -EOPNOTSUPP;
477 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000478#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000479 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100480 && ((dialect == LANMAN_PROT)
481 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000482 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000483 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000484
Steve French790fe572007-07-07 19:25:05 +0000485 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000486 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000487 server->secType = LANMAN;
488 else {
489 cERROR(1, ("mount failed weak security disabled"
490 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000491 rc = -EOPNOTSUPP;
492 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000493 }
Steve French254e55e2006-06-04 05:53:15 +0000494 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
495 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
496 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000497 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000498 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
499 /* even though we do not use raw we might as well set this
500 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000501 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000502 server->maxRw = 0xFF00;
503 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
504 } else {
505 server->maxRw = 0;/* we do not need to use raw anyway */
506 server->capabilities = CAP_MPX_MODE;
507 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000508 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000509 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000510 /* OS/2 often does not set timezone therefore
511 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000512 * Could deviate slightly from the right zone.
513 * Smallest defined timezone difference is 15 minutes
514 * (i.e. Nepal). Rounding up/down is done to match
515 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000516 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000517 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000518 struct timespec ts, utc;
519 utc = CURRENT_TIME;
520 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
521 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000522 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
523 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000524 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000525 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000526 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000527 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000528 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000529 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000530 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000531 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000532 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000533 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000534 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000535 server->timeAdj = (int)tmp;
536 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000537 }
Steve French790fe572007-07-07 19:25:05 +0000538 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000539
Steve French39798772006-05-31 22:40:51 +0000540
Steve French254e55e2006-06-04 05:53:15 +0000541 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000542 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000543
Steve French50c2f752007-07-13 00:33:32 +0000544 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000545 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000546 memcpy(server->cryptKey, rsp->EncryptionKey,
547 CIFS_CRYPTO_KEY_SIZE);
548 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
549 rc = -EIO; /* need cryptkey unless plain text */
550 goto neg_err_exit;
551 }
Steve French39798772006-05-31 22:40:51 +0000552
Steve French790fe572007-07-07 19:25:05 +0000553 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000554 /* we will not end up setting signing flags - as no signing
555 was in LANMAN and server did not return the flags on */
556 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000557#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000558 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000559 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000560 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000561 rc = -EOPNOTSUPP;
562#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000563 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000564 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000565 /* unknown wct */
566 rc = -EOPNOTSUPP;
567 goto neg_err_exit;
568 }
569 /* else wct == 17 NTLM */
570 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000571 if ((server->secMode & SECMODE_USER) == 0)
572 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000573
Steve French790fe572007-07-07 19:25:05 +0000574 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000575#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000576 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000577#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000578 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000579 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000580
Steve French790fe572007-07-07 19:25:05 +0000581 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000582 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000583 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000584 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000585 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000586 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000587 else if (secFlags & CIFSSEC_MAY_KRB5)
588 server->secType = Kerberos;
589 else if (secFlags & CIFSSEC_MAY_LANMAN)
590 server->secType = LANMAN;
591/* #ifdef CONFIG_CIFS_EXPERIMENTAL
592 else if (secFlags & CIFSSEC_MAY_PLNTXT)
593 server->secType = ??
594#endif */
595 else {
596 rc = -EOPNOTSUPP;
597 cERROR(1, ("Invalid security type"));
598 goto neg_err_exit;
599 }
600 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000601
Steve French254e55e2006-06-04 05:53:15 +0000602 /* one byte, so no need to convert this or EncryptionKeyLen from
603 little endian */
604 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
605 /* probably no need to store and check maxvcs */
606 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000608 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000609 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000610 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
611 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000612 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
613 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000614 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
615 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
616 CIFS_CRYPTO_KEY_SIZE);
617 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
618 && (pSMBr->EncryptionKeyLength == 0)) {
619 /* decode security blob */
620 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
621 rc = -EIO; /* no crypt key only if plain text pwd */
622 goto neg_err_exit;
623 }
624
625 /* BB might be helpful to save off the domain of server here */
626
Steve French50c2f752007-07-13 00:33:32 +0000627 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000628 (server->capabilities & CAP_EXTENDED_SECURITY)) {
629 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000630 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000632 goto neg_err_exit;
633 }
634
635 if (server->socketUseCount.counter > 1) {
636 if (memcmp(server->server_GUID,
637 pSMBr->u.extended_response.
638 GUID, 16) != 0) {
639 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000640 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000641 pSMBr->u.extended_response.GUID,
642 16);
643 }
644 } else
645 memcpy(server->server_GUID,
646 pSMBr->u.extended_response.GUID, 16);
647
648 if (count == 16) {
649 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000650 } else {
651 rc = decode_negTokenInit(pSMBr->u.extended_response.
652 SecurityBlob,
653 count - 16,
654 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000655 if (rc == 1) {
Jeff Laytone5459372007-11-03 05:11:06 +0000656 rc = 0;
Steve French254e55e2006-06-04 05:53:15 +0000657 } else {
658 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
Steve French254e55e2006-06-04 05:53:15 +0000661 } else
662 server->capabilities &= ~CAP_EXTENDED_SECURITY;
663
Steve French6344a422006-06-12 04:18:35 +0000664#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000665signing_check:
Steve French6344a422006-06-12 04:18:35 +0000666#endif
Steve French762e5ab2007-06-28 18:41:42 +0000667 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
668 /* MUST_SIGN already includes the MAY_SIGN FLAG
669 so if this is zero it means that signing is disabled */
670 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000671 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000672 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000673 "packet signing to be enabled in "
674 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000675 rc = -EOPNOTSUPP;
676 }
Steve French50c2f752007-07-13 00:33:32 +0000677 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000678 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000679 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
680 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000681 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000682 if ((server->secMode &
683 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
684 cERROR(1,
685 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000686 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000687 } else
688 server->secMode |= SECMODE_SIGN_REQUIRED;
689 } else {
690 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000691 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000692 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000693 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Steve French50c2f752007-07-13 00:33:32 +0000695
696neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700697 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000698
Steve French790fe572007-07-07 19:25:05 +0000699 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return rc;
701}
702
703int
704CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
705{
706 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 cFYI(1, ("In tree disconnect"));
710 /*
711 * If last user of the connection and
712 * connection alive - disconnect it
713 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000714 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 * to be freed and kernel thread woken up).
716 */
717 if (tcon)
718 down(&tcon->tconSem);
719 else
720 return -EIO;
721
722 atomic_dec(&tcon->useCount);
723 if (atomic_read(&tcon->useCount) > 0) {
724 up(&tcon->tconSem);
725 return -EBUSY;
726 }
727
Steve French50c2f752007-07-13 00:33:32 +0000728 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000730 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000732 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734
Steve French790fe572007-07-07 19:25:05 +0000735 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 up(&tcon->tconSem);
737 return -EIO;
738 }
Steve French50c2f752007-07-13 00:33:32 +0000739 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700740 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (rc) {
742 up(&tcon->tconSem);
743 return rc;
Steve Frenchcd634992005-04-28 22:41:10 -0700744 }
Steve French133672e2007-11-13 22:41:37 +0000745
746 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700748 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 up(&tcon->tconSem);
751
Steve French50c2f752007-07-13 00:33:32 +0000752 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 closed on server already e.g. due to tcp session crashing */
754 if (rc == -EAGAIN)
755 rc = 0;
756
757 return rc;
758}
759
760int
761CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
762{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 LOGOFF_ANDX_REQ *pSMB;
764 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 cFYI(1, ("In SMBLogoff for session disconnect"));
767 if (ses)
768 down(&ses->sesSem);
769 else
770 return -EIO;
771
772 atomic_dec(&ses->inUse);
773 if (atomic_read(&ses->inUse) > 0) {
774 up(&ses->sesSem);
775 return -EBUSY;
776 }
777 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
778 if (rc) {
779 up(&ses->sesSem);
780 return rc;
781 }
782
Steve French790fe572007-07-07 19:25:05 +0000783 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700784 pSMB->hdr.Mid = GetNextMid(ses->server);
785
Steve French790fe572007-07-07 19:25:05 +0000786 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
788 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
789 }
790
791 pSMB->hdr.Uid = ses->Suid;
792
793 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000794 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (ses->server) {
796 atomic_dec(&ses->server->socketUseCount);
797 if (atomic_read(&ses->server->socketUseCount) == 0) {
798 spin_lock(&GlobalMid_Lock);
799 ses->server->tcpStatus = CifsExiting;
800 spin_unlock(&GlobalMid_Lock);
801 rc = -ESHUTDOWN;
802 }
803 }
Steve Frencha59c6582005-08-17 12:12:19 -0700804 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
806 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000807 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 error */
809 if (rc == -EAGAIN)
810 rc = 0;
811 return rc;
812}
813
814int
Steve French2d785a52007-07-15 01:48:57 +0000815CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
816 __u16 type, const struct nls_table *nls_codepage, int remap)
817{
818 TRANSACTION2_SPI_REQ *pSMB = NULL;
819 TRANSACTION2_SPI_RSP *pSMBr = NULL;
820 struct unlink_psx_rq *pRqD;
821 int name_len;
822 int rc = 0;
823 int bytes_returned = 0;
824 __u16 params, param_offset, offset, byte_count;
825
826 cFYI(1, ("In POSIX delete"));
827PsxDelete:
828 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
829 (void **) &pSMBr);
830 if (rc)
831 return rc;
832
833 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
834 name_len =
835 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
836 PATH_MAX, nls_codepage, remap);
837 name_len++; /* trailing null */
838 name_len *= 2;
839 } else { /* BB add path length overrun check */
840 name_len = strnlen(fileName, PATH_MAX);
841 name_len++; /* trailing null */
842 strncpy(pSMB->FileName, fileName, name_len);
843 }
844
845 params = 6 + name_len;
846 pSMB->MaxParameterCount = cpu_to_le16(2);
847 pSMB->MaxDataCount = 0; /* BB double check this with jra */
848 pSMB->MaxSetupCount = 0;
849 pSMB->Reserved = 0;
850 pSMB->Flags = 0;
851 pSMB->Timeout = 0;
852 pSMB->Reserved2 = 0;
853 param_offset = offsetof(struct smb_com_transaction2_spi_req,
854 InformationLevel) - 4;
855 offset = param_offset + params;
856
857 /* Setup pointer to Request Data (inode type) */
858 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
859 pRqD->type = cpu_to_le16(type);
860 pSMB->ParameterOffset = cpu_to_le16(param_offset);
861 pSMB->DataOffset = cpu_to_le16(offset);
862 pSMB->SetupCount = 1;
863 pSMB->Reserved3 = 0;
864 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
865 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
866
867 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
868 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
869 pSMB->ParameterCount = cpu_to_le16(params);
870 pSMB->TotalParameterCount = pSMB->ParameterCount;
871 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
872 pSMB->Reserved4 = 0;
873 pSMB->hdr.smb_buf_length += byte_count;
874 pSMB->ByteCount = cpu_to_le16(byte_count);
875 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
876 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000877 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000878 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000879 cifs_buf_release(pSMB);
880
881 cifs_stats_inc(&tcon->num_deletes);
882
883 if (rc == -EAGAIN)
884 goto PsxDelete;
885
886 return rc;
887}
888
889int
Steve French737b7582005-04-28 22:41:06 -0700890CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
891 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892{
893 DELETE_FILE_REQ *pSMB = NULL;
894 DELETE_FILE_RSP *pSMBr = NULL;
895 int rc = 0;
896 int bytes_returned;
897 int name_len;
898
899DelFileRetry:
900 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
901 (void **) &pSMBr);
902 if (rc)
903 return rc;
904
905 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
906 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000907 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700908 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 name_len++; /* trailing null */
910 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700911 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 name_len = strnlen(fileName, PATH_MAX);
913 name_len++; /* trailing null */
914 strncpy(pSMB->fileName, fileName, name_len);
915 }
916 pSMB->SearchAttributes =
917 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
918 pSMB->BufferFormat = 0x04;
919 pSMB->hdr.smb_buf_length += name_len + 1;
920 pSMB->ByteCount = cpu_to_le16(name_len + 1);
921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700923 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000924 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927 cifs_buf_release(pSMB);
928 if (rc == -EAGAIN)
929 goto DelFileRetry;
930
931 return rc;
932}
933
934int
Steve French50c2f752007-07-13 00:33:32 +0000935CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700936 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 DELETE_DIRECTORY_REQ *pSMB = NULL;
939 DELETE_DIRECTORY_RSP *pSMBr = NULL;
940 int rc = 0;
941 int bytes_returned;
942 int name_len;
943
944 cFYI(1, ("In CIFSSMBRmDir"));
945RmDirRetry:
946 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
947 (void **) &pSMBr);
948 if (rc)
949 return rc;
950
951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700952 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
953 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 name_len++; /* trailing null */
955 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700956 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 name_len = strnlen(dirName, PATH_MAX);
958 name_len++; /* trailing null */
959 strncpy(pSMB->DirName, dirName, name_len);
960 }
961
962 pSMB->BufferFormat = 0x04;
963 pSMB->hdr.smb_buf_length += name_len + 1;
964 pSMB->ByteCount = cpu_to_le16(name_len + 1);
965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700967 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000968 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
971 cifs_buf_release(pSMB);
972 if (rc == -EAGAIN)
973 goto RmDirRetry;
974 return rc;
975}
976
977int
978CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700979 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980{
981 int rc = 0;
982 CREATE_DIRECTORY_REQ *pSMB = NULL;
983 CREATE_DIRECTORY_RSP *pSMBr = NULL;
984 int bytes_returned;
985 int name_len;
986
987 cFYI(1, ("In CIFSSMBMkDir"));
988MkDirRetry:
989 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
990 (void **) &pSMBr);
991 if (rc)
992 return rc;
993
994 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000995 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700996 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 name_len++; /* trailing null */
998 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700999 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 name_len = strnlen(name, PATH_MAX);
1001 name_len++; /* trailing null */
1002 strncpy(pSMB->DirName, name, name_len);
1003 }
1004
1005 pSMB->BufferFormat = 0x04;
1006 pSMB->hdr.smb_buf_length += name_len + 1;
1007 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001010 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001011 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07001013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 cifs_buf_release(pSMB);
1015 if (rc == -EAGAIN)
1016 goto MkDirRetry;
1017 return rc;
1018}
1019
Steve French2dd29d32007-04-23 22:07:35 +00001020int
1021CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001022 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001023 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001024 const struct nls_table *nls_codepage, int remap)
1025{
1026 TRANSACTION2_SPI_REQ *pSMB = NULL;
1027 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1028 int name_len;
1029 int rc = 0;
1030 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001031 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001032 OPEN_PSX_REQ *pdata;
1033 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001034
1035 cFYI(1, ("In POSIX Create"));
1036PsxCreat:
1037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1038 (void **) &pSMBr);
1039 if (rc)
1040 return rc;
1041
1042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1043 name_len =
1044 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1045 PATH_MAX, nls_codepage, remap);
1046 name_len++; /* trailing null */
1047 name_len *= 2;
1048 } else { /* BB improve the check for buffer overruns BB */
1049 name_len = strnlen(name, PATH_MAX);
1050 name_len++; /* trailing null */
1051 strncpy(pSMB->FileName, name, name_len);
1052 }
1053
1054 params = 6 + name_len;
1055 count = sizeof(OPEN_PSX_REQ);
1056 pSMB->MaxParameterCount = cpu_to_le16(2);
1057 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1058 pSMB->MaxSetupCount = 0;
1059 pSMB->Reserved = 0;
1060 pSMB->Flags = 0;
1061 pSMB->Timeout = 0;
1062 pSMB->Reserved2 = 0;
1063 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001064 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001065 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001066 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001067 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001068 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001069 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001070 pdata->OpenFlags = cpu_to_le32(*pOplock);
1071 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1072 pSMB->DataOffset = cpu_to_le16(offset);
1073 pSMB->SetupCount = 1;
1074 pSMB->Reserved3 = 0;
1075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1076 byte_count = 3 /* pad */ + params + count;
1077
1078 pSMB->DataCount = cpu_to_le16(count);
1079 pSMB->ParameterCount = cpu_to_le16(params);
1080 pSMB->TotalDataCount = pSMB->DataCount;
1081 pSMB->TotalParameterCount = pSMB->ParameterCount;
1082 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1083 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001084 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001085 pSMB->ByteCount = cpu_to_le16(byte_count);
1086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1088 if (rc) {
1089 cFYI(1, ("Posix create returned %d", rc));
1090 goto psx_create_err;
1091 }
1092
Steve French790fe572007-07-07 19:25:05 +00001093 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1095
1096 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1097 rc = -EIO; /* bad smb */
1098 goto psx_create_err;
1099 }
1100
1101 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001102 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001103 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001104
Steve French2dd29d32007-04-23 22:07:35 +00001105 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001106 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001107 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1108 /* Let caller know file was created so we can set the mode. */
1109 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001110 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001111 *pOplock |= CIFS_CREATE_ACTION;
1112 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001113 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1114 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001115 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001116 } else {
Steve French790fe572007-07-07 19:25:05 +00001117 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001118 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001119 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001120 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001121 goto psx_create_err;
1122 }
Steve French50c2f752007-07-13 00:33:32 +00001123 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001124 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001125 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001126 }
Steve French2dd29d32007-04-23 22:07:35 +00001127
1128psx_create_err:
1129 cifs_buf_release(pSMB);
1130
1131 cifs_stats_inc(&tcon->num_mkdirs);
1132
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1135
Steve French50c2f752007-07-13 00:33:32 +00001136 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001137}
1138
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139static __u16 convert_disposition(int disposition)
1140{
1141 __u16 ofun = 0;
1142
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
Steve French790fe572007-07-07 19:25:05 +00001163 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 ofun = SMBOPEN_OAPPEND; /* regular open */
1165 }
1166 return ofun;
1167}
1168
Jeff Layton35fc37d2008-05-14 10:22:03 -07001169static int
1170access_flags_to_smbopen_mode(const int access_flags)
1171{
1172 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1173
1174 if (masked_flags == GENERIC_READ)
1175 return SMBOPEN_READ;
1176 else if (masked_flags == GENERIC_WRITE)
1177 return SMBOPEN_WRITE;
1178
1179 /* just go for read/write */
1180 return SMBOPEN_READWRITE;
1181}
1182
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183int
1184SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1185 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001186 const int access_flags, const int create_options, __u16 *netfid,
1187 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 const struct nls_table *nls_codepage, int remap)
1189{
1190 int rc = -EACCES;
1191 OPENX_REQ *pSMB = NULL;
1192 OPENX_RSP *pSMBr = NULL;
1193 int bytes_returned;
1194 int name_len;
1195 __u16 count;
1196
1197OldOpenRetry:
1198 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1199 (void **) &pSMBr);
1200 if (rc)
1201 return rc;
1202
1203 pSMB->AndXCommand = 0xFF; /* none */
1204
1205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1206 count = 1; /* account for one byte pad to word boundary */
1207 name_len =
1208 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1209 fileName, PATH_MAX, nls_codepage, remap);
1210 name_len++; /* trailing null */
1211 name_len *= 2;
1212 } else { /* BB improve check for buffer overruns BB */
1213 count = 0; /* no pad */
1214 name_len = strnlen(fileName, PATH_MAX);
1215 name_len++; /* trailing null */
1216 strncpy(pSMB->fileName, fileName, name_len);
1217 }
1218 if (*pOplock & REQ_OPLOCK)
1219 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001222
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001224 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1226 /* set file as system file if special file such
1227 as fifo and server expecting SFU style and
1228 no Unix extensions */
1229
Steve French790fe572007-07-07 19:25:05 +00001230 if (create_options & CREATE_OPTION_SPECIAL)
1231 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001232 else /* BB FIXME BB */
1233 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
Jeff Layton67750fb2008-05-09 22:28:02 +00001235 if (create_options & CREATE_OPTION_READONLY)
1236 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237
1238 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001239/* pSMB->CreateOptions = cpu_to_le32(create_options &
1240 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001242
1243 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001244 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 count += name_len;
1246 pSMB->hdr.smb_buf_length += count;
1247
1248 pSMB->ByteCount = cpu_to_le16(count);
1249 /* long_op set to 1 to allow for oplock break timeouts */
1250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001251 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 cifs_stats_inc(&tcon->num_opens);
1253 if (rc) {
1254 cFYI(1, ("Error in Open = %d", rc));
1255 } else {
1256 /* BB verify if wct == 15 */
1257
Steve French582d21e2008-05-13 04:54:12 +00001258/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259
1260 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1261 /* Let caller know file was created so we can set the mode. */
1262 /* Do we care about the CreateAction in any other cases? */
1263 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001264/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 *pOplock |= CIFS_CREATE_ACTION; */
1266 /* BB FIXME END */
1267
Steve French790fe572007-07-07 19:25:05 +00001268 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1270 pfile_info->LastAccessTime = 0; /* BB fixme */
1271 pfile_info->LastWriteTime = 0; /* BB fixme */
1272 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001273 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001274 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001276 pfile_info->AllocationSize =
1277 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1278 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 pfile_info->NumberOfLinks = cpu_to_le32(1);
1280 }
1281 }
1282
1283 cifs_buf_release(pSMB);
1284 if (rc == -EAGAIN)
1285 goto OldOpenRetry;
1286 return rc;
1287}
1288
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289int
1290CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1291 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001292 const int access_flags, const int create_options, __u16 *netfid,
1293 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001294 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
1296 int rc = -EACCES;
1297 OPEN_REQ *pSMB = NULL;
1298 OPEN_RSP *pSMBr = NULL;
1299 int bytes_returned;
1300 int name_len;
1301 __u16 count;
1302
1303openRetry:
1304 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1305 (void **) &pSMBr);
1306 if (rc)
1307 return rc;
1308
1309 pSMB->AndXCommand = 0xFF; /* none */
1310
1311 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1312 count = 1; /* account for one byte pad to word boundary */
1313 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001314 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001315 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 name_len++; /* trailing null */
1317 name_len *= 2;
1318 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001319 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 count = 0; /* no pad */
1321 name_len = strnlen(fileName, PATH_MAX);
1322 name_len++; /* trailing null */
1323 pSMB->NameLength = cpu_to_le16(name_len);
1324 strncpy(pSMB->fileName, fileName, name_len);
1325 }
1326 if (*pOplock & REQ_OPLOCK)
1327 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001328 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1331 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001332 /* set file as system file if special file such
1333 as fifo and server expecting SFU style and
1334 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001335 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001336 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1337 else
1338 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 /* XP does not handle ATTR_POSIX_SEMANTICS */
1341 /* but it helps speed up case sensitive checks for other
1342 servers such as Samba */
1343 if (tcon->ses->capabilities & CAP_UNIX)
1344 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1345
Jeff Layton67750fb2008-05-09 22:28:02 +00001346 if (create_options & CREATE_OPTION_READONLY)
1347 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1348
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1350 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001351 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001352 /* BB Expirement with various impersonation levels and verify */
1353 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pSMB->SecurityFlags =
1355 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1356
1357 count += name_len;
1358 pSMB->hdr.smb_buf_length += count;
1359
1360 pSMB->ByteCount = cpu_to_le16(count);
1361 /* long_op set to 1 to allow for oplock break timeouts */
1362 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001363 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001364 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (rc) {
1366 cFYI(1, ("Error in Open = %d", rc));
1367 } else {
Steve French09d1db52005-04-28 22:41:08 -07001368 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1370 /* Let caller know file was created so we can set the mode. */
1371 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001372 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001373 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001374 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001375 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 36 /* CreationTime to Attributes */);
1377 /* the file_info buf is endian converted by caller */
1378 pfile_info->AllocationSize = pSMBr->AllocationSize;
1379 pfile_info->EndOfFile = pSMBr->EndOfFile;
1380 pfile_info->NumberOfLinks = cpu_to_le32(1);
1381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 cifs_buf_release(pSMB);
1385 if (rc == -EAGAIN)
1386 goto openRetry;
1387 return rc;
1388}
1389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390int
Steve French50c2f752007-07-13 00:33:32 +00001391CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1392 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1393 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
1395 int rc = -EACCES;
1396 READ_REQ *pSMB = NULL;
1397 READ_RSP *pSMBr = NULL;
1398 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001399 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001400 int resp_buf_type = 0;
1401 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Steve French790fe572007-07-07 19:25:05 +00001403 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1404 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001405 wct = 12;
1406 else
1407 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
1409 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001410 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if (rc)
1412 return rc;
1413
1414 /* tcon and ses pointer are checked in smb_init */
1415 if (tcon->ses->server == NULL)
1416 return -ECONNABORTED;
1417
Steve Frenchec637e32005-12-12 20:53:18 -08001418 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 pSMB->Fid = netfid;
1420 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001421 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001422 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001423 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001424 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001425
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 pSMB->Remaining = 0;
1427 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1428 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001429 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001430 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1431 else {
1432 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001433 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001434 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001435 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001436 }
Steve Frenchec637e32005-12-12 20:53:18 -08001437
1438 iov[0].iov_base = (char *)pSMB;
1439 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001440 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001441 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001442 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001443 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 if (rc) {
1445 cERROR(1, ("Send error in read = %d", rc));
1446 } else {
1447 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1448 data_length = data_length << 16;
1449 data_length += le16_to_cpu(pSMBr->DataLength);
1450 *nbytes = data_length;
1451
1452 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001453 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001455 cFYI(1, ("bad length %d for count %d",
1456 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 rc = -EIO;
1458 *nbytes = 0;
1459 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001460 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001461 le16_to_cpu(pSMBr->DataOffset);
1462/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001463 cERROR(1,("Faulting on read rc = %d",rc));
1464 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001465 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001466 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001467 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
1469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
Steve French4b8f9302006-02-26 16:41:18 +00001471/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001472 if (*buf) {
1473 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001474 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001475 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001476 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001477 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001478 /* return buffer to caller to free */
1479 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001480 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001481 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001482 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001483 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001484 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001485
1486 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 since file handle passed in no longer valid */
1488 return rc;
1489}
1490
Steve Frenchec637e32005-12-12 20:53:18 -08001491
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492int
1493CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1494 const int netfid, const unsigned int count,
1495 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001496 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497{
1498 int rc = -EACCES;
1499 WRITE_REQ *pSMB = NULL;
1500 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001501 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 __u32 bytes_sent;
1503 __u16 byte_count;
1504
1505 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001506 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001507 return -ECONNABORTED;
1508
Steve French790fe572007-07-07 19:25:05 +00001509 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001510 wct = 14;
1511 else
1512 wct = 12;
1513
1514 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 (void **) &pSMBr);
1516 if (rc)
1517 return rc;
1518 /* tcon and ses pointer are checked in smb_init */
1519 if (tcon->ses->server == NULL)
1520 return -ECONNABORTED;
1521
1522 pSMB->AndXCommand = 0xFF; /* none */
1523 pSMB->Fid = netfid;
1524 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001525 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001526 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001527 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001528 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 pSMB->Reserved = 0xFFFFFFFF;
1531 pSMB->WriteMode = 0;
1532 pSMB->Remaining = 0;
1533
Steve French50c2f752007-07-13 00:33:32 +00001534 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 can send more if LARGE_WRITE_X capability returned by the server and if
1536 our buffer is big enough or if we convert to iovecs on socket writes
1537 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001538 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1540 } else {
1541 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1542 & ~0xFF;
1543 }
1544
1545 if (bytes_sent > count)
1546 bytes_sent = count;
1547 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001548 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001549 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001550 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001551 else if (ubuf) {
1552 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 cifs_buf_release(pSMB);
1554 return -EFAULT;
1555 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 /* No buffer */
1558 cifs_buf_release(pSMB);
1559 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001560 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001561 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001562 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001563 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001565
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1567 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001568 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001569
Steve French790fe572007-07-07 19:25:05 +00001570 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001571 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001572 else { /* old style write has byte count 4 bytes earlier
1573 so 4 bytes pad */
1574 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001575 (struct smb_com_writex_req *)pSMB;
1576 pSMBW->ByteCount = cpu_to_le16(byte_count);
1577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
1579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1580 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001581 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 if (rc) {
1583 cFYI(1, ("Send error in write = %d", rc));
1584 *nbytes = 0;
1585 } else {
1586 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1587 *nbytes = (*nbytes) << 16;
1588 *nbytes += le16_to_cpu(pSMBr->Count);
1589 }
1590
1591 cifs_buf_release(pSMB);
1592
Steve French50c2f752007-07-13 00:33:32 +00001593 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 since file handle passed in no longer valid */
1595
1596 return rc;
1597}
1598
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001599int
1600CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001602 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1603 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604{
1605 int rc = -EACCES;
1606 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001607 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001608 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001609 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
Steve French790fe572007-07-07 19:25:05 +00001611 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001612
Steve French790fe572007-07-07 19:25:05 +00001613 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001614 wct = 14;
1615 else
1616 wct = 12;
1617 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if (rc)
1619 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 /* tcon and ses pointer are checked in smb_init */
1621 if (tcon->ses->server == NULL)
1622 return -ECONNABORTED;
1623
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001624 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 pSMB->Fid = netfid;
1626 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001627 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001628 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001629 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001630 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 pSMB->Reserved = 0xFFFFFFFF;
1632 pSMB->WriteMode = 0;
1633 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001636 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
Steve French3e844692005-10-03 13:37:24 -07001638 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1639 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001640 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001641 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001642 pSMB->hdr.smb_buf_length += count+1;
1643 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001644 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1645 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001646 pSMB->ByteCount = cpu_to_le16(count + 1);
1647 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001648 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001649 (struct smb_com_writex_req *)pSMB;
1650 pSMBW->ByteCount = cpu_to_le16(count + 5);
1651 }
Steve French3e844692005-10-03 13:37:24 -07001652 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001653 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001654 iov[0].iov_len = smb_hdr_len + 4;
1655 else /* wct == 12 pad bigger by four bytes */
1656 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001657
Steve French3e844692005-10-03 13:37:24 -07001658
Steve Frenchec637e32005-12-12 20:53:18 -08001659 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001660 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001661 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001663 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001665 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001666 /* presumably this can not happen, but best to be safe */
1667 rc = -EIO;
1668 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001669 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001670 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001671 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1672 *nbytes = (*nbytes) << 16;
1673 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
Steve French4b8f9302006-02-26 16:41:18 +00001676/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001677 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001678 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001679 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001680 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
Steve French50c2f752007-07-13 00:33:32 +00001682 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 since file handle passed in no longer valid */
1684
1685 return rc;
1686}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001687
1688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689int
1690CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1691 const __u16 smb_file_id, const __u64 len,
1692 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001693 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
1695 int rc = 0;
1696 LOCK_REQ *pSMB = NULL;
1697 LOCK_RSP *pSMBr = NULL;
1698 int bytes_returned;
1699 int timeout = 0;
1700 __u16 count;
1701
Steve French4b18f2a2008-04-29 00:06:05 +00001702 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001703 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 if (rc)
1706 return rc;
1707
Steve French46810cb2005-04-28 22:41:09 -07001708 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1709
Steve French790fe572007-07-07 19:25:05 +00001710 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001711 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001713 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001714 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1716 } else {
1717 pSMB->Timeout = 0;
1718 }
1719
1720 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1721 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1722 pSMB->LockType = lockType;
1723 pSMB->AndXCommand = 0xFF; /* none */
1724 pSMB->Fid = smb_file_id; /* netfid stays le */
1725
Steve French790fe572007-07-07 19:25:05 +00001726 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1728 /* BB where to store pid high? */
1729 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1730 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1731 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1732 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1733 count = sizeof(LOCKING_ANDX_RANGE);
1734 } else {
1735 /* oplock break */
1736 count = 0;
1737 }
1738 pSMB->hdr.smb_buf_length += count;
1739 pSMB->ByteCount = cpu_to_le16(count);
1740
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001741 if (waitFlag) {
1742 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1743 (struct smb_hdr *) pSMBr, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001744 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001745 } else {
Steve French133672e2007-11-13 22:41:37 +00001746 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1747 timeout);
1748 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001749 }
Steve Frencha4544342005-08-24 13:59:35 -07001750 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001751 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Steve French50c2f752007-07-13 00:33:32 +00001754 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 since file handle passed in no longer valid */
1756 return rc;
1757}
1758
1759int
Steve French08547b02006-02-28 22:39:25 +00001760CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1761 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001762 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001763 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001764{
1765 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1766 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001767 struct cifs_posix_lock *parm_data;
1768 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001769 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001770 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001771 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001772 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001773 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001774
1775 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001776
Steve French790fe572007-07-07 19:25:05 +00001777 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001778 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001779
Steve French08547b02006-02-28 22:39:25 +00001780 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1781
1782 if (rc)
1783 return rc;
1784
1785 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1786
Steve French50c2f752007-07-13 00:33:32 +00001787 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001788 pSMB->MaxSetupCount = 0;
1789 pSMB->Reserved = 0;
1790 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001791 pSMB->Reserved2 = 0;
1792 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1793 offset = param_offset + params;
1794
Steve French08547b02006-02-28 22:39:25 +00001795 count = sizeof(struct cifs_posix_lock);
1796 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001797 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001798 pSMB->SetupCount = 1;
1799 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001800 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001801 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1802 else
1803 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1804 byte_count = 3 /* pad */ + params + count;
1805 pSMB->DataCount = cpu_to_le16(count);
1806 pSMB->ParameterCount = cpu_to_le16(params);
1807 pSMB->TotalDataCount = pSMB->DataCount;
1808 pSMB->TotalParameterCount = pSMB->ParameterCount;
1809 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001810 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001811 (((char *) &pSMB->hdr.Protocol) + offset);
1812
1813 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001814 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001815 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001816 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001817 pSMB->Timeout = cpu_to_le32(-1);
1818 } else
1819 pSMB->Timeout = 0;
1820
Steve French08547b02006-02-28 22:39:25 +00001821 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001822 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001823 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001824
1825 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001826 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001827 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1828 pSMB->Reserved4 = 0;
1829 pSMB->hdr.smb_buf_length += byte_count;
1830 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001831 if (waitFlag) {
1832 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1833 (struct smb_hdr *) pSMBr, &bytes_returned);
1834 } else {
Steve French133672e2007-11-13 22:41:37 +00001835 iov[0].iov_base = (char *)pSMB;
1836 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1837 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1838 &resp_buf_type, timeout);
1839 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1840 not try to free it twice below on exit */
1841 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001842 }
1843
Steve French08547b02006-02-28 22:39:25 +00001844 if (rc) {
1845 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001846 } else if (get_flag) {
1847 /* lock structure can be returned on get */
1848 __u16 data_offset;
1849 __u16 data_count;
1850 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001851
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001852 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1853 rc = -EIO; /* bad smb */
1854 goto plk_err_exit;
1855 }
Steve French790fe572007-07-07 19:25:05 +00001856 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001857 rc = -EINVAL;
1858 goto plk_err_exit;
1859 }
1860 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1861 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001862 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001863 rc = -EIO;
1864 goto plk_err_exit;
1865 }
1866 parm_data = (struct cifs_posix_lock *)
1867 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001868 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001869 pLockData->fl_type = F_UNLCK;
1870 }
Steve French50c2f752007-07-13 00:33:32 +00001871
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001872plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001873 if (pSMB)
1874 cifs_small_buf_release(pSMB);
1875
Steve French133672e2007-11-13 22:41:37 +00001876 if (resp_buf_type == CIFS_SMALL_BUFFER)
1877 cifs_small_buf_release(iov[0].iov_base);
1878 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1879 cifs_buf_release(iov[0].iov_base);
1880
Steve French08547b02006-02-28 22:39:25 +00001881 /* Note: On -EAGAIN error only caller can retry on handle based calls
1882 since file handle passed in no longer valid */
1883
1884 return rc;
1885}
1886
1887
1888int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1890{
1891 int rc = 0;
1892 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 cFYI(1, ("In CIFSSMBClose"));
1894
1895/* do not retry on dead session on close */
1896 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001897 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 return 0;
1899 if (rc)
1900 return rc;
1901
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001903 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001905 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001906 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001908 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 /* EINTR is expected when user ctl-c to kill app */
1910 cERROR(1, ("Send error in Close = %d", rc));
1911 }
1912 }
1913
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001915 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 rc = 0;
1917
1918 return rc;
1919}
1920
1921int
1922CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1923 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001924 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925{
1926 int rc = 0;
1927 RENAME_REQ *pSMB = NULL;
1928 RENAME_RSP *pSMBr = NULL;
1929 int bytes_returned;
1930 int name_len, name_len2;
1931 __u16 count;
1932
1933 cFYI(1, ("In CIFSSMBRename"));
1934renameRetry:
1935 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1936 (void **) &pSMBr);
1937 if (rc)
1938 return rc;
1939
1940 pSMB->BufferFormat = 0x04;
1941 pSMB->SearchAttributes =
1942 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1943 ATTR_DIRECTORY);
1944
1945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1946 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001947 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001948 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 name_len++; /* trailing null */
1950 name_len *= 2;
1951 pSMB->OldFileName[name_len] = 0x04; /* pad */
1952 /* protocol requires ASCII signature byte on Unicode string */
1953 pSMB->OldFileName[name_len + 1] = 0x00;
1954 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001955 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001956 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1958 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001959 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 name_len = strnlen(fromName, PATH_MAX);
1961 name_len++; /* trailing null */
1962 strncpy(pSMB->OldFileName, fromName, name_len);
1963 name_len2 = strnlen(toName, PATH_MAX);
1964 name_len2++; /* trailing null */
1965 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1966 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1967 name_len2++; /* trailing null */
1968 name_len2++; /* signature byte */
1969 }
1970
1971 count = 1 /* 1st signature byte */ + name_len + name_len2;
1972 pSMB->hdr.smb_buf_length += count;
1973 pSMB->ByteCount = cpu_to_le16(count);
1974
1975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001977 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001978 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 cifs_buf_release(pSMB);
1982
1983 if (rc == -EAGAIN)
1984 goto renameRetry;
1985
1986 return rc;
1987}
1988
Steve French50c2f752007-07-13 00:33:32 +00001989int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1990 int netfid, char *target_name,
1991 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992{
1993 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1994 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001995 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 char *data_offset;
1997 char dummy_string[30];
1998 int rc = 0;
1999 int bytes_returned = 0;
2000 int len_of_str;
2001 __u16 params, param_offset, offset, count, byte_count;
2002
2003 cFYI(1, ("Rename to File by handle"));
2004 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2005 (void **) &pSMBr);
2006 if (rc)
2007 return rc;
2008
2009 params = 6;
2010 pSMB->MaxSetupCount = 0;
2011 pSMB->Reserved = 0;
2012 pSMB->Flags = 0;
2013 pSMB->Timeout = 0;
2014 pSMB->Reserved2 = 0;
2015 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2016 offset = param_offset + params;
2017
2018 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2019 rename_info = (struct set_file_rename *) data_offset;
2020 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002021 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 pSMB->SetupCount = 1;
2023 pSMB->Reserved3 = 0;
2024 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2025 byte_count = 3 /* pad */ + params;
2026 pSMB->ParameterCount = cpu_to_le16(params);
2027 pSMB->TotalParameterCount = pSMB->ParameterCount;
2028 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2029 pSMB->DataOffset = cpu_to_le16(offset);
2030 /* construct random name ".cifs_tmp<inodenum><mid>" */
2031 rename_info->overwrite = cpu_to_le32(1);
2032 rename_info->root_fid = 0;
2033 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002034 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002035 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2036 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002037 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002039 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002040 target_name, PATH_MAX, nls_codepage,
2041 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2044 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2045 byte_count += count;
2046 pSMB->DataCount = cpu_to_le16(count);
2047 pSMB->TotalDataCount = pSMB->DataCount;
2048 pSMB->Fid = netfid;
2049 pSMB->InformationLevel =
2050 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2051 pSMB->Reserved4 = 0;
2052 pSMB->hdr.smb_buf_length += byte_count;
2053 pSMB->ByteCount = cpu_to_le16(byte_count);
2054 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002056 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002057 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002058 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002059
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 cifs_buf_release(pSMB);
2061
2062 /* Note: On -EAGAIN error only caller can retry on handle based calls
2063 since file handle passed in no longer valid */
2064
2065 return rc;
2066}
2067
2068int
Steve French50c2f752007-07-13 00:33:32 +00002069CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2070 const __u16 target_tid, const char *toName, const int flags,
2071 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072{
2073 int rc = 0;
2074 COPY_REQ *pSMB = NULL;
2075 COPY_RSP *pSMBr = NULL;
2076 int bytes_returned;
2077 int name_len, name_len2;
2078 __u16 count;
2079
2080 cFYI(1, ("In CIFSSMBCopy"));
2081copyRetry:
2082 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2083 (void **) &pSMBr);
2084 if (rc)
2085 return rc;
2086
2087 pSMB->BufferFormat = 0x04;
2088 pSMB->Tid2 = target_tid;
2089
2090 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2091
2092 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002093 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002094 fromName, PATH_MAX, nls_codepage,
2095 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 name_len++; /* trailing null */
2097 name_len *= 2;
2098 pSMB->OldFileName[name_len] = 0x04; /* pad */
2099 /* protocol requires ASCII signature byte on Unicode string */
2100 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002101 name_len2 =
2102 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002103 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2105 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002106 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 name_len = strnlen(fromName, PATH_MAX);
2108 name_len++; /* trailing null */
2109 strncpy(pSMB->OldFileName, fromName, name_len);
2110 name_len2 = strnlen(toName, PATH_MAX);
2111 name_len2++; /* trailing null */
2112 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2113 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2114 name_len2++; /* trailing null */
2115 name_len2++; /* signature byte */
2116 }
2117
2118 count = 1 /* 1st signature byte */ + name_len + name_len2;
2119 pSMB->hdr.smb_buf_length += count;
2120 pSMB->ByteCount = cpu_to_le16(count);
2121
2122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2124 if (rc) {
2125 cFYI(1, ("Send error in copy = %d with %d files copied",
2126 rc, le16_to_cpu(pSMBr->CopyCount)));
2127 }
2128 if (pSMB)
2129 cifs_buf_release(pSMB);
2130
2131 if (rc == -EAGAIN)
2132 goto copyRetry;
2133
2134 return rc;
2135}
2136
2137int
2138CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2139 const char *fromName, const char *toName,
2140 const struct nls_table *nls_codepage)
2141{
2142 TRANSACTION2_SPI_REQ *pSMB = NULL;
2143 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2144 char *data_offset;
2145 int name_len;
2146 int name_len_target;
2147 int rc = 0;
2148 int bytes_returned = 0;
2149 __u16 params, param_offset, offset, byte_count;
2150
2151 cFYI(1, ("In Symlink Unix style"));
2152createSymLinkRetry:
2153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154 (void **) &pSMBr);
2155 if (rc)
2156 return rc;
2157
2158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2159 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002160 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 /* find define for this maxpathcomponent */
2162 , nls_codepage);
2163 name_len++; /* trailing null */
2164 name_len *= 2;
2165
Steve French50c2f752007-07-13 00:33:32 +00002166 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 name_len = strnlen(fromName, PATH_MAX);
2168 name_len++; /* trailing null */
2169 strncpy(pSMB->FileName, fromName, name_len);
2170 }
2171 params = 6 + name_len;
2172 pSMB->MaxSetupCount = 0;
2173 pSMB->Reserved = 0;
2174 pSMB->Flags = 0;
2175 pSMB->Timeout = 0;
2176 pSMB->Reserved2 = 0;
2177 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002178 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 offset = param_offset + params;
2180
2181 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2183 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002184 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 /* find define for this maxpathcomponent */
2186 , nls_codepage);
2187 name_len_target++; /* trailing null */
2188 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002189 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 name_len_target = strnlen(toName, PATH_MAX);
2191 name_len_target++; /* trailing null */
2192 strncpy(data_offset, toName, name_len_target);
2193 }
2194
2195 pSMB->MaxParameterCount = cpu_to_le16(2);
2196 /* BB find exact max on data count below from sess */
2197 pSMB->MaxDataCount = cpu_to_le16(1000);
2198 pSMB->SetupCount = 1;
2199 pSMB->Reserved3 = 0;
2200 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2201 byte_count = 3 /* pad */ + params + name_len_target;
2202 pSMB->DataCount = cpu_to_le16(name_len_target);
2203 pSMB->ParameterCount = cpu_to_le16(params);
2204 pSMB->TotalDataCount = pSMB->DataCount;
2205 pSMB->TotalParameterCount = pSMB->ParameterCount;
2206 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2207 pSMB->DataOffset = cpu_to_le16(offset);
2208 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2209 pSMB->Reserved4 = 0;
2210 pSMB->hdr.smb_buf_length += byte_count;
2211 pSMB->ByteCount = cpu_to_le16(byte_count);
2212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002214 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002215 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002216 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
2218 if (pSMB)
2219 cifs_buf_release(pSMB);
2220
2221 if (rc == -EAGAIN)
2222 goto createSymLinkRetry;
2223
2224 return rc;
2225}
2226
2227int
2228CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2229 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002230 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231{
2232 TRANSACTION2_SPI_REQ *pSMB = NULL;
2233 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2234 char *data_offset;
2235 int name_len;
2236 int name_len_target;
2237 int rc = 0;
2238 int bytes_returned = 0;
2239 __u16 params, param_offset, offset, byte_count;
2240
2241 cFYI(1, ("In Create Hard link Unix style"));
2242createHardLinkRetry:
2243 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2244 (void **) &pSMBr);
2245 if (rc)
2246 return rc;
2247
2248 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002249 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002250 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 name_len++; /* trailing null */
2252 name_len *= 2;
2253
Steve French50c2f752007-07-13 00:33:32 +00002254 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 name_len = strnlen(toName, PATH_MAX);
2256 name_len++; /* trailing null */
2257 strncpy(pSMB->FileName, toName, name_len);
2258 }
2259 params = 6 + name_len;
2260 pSMB->MaxSetupCount = 0;
2261 pSMB->Reserved = 0;
2262 pSMB->Flags = 0;
2263 pSMB->Timeout = 0;
2264 pSMB->Reserved2 = 0;
2265 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002266 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 offset = param_offset + params;
2268
2269 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002272 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002273 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 name_len_target++; /* trailing null */
2275 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002276 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 name_len_target = strnlen(fromName, PATH_MAX);
2278 name_len_target++; /* trailing null */
2279 strncpy(data_offset, fromName, name_len_target);
2280 }
2281
2282 pSMB->MaxParameterCount = cpu_to_le16(2);
2283 /* BB find exact max on data count below from sess*/
2284 pSMB->MaxDataCount = cpu_to_le16(1000);
2285 pSMB->SetupCount = 1;
2286 pSMB->Reserved3 = 0;
2287 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2288 byte_count = 3 /* pad */ + params + name_len_target;
2289 pSMB->ParameterCount = cpu_to_le16(params);
2290 pSMB->TotalParameterCount = pSMB->ParameterCount;
2291 pSMB->DataCount = cpu_to_le16(name_len_target);
2292 pSMB->TotalDataCount = pSMB->DataCount;
2293 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2294 pSMB->DataOffset = cpu_to_le16(offset);
2295 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2296 pSMB->Reserved4 = 0;
2297 pSMB->hdr.smb_buf_length += byte_count;
2298 pSMB->ByteCount = cpu_to_le16(byte_count);
2299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002301 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002302 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
2305 cifs_buf_release(pSMB);
2306 if (rc == -EAGAIN)
2307 goto createHardLinkRetry;
2308
2309 return rc;
2310}
2311
2312int
2313CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2314 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002315 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316{
2317 int rc = 0;
2318 NT_RENAME_REQ *pSMB = NULL;
2319 RENAME_RSP *pSMBr = NULL;
2320 int bytes_returned;
2321 int name_len, name_len2;
2322 __u16 count;
2323
2324 cFYI(1, ("In CIFSCreateHardLink"));
2325winCreateHardLinkRetry:
2326
2327 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2328 (void **) &pSMBr);
2329 if (rc)
2330 return rc;
2331
2332 pSMB->SearchAttributes =
2333 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2334 ATTR_DIRECTORY);
2335 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2336 pSMB->ClusterCount = 0;
2337
2338 pSMB->BufferFormat = 0x04;
2339
2340 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2341 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002342 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002343 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 name_len++; /* trailing null */
2345 name_len *= 2;
2346 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002347 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002349 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002350 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2352 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002353 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 name_len = strnlen(fromName, PATH_MAX);
2355 name_len++; /* trailing null */
2356 strncpy(pSMB->OldFileName, fromName, name_len);
2357 name_len2 = strnlen(toName, PATH_MAX);
2358 name_len2++; /* trailing null */
2359 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2360 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2361 name_len2++; /* trailing null */
2362 name_len2++; /* signature byte */
2363 }
2364
2365 count = 1 /* string type byte */ + name_len + name_len2;
2366 pSMB->hdr.smb_buf_length += count;
2367 pSMB->ByteCount = cpu_to_le16(count);
2368
2369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002371 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002372 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002374
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 cifs_buf_release(pSMB);
2376 if (rc == -EAGAIN)
2377 goto winCreateHardLinkRetry;
2378
2379 return rc;
2380}
2381
2382int
2383CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2384 const unsigned char *searchName,
2385 char *symlinkinfo, const int buflen,
2386 const struct nls_table *nls_codepage)
2387{
2388/* SMB_QUERY_FILE_UNIX_LINK */
2389 TRANSACTION2_QPI_REQ *pSMB = NULL;
2390 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2391 int rc = 0;
2392 int bytes_returned;
2393 int name_len;
2394 __u16 params, byte_count;
2395
2396 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2397
2398querySymLinkRetry:
2399 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2400 (void **) &pSMBr);
2401 if (rc)
2402 return rc;
2403
2404 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2405 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002406 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2407 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 name_len++; /* trailing null */
2409 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002410 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 name_len = strnlen(searchName, PATH_MAX);
2412 name_len++; /* trailing null */
2413 strncpy(pSMB->FileName, searchName, name_len);
2414 }
2415
2416 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2417 pSMB->TotalDataCount = 0;
2418 pSMB->MaxParameterCount = cpu_to_le16(2);
2419 /* BB find exact max data count below from sess structure BB */
2420 pSMB->MaxDataCount = cpu_to_le16(4000);
2421 pSMB->MaxSetupCount = 0;
2422 pSMB->Reserved = 0;
2423 pSMB->Flags = 0;
2424 pSMB->Timeout = 0;
2425 pSMB->Reserved2 = 0;
2426 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002427 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 pSMB->DataCount = 0;
2429 pSMB->DataOffset = 0;
2430 pSMB->SetupCount = 1;
2431 pSMB->Reserved3 = 0;
2432 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2433 byte_count = params + 1 /* pad */ ;
2434 pSMB->TotalParameterCount = cpu_to_le16(params);
2435 pSMB->ParameterCount = pSMB->TotalParameterCount;
2436 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2437 pSMB->Reserved4 = 0;
2438 pSMB->hdr.smb_buf_length += byte_count;
2439 pSMB->ByteCount = cpu_to_le16(byte_count);
2440
2441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2443 if (rc) {
2444 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2445 } else {
2446 /* decode response */
2447
2448 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2449 if (rc || (pSMBr->ByteCount < 2))
2450 /* BB also check enough total bytes returned */
2451 rc = -EIO; /* bad smb */
2452 else {
2453 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2454 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2455
2456 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2457 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002458 &pSMBr->hdr.Protocol + data_offset),
2459 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002460 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002462 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2463 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 name_len, nls_codepage);
2465 } else {
2466 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002467 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 data_offset,
2469 min_t(const int, buflen, count));
2470 }
2471 symlinkinfo[buflen] = 0;
2472 /* just in case so calling code does not go off the end of buffer */
2473 }
2474 }
2475 cifs_buf_release(pSMB);
2476 if (rc == -EAGAIN)
2477 goto querySymLinkRetry;
2478 return rc;
2479}
2480
Parag Warudkarc9489772007-10-23 18:09:48 +00002481#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002482/* Initialize NT TRANSACT SMB into small smb request buffer.
2483 This assumes that all NT TRANSACTS that we init here have
2484 total parm and data under about 400 bytes (to fit in small cifs
2485 buffer size), which is the case so far, it easily fits. NB:
2486 Setup words themselves and ByteCount
2487 MaxSetupCount (size of returned setup area) and
2488 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002489static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002490smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002491 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002492 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002493{
2494 int rc;
2495 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002496 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002497
2498 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2499 (void **)&pSMB);
2500 if (rc)
2501 return rc;
2502 *ret_buf = (void *)pSMB;
2503 pSMB->Reserved = 0;
2504 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2505 pSMB->TotalDataCount = 0;
2506 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2507 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2508 pSMB->ParameterCount = pSMB->TotalParameterCount;
2509 pSMB->DataCount = pSMB->TotalDataCount;
2510 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2511 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2512 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2513 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2514 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2515 pSMB->SubCommand = cpu_to_le16(sub_command);
2516 return 0;
2517}
2518
2519static int
Steve French50c2f752007-07-13 00:33:32 +00002520validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002521 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002522{
Steve French50c2f752007-07-13 00:33:32 +00002523 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002524 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002525 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002526
Steve French630f3f02007-10-25 21:17:17 +00002527 *pdatalen = 0;
2528 *pparmlen = 0;
2529
Steve French790fe572007-07-07 19:25:05 +00002530 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002531 return -EINVAL;
2532
2533 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2534
2535 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002536 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002537 (char *)&pSMBr->ByteCount;
2538
Steve French0a4b92c2006-01-12 15:44:21 -08002539 data_offset = le32_to_cpu(pSMBr->DataOffset);
2540 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002541 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002542 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2543
2544 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2545 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2546
2547 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002548 if (*ppparm > end_of_smb) {
2549 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002550 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002551 } else if (parm_count + *ppparm > end_of_smb) {
2552 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002553 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002554 } else if (*ppdata > end_of_smb) {
2555 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002556 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002557 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002558 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002559 *ppdata, data_count, (data_count + *ppdata),
2560 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002561 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002562 } else if (parm_count + data_count > pSMBr->ByteCount) {
2563 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002564 return -EINVAL;
2565 }
Steve French630f3f02007-10-25 21:17:17 +00002566 *pdatalen = data_count;
2567 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002568 return 0;
2569}
Parag Warudkarc9489772007-10-23 18:09:48 +00002570#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002571
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572int
2573CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2574 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002575 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 const struct nls_table *nls_codepage)
2577{
2578 int rc = 0;
2579 int bytes_returned;
2580 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002581 struct smb_com_transaction_ioctl_req *pSMB;
2582 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2585 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2586 (void **) &pSMBr);
2587 if (rc)
2588 return rc;
2589
2590 pSMB->TotalParameterCount = 0 ;
2591 pSMB->TotalDataCount = 0;
2592 pSMB->MaxParameterCount = cpu_to_le32(2);
2593 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002594 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2595 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 pSMB->MaxSetupCount = 4;
2597 pSMB->Reserved = 0;
2598 pSMB->ParameterOffset = 0;
2599 pSMB->DataCount = 0;
2600 pSMB->DataOffset = 0;
2601 pSMB->SetupCount = 4;
2602 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2603 pSMB->ParameterCount = pSMB->TotalParameterCount;
2604 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2605 pSMB->IsFsctl = 1; /* FSCTL */
2606 pSMB->IsRootFlag = 0;
2607 pSMB->Fid = fid; /* file handle always le */
2608 pSMB->ByteCount = 0;
2609
2610 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2611 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2612 if (rc) {
2613 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2614 } else { /* decode response */
2615 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2616 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2617 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2618 /* BB also check enough total bytes returned */
2619 rc = -EIO; /* bad smb */
2620 else {
Steve French790fe572007-07-07 19:25:05 +00002621 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002622 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002623 pSMBr->ByteCount +
2624 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
Steve French50c2f752007-07-13 00:33:32 +00002626 struct reparse_data *reparse_buf =
2627 (struct reparse_data *)
2628 ((char *)&pSMBr->hdr.Protocol
2629 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002630 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 rc = -EIO;
2632 goto qreparse_out;
2633 }
Steve French790fe572007-07-07 19:25:05 +00002634 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 reparse_buf->TargetNameOffset +
2636 reparse_buf->TargetNameLen) >
2637 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002638 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 rc = -EIO;
2640 goto qreparse_out;
2641 }
Steve French50c2f752007-07-13 00:33:32 +00002642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2644 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002645 (reparse_buf->LinkNamesBuf +
2646 reparse_buf->TargetNameOffset),
2647 min(buflen/2,
2648 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002650 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 reparse_buf->TargetNameOffset),
2652 name_len, nls_codepage);
2653 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002654 strncpy(symlinkinfo,
2655 reparse_buf->LinkNamesBuf +
2656 reparse_buf->TargetNameOffset,
2657 min_t(const int, buflen,
2658 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 }
2660 } else {
2661 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002662 cFYI(1, ("Invalid return data count on "
2663 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665 symlinkinfo[buflen] = 0; /* just in case so the caller
2666 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002667 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 }
2669 }
2670qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002671 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673 /* Note: On -EAGAIN error only caller can retry on handle based calls
2674 since file handle passed in no longer valid */
2675
2676 return rc;
2677}
2678
2679#ifdef CONFIG_CIFS_POSIX
2680
2681/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002682static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2683 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684{
2685 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002686 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2687 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2688 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2690
2691 return;
2692}
2693
2694/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002695static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2696 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
2698 int size = 0;
2699 int i;
2700 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002701 struct cifs_posix_ace *pACE;
2702 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2703 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2706 return -EOPNOTSUPP;
2707
Steve French790fe572007-07-07 19:25:05 +00002708 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 count = le16_to_cpu(cifs_acl->access_entry_count);
2710 pACE = &cifs_acl->ace_array[0];
2711 size = sizeof(struct cifs_posix_acl);
2712 size += sizeof(struct cifs_posix_ace) * count;
2713 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002714 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002715 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2716 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return -EINVAL;
2718 }
Steve French790fe572007-07-07 19:25:05 +00002719 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 count = le16_to_cpu(cifs_acl->access_entry_count);
2721 size = sizeof(struct cifs_posix_acl);
2722 size += sizeof(struct cifs_posix_ace) * count;
2723/* skip past access ACEs to get to default ACEs */
2724 pACE = &cifs_acl->ace_array[count];
2725 count = le16_to_cpu(cifs_acl->default_entry_count);
2726 size += sizeof(struct cifs_posix_ace) * count;
2727 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002728 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 return -EINVAL;
2730 } else {
2731 /* illegal type */
2732 return -EINVAL;
2733 }
2734
2735 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002736 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002737 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002738 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 return -ERANGE;
2740 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002741 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002742 for (i = 0; i < count ; i++) {
2743 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2744 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 }
2746 }
2747 return size;
2748}
2749
Steve French50c2f752007-07-13 00:33:32 +00002750static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2751 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752{
2753 __u16 rc = 0; /* 0 = ACL converted ok */
2754
Steve Frenchff7feac2005-11-15 16:45:16 -08002755 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2756 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002758 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 /* Probably no need to le convert -1 on any arch but can not hurt */
2760 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002761 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002762 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002763 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 return rc;
2765}
2766
2767/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002768static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2769 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770{
2771 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002772 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2773 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 int count;
2775 int i;
2776
Steve French790fe572007-07-07 19:25:05 +00002777 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 return 0;
2779
2780 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002781 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002782 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002783 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002784 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002785 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002786 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 return 0;
2788 }
2789 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002790 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002791 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002792 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002793 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 else {
Steve French50c2f752007-07-13 00:33:32 +00002795 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 return 0;
2797 }
Steve French50c2f752007-07-13 00:33:32 +00002798 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2800 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002801 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 /* ACE not converted */
2803 break;
2804 }
2805 }
Steve French790fe572007-07-07 19:25:05 +00002806 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2808 rc += sizeof(struct cifs_posix_acl);
2809 /* BB add check to make sure ACL does not overflow SMB */
2810 }
2811 return rc;
2812}
2813
2814int
2815CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002816 const unsigned char *searchName,
2817 char *acl_inf, const int buflen, const int acl_type,
2818 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819{
2820/* SMB_QUERY_POSIX_ACL */
2821 TRANSACTION2_QPI_REQ *pSMB = NULL;
2822 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2823 int rc = 0;
2824 int bytes_returned;
2825 int name_len;
2826 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002827
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2829
2830queryAclRetry:
2831 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2832 (void **) &pSMBr);
2833 if (rc)
2834 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002835
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2837 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002838 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002839 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 name_len++; /* trailing null */
2841 name_len *= 2;
2842 pSMB->FileName[name_len] = 0;
2843 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002844 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 name_len = strnlen(searchName, PATH_MAX);
2846 name_len++; /* trailing null */
2847 strncpy(pSMB->FileName, searchName, name_len);
2848 }
2849
2850 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2851 pSMB->TotalDataCount = 0;
2852 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002853 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 pSMB->MaxDataCount = cpu_to_le16(4000);
2855 pSMB->MaxSetupCount = 0;
2856 pSMB->Reserved = 0;
2857 pSMB->Flags = 0;
2858 pSMB->Timeout = 0;
2859 pSMB->Reserved2 = 0;
2860 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002861 offsetof(struct smb_com_transaction2_qpi_req,
2862 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 pSMB->DataCount = 0;
2864 pSMB->DataOffset = 0;
2865 pSMB->SetupCount = 1;
2866 pSMB->Reserved3 = 0;
2867 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2868 byte_count = params + 1 /* pad */ ;
2869 pSMB->TotalParameterCount = cpu_to_le16(params);
2870 pSMB->ParameterCount = pSMB->TotalParameterCount;
2871 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2872 pSMB->Reserved4 = 0;
2873 pSMB->hdr.smb_buf_length += byte_count;
2874 pSMB->ByteCount = cpu_to_le16(byte_count);
2875
2876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002878 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 if (rc) {
2880 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2881 } else {
2882 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002883
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2885 if (rc || (pSMBr->ByteCount < 2))
2886 /* BB also check enough total bytes returned */
2887 rc = -EIO; /* bad smb */
2888 else {
2889 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2890 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2891 rc = cifs_copy_posix_acl(acl_inf,
2892 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002893 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 }
2895 }
2896 cifs_buf_release(pSMB);
2897 if (rc == -EAGAIN)
2898 goto queryAclRetry;
2899 return rc;
2900}
2901
2902int
2903CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002904 const unsigned char *fileName,
2905 const char *local_acl, const int buflen,
2906 const int acl_type,
2907 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908{
2909 struct smb_com_transaction2_spi_req *pSMB = NULL;
2910 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2911 char *parm_data;
2912 int name_len;
2913 int rc = 0;
2914 int bytes_returned = 0;
2915 __u16 params, byte_count, data_count, param_offset, offset;
2916
2917 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2918setAclRetry:
2919 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002920 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 if (rc)
2922 return rc;
2923 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2924 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002925 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002926 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 name_len++; /* trailing null */
2928 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002929 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 name_len = strnlen(fileName, PATH_MAX);
2931 name_len++; /* trailing null */
2932 strncpy(pSMB->FileName, fileName, name_len);
2933 }
2934 params = 6 + name_len;
2935 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002936 /* BB find max SMB size from sess */
2937 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 pSMB->MaxSetupCount = 0;
2939 pSMB->Reserved = 0;
2940 pSMB->Flags = 0;
2941 pSMB->Timeout = 0;
2942 pSMB->Reserved2 = 0;
2943 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002944 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 offset = param_offset + params;
2946 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2947 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2948
2949 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002950 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
Steve French790fe572007-07-07 19:25:05 +00002952 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 rc = -EOPNOTSUPP;
2954 goto setACLerrorExit;
2955 }
2956 pSMB->DataOffset = cpu_to_le16(offset);
2957 pSMB->SetupCount = 1;
2958 pSMB->Reserved3 = 0;
2959 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2960 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2961 byte_count = 3 /* pad */ + params + data_count;
2962 pSMB->DataCount = cpu_to_le16(data_count);
2963 pSMB->TotalDataCount = pSMB->DataCount;
2964 pSMB->ParameterCount = cpu_to_le16(params);
2965 pSMB->TotalParameterCount = pSMB->ParameterCount;
2966 pSMB->Reserved4 = 0;
2967 pSMB->hdr.smb_buf_length += byte_count;
2968 pSMB->ByteCount = cpu_to_le16(byte_count);
2969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002971 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
2974setACLerrorExit:
2975 cifs_buf_release(pSMB);
2976 if (rc == -EAGAIN)
2977 goto setAclRetry;
2978 return rc;
2979}
2980
Steve Frenchf654bac2005-04-28 22:41:04 -07002981/* BB fix tabs in this function FIXME BB */
2982int
2983CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002984 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002985{
Steve French50c2f752007-07-13 00:33:32 +00002986 int rc = 0;
2987 struct smb_t2_qfi_req *pSMB = NULL;
2988 struct smb_t2_qfi_rsp *pSMBr = NULL;
2989 int bytes_returned;
2990 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002991
Steve French790fe572007-07-07 19:25:05 +00002992 cFYI(1, ("In GetExtAttr"));
2993 if (tcon == NULL)
2994 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002995
2996GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2998 (void **) &pSMBr);
2999 if (rc)
3000 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003001
Steve Frenchad7a2922008-02-07 23:25:02 +00003002 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003003 pSMB->t2.TotalDataCount = 0;
3004 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3005 /* BB find exact max data count below from sess structure BB */
3006 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3007 pSMB->t2.MaxSetupCount = 0;
3008 pSMB->t2.Reserved = 0;
3009 pSMB->t2.Flags = 0;
3010 pSMB->t2.Timeout = 0;
3011 pSMB->t2.Reserved2 = 0;
3012 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3013 Fid) - 4);
3014 pSMB->t2.DataCount = 0;
3015 pSMB->t2.DataOffset = 0;
3016 pSMB->t2.SetupCount = 1;
3017 pSMB->t2.Reserved3 = 0;
3018 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3019 byte_count = params + 1 /* pad */ ;
3020 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3021 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3022 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3023 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003024 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003025 pSMB->hdr.smb_buf_length += byte_count;
3026 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003027
Steve French790fe572007-07-07 19:25:05 +00003028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3030 if (rc) {
3031 cFYI(1, ("error %d in GetExtAttr", rc));
3032 } else {
3033 /* decode response */
3034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3035 if (rc || (pSMBr->ByteCount < 2))
3036 /* BB also check enough total bytes returned */
3037 /* If rc should we check for EOPNOSUPP and
3038 disable the srvino flag? or in caller? */
3039 rc = -EIO; /* bad smb */
3040 else {
3041 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3042 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3043 struct file_chattr_info *pfinfo;
3044 /* BB Do we need a cast or hash here ? */
3045 if (count != 16) {
3046 cFYI(1, ("Illegal size ret in GetExtAttr"));
3047 rc = -EIO;
3048 goto GetExtAttrOut;
3049 }
3050 pfinfo = (struct file_chattr_info *)
3051 (data_offset + (char *) &pSMBr->hdr.Protocol);
3052 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003053 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003054 }
3055 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003056GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003057 cifs_buf_release(pSMB);
3058 if (rc == -EAGAIN)
3059 goto GetExtAttrRetry;
3060 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003061}
3062
Steve Frenchf654bac2005-04-28 22:41:04 -07003063#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
Steve French297647c2007-10-12 04:11:59 +00003065#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003066/* Get Security Descriptor (by handle) from remote server for a file or dir */
3067int
3068CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003069 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003070{
3071 int rc = 0;
3072 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003073 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003074 struct kvec iov[1];
3075
3076 cFYI(1, ("GetCifsACL"));
3077
Steve French630f3f02007-10-25 21:17:17 +00003078 *pbuflen = 0;
3079 *acl_inf = NULL;
3080
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003081 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003082 8 /* parm len */, tcon, (void **) &pSMB);
3083 if (rc)
3084 return rc;
3085
3086 pSMB->MaxParameterCount = cpu_to_le32(4);
3087 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3088 pSMB->MaxSetupCount = 0;
3089 pSMB->Fid = fid; /* file handle always le */
3090 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3091 CIFS_ACL_DACL);
3092 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3093 pSMB->hdr.smb_buf_length += 11;
3094 iov[0].iov_base = (char *)pSMB;
3095 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3096
Steve Frencha761ac52007-10-18 21:45:27 +00003097 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003098 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003099 cifs_stats_inc(&tcon->num_acl_get);
3100 if (rc) {
3101 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3102 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003103 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003104 __u32 parm_len;
3105 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003106 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003107 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003108
3109/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003110 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003111 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003112 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003113 goto qsec_out;
3114 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3115
Steve French630f3f02007-10-25 21:17:17 +00003116 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003117
3118 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3119 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003120 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003121 goto qsec_out;
3122 }
3123
3124/* BB check that data area is minimum length and as big as acl_len */
3125
Steve Frenchaf6f4612007-10-16 18:40:37 +00003126 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003127 if (acl_len != *pbuflen) {
3128 cERROR(1, ("acl length %d does not match %d",
3129 acl_len, *pbuflen));
3130 if (*pbuflen > acl_len)
3131 *pbuflen = acl_len;
3132 }
Steve French0a4b92c2006-01-12 15:44:21 -08003133
Steve French630f3f02007-10-25 21:17:17 +00003134 /* check if buffer is big enough for the acl
3135 header followed by the smallest SID */
3136 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3137 (*pbuflen >= 64 * 1024)) {
3138 cERROR(1, ("bad acl length %d", *pbuflen));
3139 rc = -EINVAL;
3140 *pbuflen = 0;
3141 } else {
3142 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3143 if (*acl_inf == NULL) {
3144 *pbuflen = 0;
3145 rc = -ENOMEM;
3146 }
3147 memcpy(*acl_inf, pdata, *pbuflen);
3148 }
Steve French0a4b92c2006-01-12 15:44:21 -08003149 }
3150qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003151 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003152 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003153 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003154 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003155/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003156 return rc;
3157}
Steve French97837582007-12-31 07:47:21 +00003158
3159int
3160CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3161 struct cifs_ntsd *pntsd, __u32 acllen)
3162{
3163 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3164 int rc = 0;
3165 int bytes_returned = 0;
3166 SET_SEC_DESC_REQ *pSMB = NULL;
3167 NTRANSACT_RSP *pSMBr = NULL;
3168
3169setCifsAclRetry:
3170 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3171 (void **) &pSMBr);
3172 if (rc)
3173 return (rc);
3174
3175 pSMB->MaxSetupCount = 0;
3176 pSMB->Reserved = 0;
3177
3178 param_count = 8;
3179 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3180 data_count = acllen;
3181 data_offset = param_offset + param_count;
3182 byte_count = 3 /* pad */ + param_count;
3183
3184 pSMB->DataCount = cpu_to_le32(data_count);
3185 pSMB->TotalDataCount = pSMB->DataCount;
3186 pSMB->MaxParameterCount = cpu_to_le32(4);
3187 pSMB->MaxDataCount = cpu_to_le32(16384);
3188 pSMB->ParameterCount = cpu_to_le32(param_count);
3189 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3190 pSMB->TotalParameterCount = pSMB->ParameterCount;
3191 pSMB->DataOffset = cpu_to_le32(data_offset);
3192 pSMB->SetupCount = 0;
3193 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3194 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3195
3196 pSMB->Fid = fid; /* file handle always le */
3197 pSMB->Reserved2 = 0;
3198 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3199
3200 if (pntsd && acllen) {
3201 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3202 (char *) pntsd,
3203 acllen);
3204 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3205
3206 } else
3207 pSMB->hdr.smb_buf_length += byte_count;
3208
3209 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3210 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3211
3212 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3213 if (rc)
3214 cFYI(1, ("Set CIFS ACL returned %d", rc));
3215 cifs_buf_release(pSMB);
3216
3217 if (rc == -EAGAIN)
3218 goto setCifsAclRetry;
3219
3220 return (rc);
3221}
3222
Steve French297647c2007-10-12 04:11:59 +00003223#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003224
Steve French6b8edfe2005-08-23 20:26:03 -07003225/* Legacy Query Path Information call for lookup to old servers such
3226 as Win9x/WinME */
3227int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003228 const unsigned char *searchName,
3229 FILE_ALL_INFO *pFinfo,
3230 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003231{
Steve Frenchad7a2922008-02-07 23:25:02 +00003232 QUERY_INFORMATION_REQ *pSMB;
3233 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003234 int rc = 0;
3235 int bytes_returned;
3236 int name_len;
3237
Steve French50c2f752007-07-13 00:33:32 +00003238 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003239QInfRetry:
3240 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003241 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003242 if (rc)
3243 return rc;
3244
3245 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3246 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003247 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3248 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003249 name_len++; /* trailing null */
3250 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003251 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003252 name_len = strnlen(searchName, PATH_MAX);
3253 name_len++; /* trailing null */
3254 strncpy(pSMB->FileName, searchName, name_len);
3255 }
3256 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003257 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003258 pSMB->hdr.smb_buf_length += (__u16) name_len;
3259 pSMB->ByteCount = cpu_to_le16(name_len);
3260
3261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003263 if (rc) {
3264 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003265 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003266 struct timespec ts;
3267 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003268
3269 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003270 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003271 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003272 ts.tv_nsec = 0;
3273 ts.tv_sec = time;
3274 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003275 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003276 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3277 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003278 pFinfo->AllocationSize =
3279 cpu_to_le64(le32_to_cpu(pSMBr->size));
3280 pFinfo->EndOfFile = pFinfo->AllocationSize;
3281 pFinfo->Attributes =
3282 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003283 } else
3284 rc = -EIO; /* bad buffer passed in */
3285
3286 cifs_buf_release(pSMB);
3287
3288 if (rc == -EAGAIN)
3289 goto QInfRetry;
3290
3291 return rc;
3292}
3293
3294
3295
3296
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297int
3298CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3299 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003300 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003301 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003302 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303{
3304/* level 263 SMB_QUERY_FILE_ALL_INFO */
3305 TRANSACTION2_QPI_REQ *pSMB = NULL;
3306 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3307 int rc = 0;
3308 int bytes_returned;
3309 int name_len;
3310 __u16 params, byte_count;
3311
3312/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3313QPathInfoRetry:
3314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3315 (void **) &pSMBr);
3316 if (rc)
3317 return rc;
3318
3319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3320 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003321 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003322 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 name_len++; /* trailing null */
3324 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003325 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 name_len = strnlen(searchName, PATH_MAX);
3327 name_len++; /* trailing null */
3328 strncpy(pSMB->FileName, searchName, name_len);
3329 }
3330
Steve French50c2f752007-07-13 00:33:32 +00003331 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 pSMB->TotalDataCount = 0;
3333 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003334 /* BB find exact max SMB PDU from sess structure BB */
3335 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 pSMB->MaxSetupCount = 0;
3337 pSMB->Reserved = 0;
3338 pSMB->Flags = 0;
3339 pSMB->Timeout = 0;
3340 pSMB->Reserved2 = 0;
3341 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003342 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 pSMB->DataCount = 0;
3344 pSMB->DataOffset = 0;
3345 pSMB->SetupCount = 1;
3346 pSMB->Reserved3 = 0;
3347 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3348 byte_count = params + 1 /* pad */ ;
3349 pSMB->TotalParameterCount = cpu_to_le16(params);
3350 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003351 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003352 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3353 else
3354 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 pSMB->Reserved4 = 0;
3356 pSMB->hdr.smb_buf_length += byte_count;
3357 pSMB->ByteCount = cpu_to_le16(byte_count);
3358
3359 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3360 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3361 if (rc) {
3362 cFYI(1, ("Send error in QPathInfo = %d", rc));
3363 } else { /* decode response */
3364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3365
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003366 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3367 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003368 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003370 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003371 rc = -EIO; /* 24 or 26 expected but we do not read
3372 last field */
3373 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003374 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003376
3377 /* On legacy responses we do not read the last field,
3378 EAsize, fortunately since it varies by subdialect and
3379 also note it differs on Set vs. Get, ie two bytes or 4
3380 bytes depending but we don't care here */
3381 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003382 size = sizeof(FILE_INFO_STANDARD);
3383 else
3384 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 memcpy((char *) pFindData,
3386 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003387 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 } else
3389 rc = -ENOMEM;
3390 }
3391 cifs_buf_release(pSMB);
3392 if (rc == -EAGAIN)
3393 goto QPathInfoRetry;
3394
3395 return rc;
3396}
3397
3398int
3399CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3400 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003401 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003402 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403{
3404/* SMB_QUERY_FILE_UNIX_BASIC */
3405 TRANSACTION2_QPI_REQ *pSMB = NULL;
3406 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3407 int rc = 0;
3408 int bytes_returned = 0;
3409 int name_len;
3410 __u16 params, byte_count;
3411
3412 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3413UnixQPathInfoRetry:
3414 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3415 (void **) &pSMBr);
3416 if (rc)
3417 return rc;
3418
3419 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3420 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003421 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003422 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 name_len++; /* trailing null */
3424 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003425 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 name_len = strnlen(searchName, PATH_MAX);
3427 name_len++; /* trailing null */
3428 strncpy(pSMB->FileName, searchName, name_len);
3429 }
3430
Steve French50c2f752007-07-13 00:33:32 +00003431 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 pSMB->TotalDataCount = 0;
3433 pSMB->MaxParameterCount = cpu_to_le16(2);
3434 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003435 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 pSMB->MaxSetupCount = 0;
3437 pSMB->Reserved = 0;
3438 pSMB->Flags = 0;
3439 pSMB->Timeout = 0;
3440 pSMB->Reserved2 = 0;
3441 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003442 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 pSMB->DataCount = 0;
3444 pSMB->DataOffset = 0;
3445 pSMB->SetupCount = 1;
3446 pSMB->Reserved3 = 0;
3447 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3448 byte_count = params + 1 /* pad */ ;
3449 pSMB->TotalParameterCount = cpu_to_le16(params);
3450 pSMB->ParameterCount = pSMB->TotalParameterCount;
3451 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3452 pSMB->Reserved4 = 0;
3453 pSMB->hdr.smb_buf_length += byte_count;
3454 pSMB->ByteCount = cpu_to_le16(byte_count);
3455
3456 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3457 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3458 if (rc) {
3459 cFYI(1, ("Send error in QPathInfo = %d", rc));
3460 } else { /* decode response */
3461 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3462
3463 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003464 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3465 "Unix Extensions can be disabled on mount "
3466 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 rc = -EIO; /* bad smb */
3468 } else {
3469 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3470 memcpy((char *) pFindData,
3471 (char *) &pSMBr->hdr.Protocol +
3472 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003473 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 }
3475 }
3476 cifs_buf_release(pSMB);
3477 if (rc == -EAGAIN)
3478 goto UnixQPathInfoRetry;
3479
3480 return rc;
3481}
3482
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483/* xid, tcon, searchName and codepage are input parms, rest are returned */
3484int
3485CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003486 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003488 __u16 *pnetfid,
3489 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490{
3491/* level 257 SMB_ */
3492 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3493 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003494 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 int rc = 0;
3496 int bytes_returned = 0;
3497 int name_len;
3498 __u16 params, byte_count;
3499
Steve French50c2f752007-07-13 00:33:32 +00003500 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
3502findFirstRetry:
3503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3504 (void **) &pSMBr);
3505 if (rc)
3506 return rc;
3507
3508 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3509 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003510 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003511 PATH_MAX, nls_codepage, remap);
3512 /* We can not add the asterik earlier in case
3513 it got remapped to 0xF03A as if it were part of the
3514 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003516 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003517 pSMB->FileName[name_len+1] = 0;
3518 pSMB->FileName[name_len+2] = '*';
3519 pSMB->FileName[name_len+3] = 0;
3520 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3522 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003523 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 } else { /* BB add check for overrun of SMB buf BB */
3525 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003527 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 free buffer exit; BB */
3529 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003530 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003531 pSMB->FileName[name_len+1] = '*';
3532 pSMB->FileName[name_len+2] = 0;
3533 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 }
3535
3536 params = 12 + name_len /* includes null */ ;
3537 pSMB->TotalDataCount = 0; /* no EAs */
3538 pSMB->MaxParameterCount = cpu_to_le16(10);
3539 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3540 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3541 pSMB->MaxSetupCount = 0;
3542 pSMB->Reserved = 0;
3543 pSMB->Flags = 0;
3544 pSMB->Timeout = 0;
3545 pSMB->Reserved2 = 0;
3546 byte_count = params + 1 /* pad */ ;
3547 pSMB->TotalParameterCount = cpu_to_le16(params);
3548 pSMB->ParameterCount = pSMB->TotalParameterCount;
3549 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003550 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3551 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 pSMB->DataCount = 0;
3553 pSMB->DataOffset = 0;
3554 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3555 pSMB->Reserved3 = 0;
3556 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3557 pSMB->SearchAttributes =
3558 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3559 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003560 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3561 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 CIFS_SEARCH_RETURN_RESUME);
3563 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3564
3565 /* BB what should we set StorageType to? Does it matter? BB */
3566 pSMB->SearchStorageType = 0;
3567 pSMB->hdr.smb_buf_length += byte_count;
3568 pSMB->ByteCount = cpu_to_le16(byte_count);
3569
3570 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3571 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003572 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573
Steve French88274812006-03-09 22:21:45 +00003574 if (rc) {/* BB add logic to retry regular search if Unix search
3575 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 /* BB Add code to handle unsupported level rc */
3577 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003578
Steve French88274812006-03-09 22:21:45 +00003579 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
3581 /* BB eventually could optimize out free and realloc of buf */
3582 /* for this case */
3583 if (rc == -EAGAIN)
3584 goto findFirstRetry;
3585 } else { /* decode response */
3586 /* BB remember to free buffer if error BB */
3587 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003588 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003590 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 else
Steve French4b18f2a2008-04-29 00:06:05 +00003592 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593
3594 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003595 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003596 psrch_inf->srch_entries_start =
3597 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3600 le16_to_cpu(pSMBr->t2.ParameterOffset));
3601
Steve French790fe572007-07-07 19:25:05 +00003602 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003603 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 else
Steve French4b18f2a2008-04-29 00:06:05 +00003605 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
Steve French50c2f752007-07-13 00:33:32 +00003607 psrch_inf->entries_in_buffer =
3608 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003609 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 *pnetfid = parms->SearchHandle;
3612 } else {
3613 cifs_buf_release(pSMB);
3614 }
3615 }
3616
3617 return rc;
3618}
3619
3620int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003621 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622{
3623 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3624 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003625 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 char *response_data;
3627 int rc = 0;
3628 int bytes_returned, name_len;
3629 __u16 params, byte_count;
3630
3631 cFYI(1, ("In FindNext"));
3632
Steve French4b18f2a2008-04-29 00:06:05 +00003633 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 return -ENOENT;
3635
3636 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3637 (void **) &pSMBr);
3638 if (rc)
3639 return rc;
3640
Steve French50c2f752007-07-13 00:33:32 +00003641 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 byte_count = 0;
3643 pSMB->TotalDataCount = 0; /* no EAs */
3644 pSMB->MaxParameterCount = cpu_to_le16(8);
3645 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003646 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3647 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 pSMB->MaxSetupCount = 0;
3649 pSMB->Reserved = 0;
3650 pSMB->Flags = 0;
3651 pSMB->Timeout = 0;
3652 pSMB->Reserved2 = 0;
3653 pSMB->ParameterOffset = cpu_to_le16(
3654 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3655 pSMB->DataCount = 0;
3656 pSMB->DataOffset = 0;
3657 pSMB->SetupCount = 1;
3658 pSMB->Reserved3 = 0;
3659 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3660 pSMB->SearchHandle = searchHandle; /* always kept as le */
3661 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003662 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3664 pSMB->ResumeKey = psrch_inf->resume_key;
3665 pSMB->SearchFlags =
3666 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3667
3668 name_len = psrch_inf->resume_name_len;
3669 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003670 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3672 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003673 /* 14 byte parm len above enough for 2 byte null terminator */
3674 pSMB->ResumeFileName[name_len] = 0;
3675 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 } else {
3677 rc = -EINVAL;
3678 goto FNext2_err_exit;
3679 }
3680 byte_count = params + 1 /* pad */ ;
3681 pSMB->TotalParameterCount = cpu_to_le16(params);
3682 pSMB->ParameterCount = pSMB->TotalParameterCount;
3683 pSMB->hdr.smb_buf_length += byte_count;
3684 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003685
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3687 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003688 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 if (rc) {
3690 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003691 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003692 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003693 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 } else
3695 cFYI(1, ("FindNext returned = %d", rc));
3696 } else { /* decode response */
3697 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003698
Steve French790fe572007-07-07 19:25:05 +00003699 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 /* BB fixme add lock for file (srch_info) struct here */
3701 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003702 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 else
Steve French4b18f2a2008-04-29 00:06:05 +00003704 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 response_data = (char *) &pSMBr->hdr.Protocol +
3706 le16_to_cpu(pSMBr->t2.ParameterOffset);
3707 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3708 response_data = (char *)&pSMBr->hdr.Protocol +
3709 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003710 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003711 cifs_small_buf_release(
3712 psrch_inf->ntwrk_buf_start);
3713 else
3714 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 psrch_inf->srch_entries_start = response_data;
3716 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003717 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003718 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003719 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 else
Steve French4b18f2a2008-04-29 00:06:05 +00003721 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003722 psrch_inf->entries_in_buffer =
3723 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 psrch_inf->index_of_last_entry +=
3725 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003726/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3727 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
3729 /* BB fixme add unlock here */
3730 }
3731
3732 }
3733
3734 /* BB On error, should we leave previous search buf (and count and
3735 last entry fields) intact or free the previous one? */
3736
3737 /* Note: On -EAGAIN error only caller can retry on handle based calls
3738 since file handle passed in no longer valid */
3739FNext2_err_exit:
3740 if (rc != 0)
3741 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 return rc;
3743}
3744
3745int
Steve French50c2f752007-07-13 00:33:32 +00003746CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3747 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748{
3749 int rc = 0;
3750 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
3752 cFYI(1, ("In CIFSSMBFindClose"));
3753 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3754
3755 /* no sense returning error if session restarted
3756 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003757 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 return 0;
3759 if (rc)
3760 return rc;
3761
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 pSMB->FileID = searchHandle;
3763 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003764 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003765 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003767
Steve Frencha4544342005-08-24 13:59:35 -07003768 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
3770 /* Since session is dead, search handle closed on server already */
3771 if (rc == -EAGAIN)
3772 rc = 0;
3773
3774 return rc;
3775}
3776
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777int
3778CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003779 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003780 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003781 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782{
3783 int rc = 0;
3784 TRANSACTION2_QPI_REQ *pSMB = NULL;
3785 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3786 int name_len, bytes_returned;
3787 __u16 params, byte_count;
3788
Steve French50c2f752007-07-13 00:33:32 +00003789 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003790 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003791 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792
3793GetInodeNumberRetry:
3794 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003795 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 if (rc)
3797 return rc;
3798
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3800 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003801 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003802 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 name_len++; /* trailing null */
3804 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003805 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 name_len = strnlen(searchName, PATH_MAX);
3807 name_len++; /* trailing null */
3808 strncpy(pSMB->FileName, searchName, name_len);
3809 }
3810
3811 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3812 pSMB->TotalDataCount = 0;
3813 pSMB->MaxParameterCount = cpu_to_le16(2);
3814 /* BB find exact max data count below from sess structure BB */
3815 pSMB->MaxDataCount = cpu_to_le16(4000);
3816 pSMB->MaxSetupCount = 0;
3817 pSMB->Reserved = 0;
3818 pSMB->Flags = 0;
3819 pSMB->Timeout = 0;
3820 pSMB->Reserved2 = 0;
3821 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003822 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 pSMB->DataCount = 0;
3824 pSMB->DataOffset = 0;
3825 pSMB->SetupCount = 1;
3826 pSMB->Reserved3 = 0;
3827 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3828 byte_count = params + 1 /* pad */ ;
3829 pSMB->TotalParameterCount = cpu_to_le16(params);
3830 pSMB->ParameterCount = pSMB->TotalParameterCount;
3831 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3832 pSMB->Reserved4 = 0;
3833 pSMB->hdr.smb_buf_length += byte_count;
3834 pSMB->ByteCount = cpu_to_le16(byte_count);
3835
3836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3837 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3838 if (rc) {
3839 cFYI(1, ("error %d in QueryInternalInfo", rc));
3840 } else {
3841 /* decode response */
3842 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3843 if (rc || (pSMBr->ByteCount < 2))
3844 /* BB also check enough total bytes returned */
3845 /* If rc should we check for EOPNOSUPP and
3846 disable the srvino flag? or in caller? */
3847 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003848 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3850 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003851 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003853 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3855 rc = -EIO;
3856 goto GetInodeNumOut;
3857 }
3858 pfinfo = (struct file_internal_info *)
3859 (data_offset + (char *) &pSMBr->hdr.Protocol);
3860 *inode_number = pfinfo->UniqueId;
3861 }
3862 }
3863GetInodeNumOut:
3864 cifs_buf_release(pSMB);
3865 if (rc == -EAGAIN)
3866 goto GetInodeNumberRetry;
3867 return rc;
3868}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869
3870int
3871CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3872 const unsigned char *searchName,
3873 unsigned char **targetUNCs,
3874 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003875 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876{
3877/* TRANS2_GET_DFS_REFERRAL */
3878 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3879 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003880 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 int rc = 0;
3882 int bytes_returned;
3883 int name_len;
3884 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003885 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 __u16 params, byte_count;
3887 *number_of_UNC_in_array = 0;
3888 *targetUNCs = NULL;
3889
3890 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3891 if (ses == NULL)
3892 return -ENODEV;
3893getDFSRetry:
3894 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3895 (void **) &pSMBr);
3896 if (rc)
3897 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003898
3899 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003900 but should never be null here anyway */
3901 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 pSMB->hdr.Tid = ses->ipc_tid;
3903 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003904 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003906 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
3909 if (ses->capabilities & CAP_UNICODE) {
3910 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3911 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003912 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003913 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 name_len++; /* trailing null */
3915 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003916 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 name_len = strnlen(searchName, PATH_MAX);
3918 name_len++; /* trailing null */
3919 strncpy(pSMB->RequestFileName, searchName, name_len);
3920 }
3921
Steve French790fe572007-07-07 19:25:05 +00003922 if (ses->server) {
3923 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003924 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3925 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3926 }
3927
Steve French50c2f752007-07-13 00:33:32 +00003928 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003929
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 params = 2 /* level */ + name_len /*includes null */ ;
3931 pSMB->TotalDataCount = 0;
3932 pSMB->DataCount = 0;
3933 pSMB->DataOffset = 0;
3934 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00003935 /* BB find exact max SMB PDU from sess structure BB */
3936 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 pSMB->MaxSetupCount = 0;
3938 pSMB->Reserved = 0;
3939 pSMB->Flags = 0;
3940 pSMB->Timeout = 0;
3941 pSMB->Reserved2 = 0;
3942 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003943 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 pSMB->SetupCount = 1;
3945 pSMB->Reserved3 = 0;
3946 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3947 byte_count = params + 3 /* pad */ ;
3948 pSMB->ParameterCount = cpu_to_le16(params);
3949 pSMB->TotalParameterCount = pSMB->ParameterCount;
3950 pSMB->MaxReferralLevel = cpu_to_le16(3);
3951 pSMB->hdr.smb_buf_length += byte_count;
3952 pSMB->ByteCount = cpu_to_le16(byte_count);
3953
3954 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3956 if (rc) {
3957 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3958 } else { /* decode response */
3959/* BB Add logic to parse referrals here */
3960 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3961
Steve French50c2f752007-07-13 00:33:32 +00003962 /* BB Also check if enough total bytes returned? */
3963 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 rc = -EIO; /* bad smb */
3965 else {
Steve French50c2f752007-07-13 00:33:32 +00003966 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3968
3969 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003970 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003972 referrals =
3973 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 (8 /* sizeof start of data block */ +
3975 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003976 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003977 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003978 "for referral one refer size: 0x%x srv "
3979 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003980 le16_to_cpu(pSMBr->NumberOfReferrals),
3981 le16_to_cpu(pSMBr->DFSFlags),
3982 le16_to_cpu(referrals->ReferralSize),
3983 le16_to_cpu(referrals->ServerType),
3984 le16_to_cpu(referrals->ReferralFlags),
3985 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 /* BB This field is actually two bytes in from start of
3987 data block so we could do safety check that DataBlock
3988 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003989 *number_of_UNC_in_array =
3990 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
3992 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003993 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 *number_of_UNC_in_array = 1;
3995
3996 /* get the length of the strings describing refs */
3997 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003998 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00004000 __u16 offset =
4001 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00004003 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 not try to copy any more */
4005 *number_of_UNC_in_array = i;
4006 break;
Steve French50c2f752007-07-13 00:33:32 +00004007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 temp = ((char *)referrals) + offset;
4009
4010 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004011 name_len += UniStrnlen((wchar_t *)temp,
4012 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 } else {
Steve French50c2f752007-07-13 00:33:32 +00004014 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 }
4016 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004017 /* BB add check that referral pointer does
4018 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 }
4020 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004021 *targetUNCs =
4022 kmalloc(name_len+1+(*number_of_UNC_in_array),
4023 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004024 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 rc = -ENOMEM;
4026 goto GetDFSRefExit;
4027 }
4028 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004029 referrals = (struct dfs_referral_level_3 *)
4030 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 (char *) &pSMBr->hdr.Protocol);
4032
Steve French50c2f752007-07-13 00:33:32 +00004033 for (i = 0; i < *number_of_UNC_in_array; i++) {
4034 temp = ((char *)referrals) +
4035 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4037 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004038 (__le16 *) temp,
4039 name_len,
4040 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 } else {
Steve French50c2f752007-07-13 00:33:32 +00004042 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 }
4044 /* BB update target_uncs pointers */
4045 referrals++;
4046 }
4047 temp = *targetUNCs;
4048 temp[name_len] = 0;
4049 }
4050
4051 }
4052GetDFSRefExit:
4053 if (pSMB)
4054 cifs_buf_release(pSMB);
4055
4056 if (rc == -EAGAIN)
4057 goto getDFSRetry;
4058
4059 return rc;
4060}
4061
Steve French20962432005-09-21 22:05:57 -07004062/* Query File System Info such as free space to old servers such as Win 9x */
4063int
4064SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4065{
4066/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4067 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4068 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4069 FILE_SYSTEM_ALLOC_INFO *response_data;
4070 int rc = 0;
4071 int bytes_returned = 0;
4072 __u16 params, byte_count;
4073
4074 cFYI(1, ("OldQFSInfo"));
4075oldQFSInfoRetry:
4076 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4077 (void **) &pSMBr);
4078 if (rc)
4079 return rc;
Steve French20962432005-09-21 22:05:57 -07004080
4081 params = 2; /* level */
4082 pSMB->TotalDataCount = 0;
4083 pSMB->MaxParameterCount = cpu_to_le16(2);
4084 pSMB->MaxDataCount = cpu_to_le16(1000);
4085 pSMB->MaxSetupCount = 0;
4086 pSMB->Reserved = 0;
4087 pSMB->Flags = 0;
4088 pSMB->Timeout = 0;
4089 pSMB->Reserved2 = 0;
4090 byte_count = params + 1 /* pad */ ;
4091 pSMB->TotalParameterCount = cpu_to_le16(params);
4092 pSMB->ParameterCount = pSMB->TotalParameterCount;
4093 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4094 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4095 pSMB->DataCount = 0;
4096 pSMB->DataOffset = 0;
4097 pSMB->SetupCount = 1;
4098 pSMB->Reserved3 = 0;
4099 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4100 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4101 pSMB->hdr.smb_buf_length += byte_count;
4102 pSMB->ByteCount = cpu_to_le16(byte_count);
4103
4104 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4106 if (rc) {
4107 cFYI(1, ("Send error in QFSInfo = %d", rc));
4108 } else { /* decode response */
4109 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4110
4111 if (rc || (pSMBr->ByteCount < 18))
4112 rc = -EIO; /* bad smb */
4113 else {
4114 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004115 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004116 pSMBr->ByteCount, data_offset));
4117
Steve French50c2f752007-07-13 00:33:32 +00004118 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004119 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4120 FSData->f_bsize =
4121 le16_to_cpu(response_data->BytesPerSector) *
4122 le32_to_cpu(response_data->
4123 SectorsPerAllocationUnit);
4124 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004125 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004126 FSData->f_bfree = FSData->f_bavail =
4127 le32_to_cpu(response_data->FreeAllocationUnits);
4128 cFYI(1,
4129 ("Blocks: %lld Free: %lld Block size %ld",
4130 (unsigned long long)FSData->f_blocks,
4131 (unsigned long long)FSData->f_bfree,
4132 FSData->f_bsize));
4133 }
4134 }
4135 cifs_buf_release(pSMB);
4136
4137 if (rc == -EAGAIN)
4138 goto oldQFSInfoRetry;
4139
4140 return rc;
4141}
4142
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143int
Steve French737b7582005-04-28 22:41:06 -07004144CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145{
4146/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4147 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4148 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4149 FILE_SYSTEM_INFO *response_data;
4150 int rc = 0;
4151 int bytes_returned = 0;
4152 __u16 params, byte_count;
4153
4154 cFYI(1, ("In QFSInfo"));
4155QFSInfoRetry:
4156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4157 (void **) &pSMBr);
4158 if (rc)
4159 return rc;
4160
4161 params = 2; /* level */
4162 pSMB->TotalDataCount = 0;
4163 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004164 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 pSMB->MaxSetupCount = 0;
4166 pSMB->Reserved = 0;
4167 pSMB->Flags = 0;
4168 pSMB->Timeout = 0;
4169 pSMB->Reserved2 = 0;
4170 byte_count = params + 1 /* pad */ ;
4171 pSMB->TotalParameterCount = cpu_to_le16(params);
4172 pSMB->ParameterCount = pSMB->TotalParameterCount;
4173 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004174 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 pSMB->DataCount = 0;
4176 pSMB->DataOffset = 0;
4177 pSMB->SetupCount = 1;
4178 pSMB->Reserved3 = 0;
4179 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4180 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4181 pSMB->hdr.smb_buf_length += byte_count;
4182 pSMB->ByteCount = cpu_to_le16(byte_count);
4183
4184 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4185 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4186 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004187 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004189 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190
Steve French20962432005-09-21 22:05:57 -07004191 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 rc = -EIO; /* bad smb */
4193 else {
4194 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195
4196 response_data =
4197 (FILE_SYSTEM_INFO
4198 *) (((char *) &pSMBr->hdr.Protocol) +
4199 data_offset);
4200 FSData->f_bsize =
4201 le32_to_cpu(response_data->BytesPerSector) *
4202 le32_to_cpu(response_data->
4203 SectorsPerAllocationUnit);
4204 FSData->f_blocks =
4205 le64_to_cpu(response_data->TotalAllocationUnits);
4206 FSData->f_bfree = FSData->f_bavail =
4207 le64_to_cpu(response_data->FreeAllocationUnits);
4208 cFYI(1,
4209 ("Blocks: %lld Free: %lld Block size %ld",
4210 (unsigned long long)FSData->f_blocks,
4211 (unsigned long long)FSData->f_bfree,
4212 FSData->f_bsize));
4213 }
4214 }
4215 cifs_buf_release(pSMB);
4216
4217 if (rc == -EAGAIN)
4218 goto QFSInfoRetry;
4219
4220 return rc;
4221}
4222
4223int
Steve French737b7582005-04-28 22:41:06 -07004224CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225{
4226/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4227 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4228 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4229 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4230 int rc = 0;
4231 int bytes_returned = 0;
4232 __u16 params, byte_count;
4233
4234 cFYI(1, ("In QFSAttributeInfo"));
4235QFSAttributeRetry:
4236 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4237 (void **) &pSMBr);
4238 if (rc)
4239 return rc;
4240
4241 params = 2; /* level */
4242 pSMB->TotalDataCount = 0;
4243 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004244 /* BB find exact max SMB PDU from sess structure BB */
4245 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 pSMB->MaxSetupCount = 0;
4247 pSMB->Reserved = 0;
4248 pSMB->Flags = 0;
4249 pSMB->Timeout = 0;
4250 pSMB->Reserved2 = 0;
4251 byte_count = params + 1 /* pad */ ;
4252 pSMB->TotalParameterCount = cpu_to_le16(params);
4253 pSMB->ParameterCount = pSMB->TotalParameterCount;
4254 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004255 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 pSMB->DataCount = 0;
4257 pSMB->DataOffset = 0;
4258 pSMB->SetupCount = 1;
4259 pSMB->Reserved3 = 0;
4260 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4261 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4262 pSMB->hdr.smb_buf_length += byte_count;
4263 pSMB->ByteCount = cpu_to_le16(byte_count);
4264
4265 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4266 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4267 if (rc) {
4268 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4269 } else { /* decode response */
4270 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4271
Steve French50c2f752007-07-13 00:33:32 +00004272 if (rc || (pSMBr->ByteCount < 13)) {
4273 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 rc = -EIO; /* bad smb */
4275 } else {
4276 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4277 response_data =
4278 (FILE_SYSTEM_ATTRIBUTE_INFO
4279 *) (((char *) &pSMBr->hdr.Protocol) +
4280 data_offset);
4281 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004282 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 }
4284 }
4285 cifs_buf_release(pSMB);
4286
4287 if (rc == -EAGAIN)
4288 goto QFSAttributeRetry;
4289
4290 return rc;
4291}
4292
4293int
Steve French737b7582005-04-28 22:41:06 -07004294CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295{
4296/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4297 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4298 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4299 FILE_SYSTEM_DEVICE_INFO *response_data;
4300 int rc = 0;
4301 int bytes_returned = 0;
4302 __u16 params, byte_count;
4303
4304 cFYI(1, ("In QFSDeviceInfo"));
4305QFSDeviceRetry:
4306 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4307 (void **) &pSMBr);
4308 if (rc)
4309 return rc;
4310
4311 params = 2; /* level */
4312 pSMB->TotalDataCount = 0;
4313 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004314 /* BB find exact max SMB PDU from sess structure BB */
4315 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 pSMB->MaxSetupCount = 0;
4317 pSMB->Reserved = 0;
4318 pSMB->Flags = 0;
4319 pSMB->Timeout = 0;
4320 pSMB->Reserved2 = 0;
4321 byte_count = params + 1 /* pad */ ;
4322 pSMB->TotalParameterCount = cpu_to_le16(params);
4323 pSMB->ParameterCount = pSMB->TotalParameterCount;
4324 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004325 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326
4327 pSMB->DataCount = 0;
4328 pSMB->DataOffset = 0;
4329 pSMB->SetupCount = 1;
4330 pSMB->Reserved3 = 0;
4331 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4332 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4333 pSMB->hdr.smb_buf_length += byte_count;
4334 pSMB->ByteCount = cpu_to_le16(byte_count);
4335
4336 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4337 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4338 if (rc) {
4339 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4340 } else { /* decode response */
4341 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4342
Steve French630f3f02007-10-25 21:17:17 +00004343 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 rc = -EIO; /* bad smb */
4345 else {
4346 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4347 response_data =
Steve French737b7582005-04-28 22:41:06 -07004348 (FILE_SYSTEM_DEVICE_INFO *)
4349 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 data_offset);
4351 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004352 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 }
4354 }
4355 cifs_buf_release(pSMB);
4356
4357 if (rc == -EAGAIN)
4358 goto QFSDeviceRetry;
4359
4360 return rc;
4361}
4362
4363int
Steve French737b7582005-04-28 22:41:06 -07004364CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365{
4366/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4367 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4368 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4369 FILE_SYSTEM_UNIX_INFO *response_data;
4370 int rc = 0;
4371 int bytes_returned = 0;
4372 __u16 params, byte_count;
4373
4374 cFYI(1, ("In QFSUnixInfo"));
4375QFSUnixRetry:
4376 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4377 (void **) &pSMBr);
4378 if (rc)
4379 return rc;
4380
4381 params = 2; /* level */
4382 pSMB->TotalDataCount = 0;
4383 pSMB->DataCount = 0;
4384 pSMB->DataOffset = 0;
4385 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004386 /* BB find exact max SMB PDU from sess structure BB */
4387 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 pSMB->MaxSetupCount = 0;
4389 pSMB->Reserved = 0;
4390 pSMB->Flags = 0;
4391 pSMB->Timeout = 0;
4392 pSMB->Reserved2 = 0;
4393 byte_count = params + 1 /* pad */ ;
4394 pSMB->ParameterCount = cpu_to_le16(params);
4395 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004396 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4397 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 pSMB->SetupCount = 1;
4399 pSMB->Reserved3 = 0;
4400 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4401 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4402 pSMB->hdr.smb_buf_length += byte_count;
4403 pSMB->ByteCount = cpu_to_le16(byte_count);
4404
4405 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4406 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4407 if (rc) {
4408 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4409 } else { /* decode response */
4410 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4411
4412 if (rc || (pSMBr->ByteCount < 13)) {
4413 rc = -EIO; /* bad smb */
4414 } else {
4415 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4416 response_data =
4417 (FILE_SYSTEM_UNIX_INFO
4418 *) (((char *) &pSMBr->hdr.Protocol) +
4419 data_offset);
4420 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004421 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 }
4423 }
4424 cifs_buf_release(pSMB);
4425
4426 if (rc == -EAGAIN)
4427 goto QFSUnixRetry;
4428
4429
4430 return rc;
4431}
4432
Jeremy Allisonac670552005-06-22 17:26:35 -07004433int
Steve French45abc6e2005-06-23 13:42:03 -05004434CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004435{
4436/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4437 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4438 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4439 int rc = 0;
4440 int bytes_returned = 0;
4441 __u16 params, param_offset, offset, byte_count;
4442
4443 cFYI(1, ("In SETFSUnixInfo"));
4444SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004445 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004446 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4447 (void **) &pSMBr);
4448 if (rc)
4449 return rc;
4450
4451 params = 4; /* 2 bytes zero followed by info level. */
4452 pSMB->MaxSetupCount = 0;
4453 pSMB->Reserved = 0;
4454 pSMB->Flags = 0;
4455 pSMB->Timeout = 0;
4456 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004457 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4458 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004459 offset = param_offset + params;
4460
4461 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004462 /* BB find exact max SMB PDU from sess structure BB */
4463 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004464 pSMB->SetupCount = 1;
4465 pSMB->Reserved3 = 0;
4466 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4467 byte_count = 1 /* pad */ + params + 12;
4468
4469 pSMB->DataCount = cpu_to_le16(12);
4470 pSMB->ParameterCount = cpu_to_le16(params);
4471 pSMB->TotalDataCount = pSMB->DataCount;
4472 pSMB->TotalParameterCount = pSMB->ParameterCount;
4473 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4474 pSMB->DataOffset = cpu_to_le16(offset);
4475
4476 /* Params. */
4477 pSMB->FileNum = 0;
4478 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4479
4480 /* Data. */
4481 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4482 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4483 pSMB->ClientUnixCap = cpu_to_le64(cap);
4484
4485 pSMB->hdr.smb_buf_length += byte_count;
4486 pSMB->ByteCount = cpu_to_le16(byte_count);
4487
4488 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4489 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4490 if (rc) {
4491 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4492 } else { /* decode response */
4493 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004494 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004495 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004496 }
4497 cifs_buf_release(pSMB);
4498
4499 if (rc == -EAGAIN)
4500 goto SETFSUnixRetry;
4501
4502 return rc;
4503}
4504
4505
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506
4507int
4508CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004509 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510{
4511/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4512 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4513 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4514 FILE_SYSTEM_POSIX_INFO *response_data;
4515 int rc = 0;
4516 int bytes_returned = 0;
4517 __u16 params, byte_count;
4518
4519 cFYI(1, ("In QFSPosixInfo"));
4520QFSPosixRetry:
4521 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4522 (void **) &pSMBr);
4523 if (rc)
4524 return rc;
4525
4526 params = 2; /* level */
4527 pSMB->TotalDataCount = 0;
4528 pSMB->DataCount = 0;
4529 pSMB->DataOffset = 0;
4530 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004531 /* BB find exact max SMB PDU from sess structure BB */
4532 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 pSMB->MaxSetupCount = 0;
4534 pSMB->Reserved = 0;
4535 pSMB->Flags = 0;
4536 pSMB->Timeout = 0;
4537 pSMB->Reserved2 = 0;
4538 byte_count = params + 1 /* pad */ ;
4539 pSMB->ParameterCount = cpu_to_le16(params);
4540 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004541 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4542 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 pSMB->SetupCount = 1;
4544 pSMB->Reserved3 = 0;
4545 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4546 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4547 pSMB->hdr.smb_buf_length += byte_count;
4548 pSMB->ByteCount = cpu_to_le16(byte_count);
4549
4550 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4551 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4552 if (rc) {
4553 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4554 } else { /* decode response */
4555 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4556
4557 if (rc || (pSMBr->ByteCount < 13)) {
4558 rc = -EIO; /* bad smb */
4559 } else {
4560 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4561 response_data =
4562 (FILE_SYSTEM_POSIX_INFO
4563 *) (((char *) &pSMBr->hdr.Protocol) +
4564 data_offset);
4565 FSData->f_bsize =
4566 le32_to_cpu(response_data->BlockSize);
4567 FSData->f_blocks =
4568 le64_to_cpu(response_data->TotalBlocks);
4569 FSData->f_bfree =
4570 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004571 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 FSData->f_bavail = FSData->f_bfree;
4573 } else {
4574 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004575 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 }
Steve French790fe572007-07-07 19:25:05 +00004577 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004579 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004580 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004582 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 }
4584 }
4585 cifs_buf_release(pSMB);
4586
4587 if (rc == -EAGAIN)
4588 goto QFSPosixRetry;
4589
4590 return rc;
4591}
4592
4593
Steve French50c2f752007-07-13 00:33:32 +00004594/* We can not use write of zero bytes trick to
4595 set file size due to need for large file support. Also note that
4596 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 routine which is only needed to work around a sharing violation bug
4598 in Samba which this routine can run into */
4599
4600int
4601CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004602 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004603 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604{
4605 struct smb_com_transaction2_spi_req *pSMB = NULL;
4606 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4607 struct file_end_of_file_info *parm_data;
4608 int name_len;
4609 int rc = 0;
4610 int bytes_returned = 0;
4611 __u16 params, byte_count, data_count, param_offset, offset;
4612
4613 cFYI(1, ("In SetEOF"));
4614SetEOFRetry:
4615 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4616 (void **) &pSMBr);
4617 if (rc)
4618 return rc;
4619
4620 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4621 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004622 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004623 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 name_len++; /* trailing null */
4625 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004626 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 name_len = strnlen(fileName, PATH_MAX);
4628 name_len++; /* trailing null */
4629 strncpy(pSMB->FileName, fileName, name_len);
4630 }
4631 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004632 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004634 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 pSMB->MaxSetupCount = 0;
4636 pSMB->Reserved = 0;
4637 pSMB->Flags = 0;
4638 pSMB->Timeout = 0;
4639 pSMB->Reserved2 = 0;
4640 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004641 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004643 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004644 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4645 pSMB->InformationLevel =
4646 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4647 else
4648 pSMB->InformationLevel =
4649 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4650 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4652 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004653 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 else
4655 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004656 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 }
4658
4659 parm_data =
4660 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4661 offset);
4662 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4663 pSMB->DataOffset = cpu_to_le16(offset);
4664 pSMB->SetupCount = 1;
4665 pSMB->Reserved3 = 0;
4666 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4667 byte_count = 3 /* pad */ + params + data_count;
4668 pSMB->DataCount = cpu_to_le16(data_count);
4669 pSMB->TotalDataCount = pSMB->DataCount;
4670 pSMB->ParameterCount = cpu_to_le16(params);
4671 pSMB->TotalParameterCount = pSMB->ParameterCount;
4672 pSMB->Reserved4 = 0;
4673 pSMB->hdr.smb_buf_length += byte_count;
4674 parm_data->FileSize = cpu_to_le64(size);
4675 pSMB->ByteCount = cpu_to_le16(byte_count);
4676 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004678 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
4681 cifs_buf_release(pSMB);
4682
4683 if (rc == -EAGAIN)
4684 goto SetEOFRetry;
4685
4686 return rc;
4687}
4688
4689int
Steve French50c2f752007-07-13 00:33:32 +00004690CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004691 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692{
4693 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 char *data_offset;
4695 struct file_end_of_file_info *parm_data;
4696 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 __u16 params, param_offset, offset, byte_count, count;
4698
4699 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4700 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004701 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4702
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 if (rc)
4704 return rc;
4705
4706 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4707 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004708
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 params = 6;
4710 pSMB->MaxSetupCount = 0;
4711 pSMB->Reserved = 0;
4712 pSMB->Flags = 0;
4713 pSMB->Timeout = 0;
4714 pSMB->Reserved2 = 0;
4715 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4716 offset = param_offset + params;
4717
Steve French50c2f752007-07-13 00:33:32 +00004718 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719
4720 count = sizeof(struct file_end_of_file_info);
4721 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004722 /* BB find exact max SMB PDU from sess structure BB */
4723 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 pSMB->SetupCount = 1;
4725 pSMB->Reserved3 = 0;
4726 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4727 byte_count = 3 /* pad */ + params + count;
4728 pSMB->DataCount = cpu_to_le16(count);
4729 pSMB->ParameterCount = cpu_to_le16(params);
4730 pSMB->TotalDataCount = pSMB->DataCount;
4731 pSMB->TotalParameterCount = pSMB->ParameterCount;
4732 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4733 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004734 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4735 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 pSMB->DataOffset = cpu_to_le16(offset);
4737 parm_data->FileSize = cpu_to_le64(size);
4738 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004739 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4741 pSMB->InformationLevel =
4742 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4743 else
4744 pSMB->InformationLevel =
4745 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004746 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4748 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004749 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 else
4751 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004752 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 }
4754 pSMB->Reserved4 = 0;
4755 pSMB->hdr.smb_buf_length += byte_count;
4756 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004757 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 if (rc) {
4759 cFYI(1,
4760 ("Send error in SetFileInfo (SetFileSize) = %d",
4761 rc));
4762 }
4763
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 char *data_offset;
4782 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 __u16 params, param_offset, offset, byte_count, count;
4784
4785 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004786 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4787
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 if (rc)
4789 return rc;
4790
4791 /* At this point there is no need to override the current pid
4792 with the pid of the opener, but that could change if we someday
4793 use an existing handle (rather than opening one on the fly) */
4794 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4795 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004796
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 params = 6;
4798 pSMB->MaxSetupCount = 0;
4799 pSMB->Reserved = 0;
4800 pSMB->Flags = 0;
4801 pSMB->Timeout = 0;
4802 pSMB->Reserved2 = 0;
4803 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4804 offset = param_offset + params;
4805
Steve French50c2f752007-07-13 00:33:32 +00004806 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
Steve French26f57362007-08-30 22:09:15 +00004808 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004810 /* BB find max SMB PDU from sess */
4811 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 pSMB->SetupCount = 1;
4813 pSMB->Reserved3 = 0;
4814 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4815 byte_count = 3 /* pad */ + params + count;
4816 pSMB->DataCount = cpu_to_le16(count);
4817 pSMB->ParameterCount = cpu_to_le16(params);
4818 pSMB->TotalDataCount = pSMB->DataCount;
4819 pSMB->TotalParameterCount = pSMB->ParameterCount;
4820 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4821 pSMB->DataOffset = cpu_to_le16(offset);
4822 pSMB->Fid = fid;
4823 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4824 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4825 else
4826 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4827 pSMB->Reserved4 = 0;
4828 pSMB->hdr.smb_buf_length += byte_count;
4829 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004830 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004831 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004832 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004833 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834
Steve French50c2f752007-07-13 00:33:32 +00004835 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 since file handle passed in no longer valid */
4837
4838 return rc;
4839}
4840
4841
4842int
4843CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004844 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004845 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846{
4847 TRANSACTION2_SPI_REQ *pSMB = NULL;
4848 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4849 int name_len;
4850 int rc = 0;
4851 int bytes_returned = 0;
4852 char *data_offset;
4853 __u16 params, param_offset, offset, byte_count, count;
4854
4855 cFYI(1, ("In SetTimes"));
4856
4857SetTimesRetry:
4858 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4859 (void **) &pSMBr);
4860 if (rc)
4861 return rc;
4862
4863 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4864 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004865 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004866 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 name_len++; /* trailing null */
4868 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004869 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 name_len = strnlen(fileName, PATH_MAX);
4871 name_len++; /* trailing null */
4872 strncpy(pSMB->FileName, fileName, name_len);
4873 }
4874
4875 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004876 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004878 /* BB find max SMB PDU from sess structure BB */
4879 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 pSMB->MaxSetupCount = 0;
4881 pSMB->Reserved = 0;
4882 pSMB->Flags = 0;
4883 pSMB->Timeout = 0;
4884 pSMB->Reserved2 = 0;
4885 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004886 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 offset = param_offset + params;
4888 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4889 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4890 pSMB->DataOffset = cpu_to_le16(offset);
4891 pSMB->SetupCount = 1;
4892 pSMB->Reserved3 = 0;
4893 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4894 byte_count = 3 /* pad */ + params + count;
4895
4896 pSMB->DataCount = cpu_to_le16(count);
4897 pSMB->ParameterCount = cpu_to_le16(params);
4898 pSMB->TotalDataCount = pSMB->DataCount;
4899 pSMB->TotalParameterCount = pSMB->ParameterCount;
4900 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4901 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4902 else
4903 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4904 pSMB->Reserved4 = 0;
4905 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004906 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 pSMB->ByteCount = cpu_to_le16(byte_count);
4908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004910 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912
4913 cifs_buf_release(pSMB);
4914
4915 if (rc == -EAGAIN)
4916 goto SetTimesRetry;
4917
4918 return rc;
4919}
4920
4921/* Can not be used to set time stamps yet (due to old DOS time format) */
4922/* Can be used to set attributes */
4923#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4924 handling it anyway and NT4 was what we thought it would be needed for
4925 Do not delete it until we prove whether needed for Win9x though */
4926int
4927CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4928 __u16 dos_attrs, const struct nls_table *nls_codepage)
4929{
4930 SETATTR_REQ *pSMB = NULL;
4931 SETATTR_RSP *pSMBr = NULL;
4932 int rc = 0;
4933 int bytes_returned;
4934 int name_len;
4935
4936 cFYI(1, ("In SetAttrLegacy"));
4937
4938SetAttrLgcyRetry:
4939 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4940 (void **) &pSMBr);
4941 if (rc)
4942 return rc;
4943
4944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4945 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004946 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 PATH_MAX, nls_codepage);
4948 name_len++; /* trailing null */
4949 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004950 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 name_len = strnlen(fileName, PATH_MAX);
4952 name_len++; /* trailing null */
4953 strncpy(pSMB->fileName, fileName, name_len);
4954 }
4955 pSMB->attr = cpu_to_le16(dos_attrs);
4956 pSMB->BufferFormat = 0x04;
4957 pSMB->hdr.smb_buf_length += name_len + 1;
4958 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004961 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963
4964 cifs_buf_release(pSMB);
4965
4966 if (rc == -EAGAIN)
4967 goto SetAttrLgcyRetry;
4968
4969 return rc;
4970}
4971#endif /* temporarily unneeded SetAttr legacy function */
4972
4973int
4974CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004975 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4976 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004977 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978{
4979 TRANSACTION2_SPI_REQ *pSMB = NULL;
4980 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4981 int name_len;
4982 int rc = 0;
4983 int bytes_returned = 0;
4984 FILE_UNIX_BASIC_INFO *data_offset;
4985 __u16 params, param_offset, offset, count, byte_count;
4986
4987 cFYI(1, ("In SetUID/GID/Mode"));
4988setPermsRetry:
4989 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4990 (void **) &pSMBr);
4991 if (rc)
4992 return rc;
4993
4994 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4995 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004996 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004997 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 name_len++; /* trailing null */
4999 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005000 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 name_len = strnlen(fileName, PATH_MAX);
5002 name_len++; /* trailing null */
5003 strncpy(pSMB->FileName, fileName, name_len);
5004 }
5005
5006 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005007 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005009 /* BB find max SMB PDU from sess structure BB */
5010 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 pSMB->MaxSetupCount = 0;
5012 pSMB->Reserved = 0;
5013 pSMB->Flags = 0;
5014 pSMB->Timeout = 0;
5015 pSMB->Reserved2 = 0;
5016 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005017 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 offset = param_offset + params;
5019 data_offset =
5020 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5021 offset);
5022 memset(data_offset, 0, count);
5023 pSMB->DataOffset = cpu_to_le16(offset);
5024 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5025 pSMB->SetupCount = 1;
5026 pSMB->Reserved3 = 0;
5027 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5028 byte_count = 3 /* pad */ + params + count;
5029 pSMB->ParameterCount = cpu_to_le16(params);
5030 pSMB->DataCount = cpu_to_le16(count);
5031 pSMB->TotalParameterCount = pSMB->ParameterCount;
5032 pSMB->TotalDataCount = pSMB->DataCount;
5033 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5034 pSMB->Reserved4 = 0;
5035 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005036 /* Samba server ignores set of file size to zero due to bugs in some
5037 older clients, but we should be precise - we use SetFileSize to
5038 set file size and do not want to truncate file size to zero
5039 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005040 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005041 data_offset->EndOfFile = NO_CHANGE_64;
5042 data_offset->NumOfBytes = NO_CHANGE_64;
5043 data_offset->LastStatusChange = NO_CHANGE_64;
5044 data_offset->LastAccessTime = NO_CHANGE_64;
5045 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 data_offset->Uid = cpu_to_le64(uid);
5047 data_offset->Gid = cpu_to_le64(gid);
5048 /* better to leave device as zero when it is */
5049 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5050 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5051 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005052
Steve French790fe572007-07-07 19:25:05 +00005053 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005055 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005057 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005059 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005061 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005063 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005065 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5067
5068
5069 pSMB->ByteCount = cpu_to_le16(byte_count);
5070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005072 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074
5075 if (pSMB)
5076 cifs_buf_release(pSMB);
5077 if (rc == -EAGAIN)
5078 goto setPermsRetry;
5079 return rc;
5080}
5081
Steve French50c2f752007-07-13 00:33:32 +00005082int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005083 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005084 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005085 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086{
5087 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005088 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5089 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005090 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 int bytes_returned;
5092
Steve French50c2f752007-07-13 00:33:32 +00005093 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005095 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 if (rc)
5097 return rc;
5098
5099 pSMB->TotalParameterCount = 0 ;
5100 pSMB->TotalDataCount = 0;
5101 pSMB->MaxParameterCount = cpu_to_le32(2);
5102 /* BB find exact data count max from sess structure BB */
5103 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005104/* BB VERIFY verify which is correct for above BB */
5105 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5106 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5107
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 pSMB->MaxSetupCount = 4;
5109 pSMB->Reserved = 0;
5110 pSMB->ParameterOffset = 0;
5111 pSMB->DataCount = 0;
5112 pSMB->DataOffset = 0;
5113 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5114 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5115 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005116 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5118 pSMB->Reserved2 = 0;
5119 pSMB->CompletionFilter = cpu_to_le32(filter);
5120 pSMB->Fid = netfid; /* file handle always le */
5121 pSMB->ByteCount = 0;
5122
5123 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005124 (struct smb_hdr *)pSMBr, &bytes_returned,
5125 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 if (rc) {
5127 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005128 } else {
5129 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005130 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005131 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005132 sizeof(struct dir_notify_req),
5133 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005134 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005135 dnotify_req->Pid = pSMB->hdr.Pid;
5136 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5137 dnotify_req->Mid = pSMB->hdr.Mid;
5138 dnotify_req->Tid = pSMB->hdr.Tid;
5139 dnotify_req->Uid = pSMB->hdr.Uid;
5140 dnotify_req->netfid = netfid;
5141 dnotify_req->pfile = pfile;
5142 dnotify_req->filter = filter;
5143 dnotify_req->multishot = multishot;
5144 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005145 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005146 &GlobalDnotifyReqList);
5147 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005148 } else
Steve French47c786e2005-10-11 20:03:18 -07005149 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 }
5151 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005152 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153}
5154#ifdef CONFIG_CIFS_XATTR
5155ssize_t
5156CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5157 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005158 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005159 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160{
5161 /* BB assumes one setup word */
5162 TRANSACTION2_QPI_REQ *pSMB = NULL;
5163 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5164 int rc = 0;
5165 int bytes_returned;
5166 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005167 struct fea *temp_fea;
5168 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 __u16 params, byte_count;
5170
5171 cFYI(1, ("In Query All EAs path %s", searchName));
5172QAllEAsRetry:
5173 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5174 (void **) &pSMBr);
5175 if (rc)
5176 return rc;
5177
5178 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5179 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005180 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005181 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 name_len++; /* trailing null */
5183 name_len *= 2;
5184 } else { /* BB improve the check for buffer overruns BB */
5185 name_len = strnlen(searchName, PATH_MAX);
5186 name_len++; /* trailing null */
5187 strncpy(pSMB->FileName, searchName, name_len);
5188 }
5189
Steve French50c2f752007-07-13 00:33:32 +00005190 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 pSMB->TotalDataCount = 0;
5192 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005193 /* BB find exact max SMB PDU from sess structure BB */
5194 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 pSMB->MaxSetupCount = 0;
5196 pSMB->Reserved = 0;
5197 pSMB->Flags = 0;
5198 pSMB->Timeout = 0;
5199 pSMB->Reserved2 = 0;
5200 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005201 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 pSMB->DataCount = 0;
5203 pSMB->DataOffset = 0;
5204 pSMB->SetupCount = 1;
5205 pSMB->Reserved3 = 0;
5206 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5207 byte_count = params + 1 /* pad */ ;
5208 pSMB->TotalParameterCount = cpu_to_le16(params);
5209 pSMB->ParameterCount = pSMB->TotalParameterCount;
5210 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5211 pSMB->Reserved4 = 0;
5212 pSMB->hdr.smb_buf_length += byte_count;
5213 pSMB->ByteCount = cpu_to_le16(byte_count);
5214
5215 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5216 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5217 if (rc) {
5218 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5219 } else { /* decode response */
5220 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5221
5222 /* BB also check enough total bytes returned */
5223 /* BB we need to improve the validity checking
5224 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005225 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 rc = -EIO; /* bad smb */
5227 /* else if (pFindData){
5228 memcpy((char *) pFindData,
5229 (char *) &pSMBr->hdr.Protocol +
5230 data_offset, kl);
5231 }*/ else {
5232 /* check that length of list is not more than bcc */
5233 /* check that each entry does not go beyond length
5234 of list */
5235 /* check that each element of each entry does not
5236 go beyond end of list */
5237 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005238 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 rc = 0;
5240 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005241 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 ea_response_data = (struct fealist *)
5243 (((char *) &pSMBr->hdr.Protocol) +
5244 data_offset);
5245 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005246 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005247 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005249 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 } else {
5251 /* account for ea list len */
5252 name_len -= 4;
5253 temp_fea = ea_response_data->list;
5254 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005255 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 __u16 value_len;
5257 name_len -= 4;
5258 temp_ptr += 4;
5259 rc += temp_fea->name_len;
5260 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005261 rc = rc + 5 + 1;
5262 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005263 memcpy(EAData, "user.", 5);
5264 EAData += 5;
5265 memcpy(EAData, temp_ptr,
5266 temp_fea->name_len);
5267 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 /* null terminate name */
5269 *EAData = 0;
5270 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005271 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 /* skip copy - calc size only */
5273 } else {
5274 /* stop before overrun buffer */
5275 rc = -ERANGE;
5276 break;
5277 }
5278 name_len -= temp_fea->name_len;
5279 temp_ptr += temp_fea->name_len;
5280 /* account for trailing null */
5281 name_len--;
5282 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005283 value_len =
5284 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 name_len -= value_len;
5286 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005287 /* BB check that temp_ptr is still
5288 within the SMB BB*/
5289
5290 /* no trailing null to account for
5291 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 /* go on to next EA */
5293 temp_fea = (struct fea *)temp_ptr;
5294 }
5295 }
5296 }
5297 }
5298 if (pSMB)
5299 cifs_buf_release(pSMB);
5300 if (rc == -EAGAIN)
5301 goto QAllEAsRetry;
5302
5303 return (ssize_t)rc;
5304}
5305
Steve French50c2f752007-07-13 00:33:32 +00005306ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5307 const unsigned char *searchName, const unsigned char *ea_name,
5308 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005309 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310{
5311 TRANSACTION2_QPI_REQ *pSMB = NULL;
5312 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5313 int rc = 0;
5314 int bytes_returned;
5315 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005316 struct fea *temp_fea;
5317 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318 __u16 params, byte_count;
5319
5320 cFYI(1, ("In Query EA path %s", searchName));
5321QEARetry:
5322 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5323 (void **) &pSMBr);
5324 if (rc)
5325 return rc;
5326
5327 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5328 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005329 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005330 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 name_len++; /* trailing null */
5332 name_len *= 2;
5333 } else { /* BB improve the check for buffer overruns BB */
5334 name_len = strnlen(searchName, PATH_MAX);
5335 name_len++; /* trailing null */
5336 strncpy(pSMB->FileName, searchName, name_len);
5337 }
5338
Steve French50c2f752007-07-13 00:33:32 +00005339 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 pSMB->TotalDataCount = 0;
5341 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005342 /* BB find exact max SMB PDU from sess structure BB */
5343 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 pSMB->MaxSetupCount = 0;
5345 pSMB->Reserved = 0;
5346 pSMB->Flags = 0;
5347 pSMB->Timeout = 0;
5348 pSMB->Reserved2 = 0;
5349 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005350 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 pSMB->DataCount = 0;
5352 pSMB->DataOffset = 0;
5353 pSMB->SetupCount = 1;
5354 pSMB->Reserved3 = 0;
5355 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5356 byte_count = params + 1 /* pad */ ;
5357 pSMB->TotalParameterCount = cpu_to_le16(params);
5358 pSMB->ParameterCount = pSMB->TotalParameterCount;
5359 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5360 pSMB->Reserved4 = 0;
5361 pSMB->hdr.smb_buf_length += byte_count;
5362 pSMB->ByteCount = cpu_to_le16(byte_count);
5363
5364 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5365 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5366 if (rc) {
5367 cFYI(1, ("Send error in Query EA = %d", rc));
5368 } else { /* decode response */
5369 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5370
5371 /* BB also check enough total bytes returned */
5372 /* BB we need to improve the validity checking
5373 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005374 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 rc = -EIO; /* bad smb */
5376 /* else if (pFindData){
5377 memcpy((char *) pFindData,
5378 (char *) &pSMBr->hdr.Protocol +
5379 data_offset, kl);
5380 }*/ else {
5381 /* check that length of list is not more than bcc */
5382 /* check that each entry does not go beyond length
5383 of list */
5384 /* check that each element of each entry does not
5385 go beyond end of list */
5386 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005387 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 rc = -ENODATA;
5389 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005390 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 ea_response_data = (struct fealist *)
5392 (((char *) &pSMBr->hdr.Protocol) +
5393 data_offset);
5394 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005395 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005396 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005398 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 } else {
5400 /* account for ea list len */
5401 name_len -= 4;
5402 temp_fea = ea_response_data->list;
5403 temp_ptr = (char *)temp_fea;
5404 /* loop through checking if we have a matching
5405 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005406 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 __u16 value_len;
5408 name_len -= 4;
5409 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005410 value_len =
5411 le16_to_cpu(temp_fea->value_len);
5412 /* BB validate that value_len falls within SMB,
5413 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005414 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 temp_fea->name_len) == 0) {
5416 /* found a match */
5417 rc = value_len;
5418 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005419 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 memcpy(ea_value,
5421 temp_fea->name+temp_fea->name_len+1,
5422 rc);
Steve French50c2f752007-07-13 00:33:32 +00005423 /* ea values, unlike ea
5424 names, are not null
5425 terminated */
Steve French790fe572007-07-07 19:25:05 +00005426 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 /* skip copy - calc size only */
5428 } else {
Steve French50c2f752007-07-13 00:33:32 +00005429 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 rc = -ERANGE;
5431 }
5432 break;
5433 }
5434 name_len -= temp_fea->name_len;
5435 temp_ptr += temp_fea->name_len;
5436 /* account for trailing null */
5437 name_len--;
5438 temp_ptr++;
5439 name_len -= value_len;
5440 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005441 /* No trailing null to account for in
5442 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 temp_fea = (struct fea *)temp_ptr;
5444 }
Steve French50c2f752007-07-13 00:33:32 +00005445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 }
5447 }
5448 if (pSMB)
5449 cifs_buf_release(pSMB);
5450 if (rc == -EAGAIN)
5451 goto QEARetry;
5452
5453 return (ssize_t)rc;
5454}
5455
5456int
5457CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005458 const char *ea_name, const void *ea_value,
5459 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5460 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461{
5462 struct smb_com_transaction2_spi_req *pSMB = NULL;
5463 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5464 struct fealist *parm_data;
5465 int name_len;
5466 int rc = 0;
5467 int bytes_returned = 0;
5468 __u16 params, param_offset, byte_count, offset, count;
5469
5470 cFYI(1, ("In SetEA"));
5471SetEARetry:
5472 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5473 (void **) &pSMBr);
5474 if (rc)
5475 return rc;
5476
5477 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5478 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005479 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005480 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 name_len++; /* trailing null */
5482 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005483 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 name_len = strnlen(fileName, PATH_MAX);
5485 name_len++; /* trailing null */
5486 strncpy(pSMB->FileName, fileName, name_len);
5487 }
5488
5489 params = 6 + name_len;
5490
5491 /* done calculating parms using name_len of file name,
5492 now use name_len to calculate length of ea name
5493 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005494 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 name_len = 0;
5496 else
Steve French50c2f752007-07-13 00:33:32 +00005497 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005499 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005501 /* BB find max SMB PDU from sess */
5502 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 pSMB->MaxSetupCount = 0;
5504 pSMB->Reserved = 0;
5505 pSMB->Flags = 0;
5506 pSMB->Timeout = 0;
5507 pSMB->Reserved2 = 0;
5508 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005509 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 offset = param_offset + params;
5511 pSMB->InformationLevel =
5512 cpu_to_le16(SMB_SET_FILE_EA);
5513
5514 parm_data =
5515 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5516 offset);
5517 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5518 pSMB->DataOffset = cpu_to_le16(offset);
5519 pSMB->SetupCount = 1;
5520 pSMB->Reserved3 = 0;
5521 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5522 byte_count = 3 /* pad */ + params + count;
5523 pSMB->DataCount = cpu_to_le16(count);
5524 parm_data->list_len = cpu_to_le32(count);
5525 parm_data->list[0].EA_flags = 0;
5526 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005527 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005529 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005530 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 parm_data->list[0].name[name_len] = 0;
5532 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5533 /* caller ensures that ea_value_len is less than 64K but
5534 we need to ensure that it fits within the smb */
5535
Steve French50c2f752007-07-13 00:33:32 +00005536 /*BB add length check to see if it would fit in
5537 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005538 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5539 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005540 memcpy(parm_data->list[0].name+name_len+1,
5541 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542
5543 pSMB->TotalDataCount = pSMB->DataCount;
5544 pSMB->ParameterCount = cpu_to_le16(params);
5545 pSMB->TotalParameterCount = pSMB->ParameterCount;
5546 pSMB->Reserved4 = 0;
5547 pSMB->hdr.smb_buf_length += byte_count;
5548 pSMB->ByteCount = cpu_to_le16(byte_count);
5549 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5550 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005551 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553
5554 cifs_buf_release(pSMB);
5555
5556 if (rc == -EAGAIN)
5557 goto SetEARetry;
5558
5559 return rc;
5560}
5561
5562#endif