blob: 3c05c2de50e1e95530c78f89facb24f877ed3546 [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
1169int
1170SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1171 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001172 const int access_flags, const int create_options, __u16 *netfid,
1173 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 const struct nls_table *nls_codepage, int remap)
1175{
1176 int rc = -EACCES;
1177 OPENX_REQ *pSMB = NULL;
1178 OPENX_RSP *pSMBr = NULL;
1179 int bytes_returned;
1180 int name_len;
1181 __u16 count;
1182
1183OldOpenRetry:
1184 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1185 (void **) &pSMBr);
1186 if (rc)
1187 return rc;
1188
1189 pSMB->AndXCommand = 0xFF; /* none */
1190
1191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1192 count = 1; /* account for one byte pad to word boundary */
1193 name_len =
1194 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1195 fileName, PATH_MAX, nls_codepage, remap);
1196 name_len++; /* trailing null */
1197 name_len *= 2;
1198 } else { /* BB improve check for buffer overruns BB */
1199 count = 0; /* no pad */
1200 name_len = strnlen(fileName, PATH_MAX);
1201 name_len++; /* trailing null */
1202 strncpy(pSMB->fileName, fileName, name_len);
1203 }
1204 if (*pOplock & REQ_OPLOCK)
1205 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001206 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001208
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1210 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1211 /* 0 = read
1212 1 = write
1213 2 = rw
1214 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001215 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 pSMB->Mode = cpu_to_le16(2);
1217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1221
Steve French790fe572007-07-07 19:25:05 +00001222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001224 else /* BB FIXME BB */
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226
Jeff Layton67750fb2008-05-09 22:28:02 +00001227 if (create_options & CREATE_OPTION_READONLY)
1228 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229
1230 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001231/* pSMB->CreateOptions = cpu_to_le32(create_options &
1232 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001234
1235 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001236 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 count += name_len;
1238 pSMB->hdr.smb_buf_length += count;
1239
1240 pSMB->ByteCount = cpu_to_le16(count);
1241 /* long_op set to 1 to allow for oplock break timeouts */
1242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001243 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 cifs_stats_inc(&tcon->num_opens);
1245 if (rc) {
1246 cFYI(1, ("Error in Open = %d", rc));
1247 } else {
1248 /* BB verify if wct == 15 */
1249
Steve French582d21e2008-05-13 04:54:12 +00001250/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251
1252 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1253 /* Let caller know file was created so we can set the mode. */
1254 /* Do we care about the CreateAction in any other cases? */
1255 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001256/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 *pOplock |= CIFS_CREATE_ACTION; */
1258 /* BB FIXME END */
1259
Steve French790fe572007-07-07 19:25:05 +00001260 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1262 pfile_info->LastAccessTime = 0; /* BB fixme */
1263 pfile_info->LastWriteTime = 0; /* BB fixme */
1264 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001265 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001266 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->AllocationSize =
1269 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1270 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 pfile_info->NumberOfLinks = cpu_to_le32(1);
1272 }
1273 }
1274
1275 cifs_buf_release(pSMB);
1276 if (rc == -EAGAIN)
1277 goto OldOpenRetry;
1278 return rc;
1279}
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281int
1282CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1283 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001284 const int access_flags, const int create_options, __u16 *netfid,
1285 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001286 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287{
1288 int rc = -EACCES;
1289 OPEN_REQ *pSMB = NULL;
1290 OPEN_RSP *pSMBr = NULL;
1291 int bytes_returned;
1292 int name_len;
1293 __u16 count;
1294
1295openRetry:
1296 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1297 (void **) &pSMBr);
1298 if (rc)
1299 return rc;
1300
1301 pSMB->AndXCommand = 0xFF; /* none */
1302
1303 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1304 count = 1; /* account for one byte pad to word boundary */
1305 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001306 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001307 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 name_len++; /* trailing null */
1309 name_len *= 2;
1310 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001311 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 count = 0; /* no pad */
1313 name_len = strnlen(fileName, PATH_MAX);
1314 name_len++; /* trailing null */
1315 pSMB->NameLength = cpu_to_le16(name_len);
1316 strncpy(pSMB->fileName, fileName, name_len);
1317 }
1318 if (*pOplock & REQ_OPLOCK)
1319 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001320 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1323 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001324 /* set file as system file if special file such
1325 as fifo and server expecting SFU style and
1326 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001327 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001328 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1329 else
1330 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 /* XP does not handle ATTR_POSIX_SEMANTICS */
1333 /* but it helps speed up case sensitive checks for other
1334 servers such as Samba */
1335 if (tcon->ses->capabilities & CAP_UNIX)
1336 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1337
Jeff Layton67750fb2008-05-09 22:28:02 +00001338 if (create_options & CREATE_OPTION_READONLY)
1339 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1342 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001343 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001344 /* BB Expirement with various impersonation levels and verify */
1345 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 pSMB->SecurityFlags =
1347 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1348
1349 count += name_len;
1350 pSMB->hdr.smb_buf_length += count;
1351
1352 pSMB->ByteCount = cpu_to_le16(count);
1353 /* long_op set to 1 to allow for oplock break timeouts */
1354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001355 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001356 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 if (rc) {
1358 cFYI(1, ("Error in Open = %d", rc));
1359 } else {
Steve French09d1db52005-04-28 22:41:08 -07001360 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1362 /* Let caller know file was created so we can set the mode. */
1363 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001364 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001365 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001366 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001367 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 36 /* CreationTime to Attributes */);
1369 /* the file_info buf is endian converted by caller */
1370 pfile_info->AllocationSize = pSMBr->AllocationSize;
1371 pfile_info->EndOfFile = pSMBr->EndOfFile;
1372 pfile_info->NumberOfLinks = cpu_to_le32(1);
1373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 cifs_buf_release(pSMB);
1377 if (rc == -EAGAIN)
1378 goto openRetry;
1379 return rc;
1380}
1381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382int
Steve French50c2f752007-07-13 00:33:32 +00001383CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1384 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1385 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386{
1387 int rc = -EACCES;
1388 READ_REQ *pSMB = NULL;
1389 READ_RSP *pSMBr = NULL;
1390 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001391 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001392 int resp_buf_type = 0;
1393 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
Steve French790fe572007-07-07 19:25:05 +00001395 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1396 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001397 wct = 12;
1398 else
1399 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
1401 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001402 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if (rc)
1404 return rc;
1405
1406 /* tcon and ses pointer are checked in smb_init */
1407 if (tcon->ses->server == NULL)
1408 return -ECONNABORTED;
1409
Steve Frenchec637e32005-12-12 20:53:18 -08001410 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 pSMB->Fid = netfid;
1412 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001413 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001415 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001416 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 pSMB->Remaining = 0;
1419 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1420 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001421 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001422 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1423 else {
1424 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001425 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001426 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001427 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001428 }
Steve Frenchec637e32005-12-12 20:53:18 -08001429
1430 iov[0].iov_base = (char *)pSMB;
1431 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001432 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001433 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001434 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001435 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 if (rc) {
1437 cERROR(1, ("Send error in read = %d", rc));
1438 } else {
1439 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1440 data_length = data_length << 16;
1441 data_length += le16_to_cpu(pSMBr->DataLength);
1442 *nbytes = data_length;
1443
1444 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001445 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001447 cFYI(1, ("bad length %d for count %d",
1448 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 rc = -EIO;
1450 *nbytes = 0;
1451 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001452 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001453 le16_to_cpu(pSMBr->DataOffset);
1454/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001455 cERROR(1,("Faulting on read rc = %d",rc));
1456 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001457 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001458 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001459 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 }
1461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
Steve French4b8f9302006-02-26 16:41:18 +00001463/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001464 if (*buf) {
1465 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001466 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001467 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001468 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001469 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001470 /* return buffer to caller to free */
1471 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001472 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001473 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001474 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001475 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001476 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001477
1478 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 since file handle passed in no longer valid */
1480 return rc;
1481}
1482
Steve Frenchec637e32005-12-12 20:53:18 -08001483
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484int
1485CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1486 const int netfid, const unsigned int count,
1487 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001488 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489{
1490 int rc = -EACCES;
1491 WRITE_REQ *pSMB = NULL;
1492 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001493 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 __u32 bytes_sent;
1495 __u16 byte_count;
1496
1497 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001498 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001499 return -ECONNABORTED;
1500
Steve French790fe572007-07-07 19:25:05 +00001501 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001502 wct = 14;
1503 else
1504 wct = 12;
1505
1506 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 (void **) &pSMBr);
1508 if (rc)
1509 return rc;
1510 /* tcon and ses pointer are checked in smb_init */
1511 if (tcon->ses->server == NULL)
1512 return -ECONNABORTED;
1513
1514 pSMB->AndXCommand = 0xFF; /* none */
1515 pSMB->Fid = netfid;
1516 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001517 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001518 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001519 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001520 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001521
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 pSMB->Reserved = 0xFFFFFFFF;
1523 pSMB->WriteMode = 0;
1524 pSMB->Remaining = 0;
1525
Steve French50c2f752007-07-13 00:33:32 +00001526 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 can send more if LARGE_WRITE_X capability returned by the server and if
1528 our buffer is big enough or if we convert to iovecs on socket writes
1529 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001530 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1532 } else {
1533 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1534 & ~0xFF;
1535 }
1536
1537 if (bytes_sent > count)
1538 bytes_sent = count;
1539 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001540 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001541 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001542 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001543 else if (ubuf) {
1544 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 cifs_buf_release(pSMB);
1546 return -EFAULT;
1547 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001548 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 /* No buffer */
1550 cifs_buf_release(pSMB);
1551 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001552 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001553 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001554 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001555 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001557
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1559 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001560 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001561
Steve French790fe572007-07-07 19:25:05 +00001562 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001563 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001564 else { /* old style write has byte count 4 bytes earlier
1565 so 4 bytes pad */
1566 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001567 (struct smb_com_writex_req *)pSMB;
1568 pSMBW->ByteCount = cpu_to_le16(byte_count);
1569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
1571 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1572 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001573 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 if (rc) {
1575 cFYI(1, ("Send error in write = %d", rc));
1576 *nbytes = 0;
1577 } else {
1578 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1579 *nbytes = (*nbytes) << 16;
1580 *nbytes += le16_to_cpu(pSMBr->Count);
1581 }
1582
1583 cifs_buf_release(pSMB);
1584
Steve French50c2f752007-07-13 00:33:32 +00001585 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 since file handle passed in no longer valid */
1587
1588 return rc;
1589}
1590
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001591int
1592CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001594 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1595 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596{
1597 int rc = -EACCES;
1598 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001599 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001600 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001601 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602
Steve French790fe572007-07-07 19:25:05 +00001603 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001604
Steve French790fe572007-07-07 19:25:05 +00001605 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001606 wct = 14;
1607 else
1608 wct = 12;
1609 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if (rc)
1611 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 /* tcon and ses pointer are checked in smb_init */
1613 if (tcon->ses->server == NULL)
1614 return -ECONNABORTED;
1615
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001616 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 pSMB->Fid = netfid;
1618 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001619 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001620 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001621 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001622 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 pSMB->Reserved = 0xFFFFFFFF;
1624 pSMB->WriteMode = 0;
1625 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001626
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001628 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
Steve French3e844692005-10-03 13:37:24 -07001630 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1631 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001632 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001633 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001634 pSMB->hdr.smb_buf_length += count+1;
1635 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001636 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1637 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001638 pSMB->ByteCount = cpu_to_le16(count + 1);
1639 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001640 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001641 (struct smb_com_writex_req *)pSMB;
1642 pSMBW->ByteCount = cpu_to_le16(count + 5);
1643 }
Steve French3e844692005-10-03 13:37:24 -07001644 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001645 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001646 iov[0].iov_len = smb_hdr_len + 4;
1647 else /* wct == 12 pad bigger by four bytes */
1648 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001649
Steve French3e844692005-10-03 13:37:24 -07001650
Steve Frenchec637e32005-12-12 20:53:18 -08001651 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001652 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001653 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001655 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001657 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001658 /* presumably this can not happen, but best to be safe */
1659 rc = -EIO;
1660 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001661 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001662 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001663 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1664 *nbytes = (*nbytes) << 16;
1665 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
Steve French4b8f9302006-02-26 16:41:18 +00001668/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001669 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001670 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001671 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001672 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
Steve French50c2f752007-07-13 00:33:32 +00001674 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 since file handle passed in no longer valid */
1676
1677 return rc;
1678}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001679
1680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681int
1682CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1683 const __u16 smb_file_id, const __u64 len,
1684 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001685 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686{
1687 int rc = 0;
1688 LOCK_REQ *pSMB = NULL;
1689 LOCK_RSP *pSMBr = NULL;
1690 int bytes_returned;
1691 int timeout = 0;
1692 __u16 count;
1693
Steve French4b18f2a2008-04-29 00:06:05 +00001694 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001695 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 if (rc)
1698 return rc;
1699
Steve French46810cb2005-04-28 22:41:09 -07001700 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1701
Steve French790fe572007-07-07 19:25:05 +00001702 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001703 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001705 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001706 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1708 } else {
1709 pSMB->Timeout = 0;
1710 }
1711
1712 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1713 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1714 pSMB->LockType = lockType;
1715 pSMB->AndXCommand = 0xFF; /* none */
1716 pSMB->Fid = smb_file_id; /* netfid stays le */
1717
Steve French790fe572007-07-07 19:25:05 +00001718 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1720 /* BB where to store pid high? */
1721 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1722 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1723 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1724 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1725 count = sizeof(LOCKING_ANDX_RANGE);
1726 } else {
1727 /* oplock break */
1728 count = 0;
1729 }
1730 pSMB->hdr.smb_buf_length += count;
1731 pSMB->ByteCount = cpu_to_le16(count);
1732
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001733 if (waitFlag) {
1734 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1735 (struct smb_hdr *) pSMBr, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001736 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001737 } else {
Steve French133672e2007-11-13 22:41:37 +00001738 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1739 timeout);
1740 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001741 }
Steve Frencha4544342005-08-24 13:59:35 -07001742 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001743 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
Steve French50c2f752007-07-13 00:33:32 +00001746 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 since file handle passed in no longer valid */
1748 return rc;
1749}
1750
1751int
Steve French08547b02006-02-28 22:39:25 +00001752CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1753 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001754 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001755 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001756{
1757 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1758 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001759 struct cifs_posix_lock *parm_data;
1760 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001761 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001762 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001763 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001764 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001765 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001766
1767 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001768
Steve French790fe572007-07-07 19:25:05 +00001769 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001770 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001771
Steve French08547b02006-02-28 22:39:25 +00001772 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1773
1774 if (rc)
1775 return rc;
1776
1777 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1778
Steve French50c2f752007-07-13 00:33:32 +00001779 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001780 pSMB->MaxSetupCount = 0;
1781 pSMB->Reserved = 0;
1782 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001783 pSMB->Reserved2 = 0;
1784 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1785 offset = param_offset + params;
1786
Steve French08547b02006-02-28 22:39:25 +00001787 count = sizeof(struct cifs_posix_lock);
1788 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001789 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001790 pSMB->SetupCount = 1;
1791 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001792 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001793 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1794 else
1795 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1796 byte_count = 3 /* pad */ + params + count;
1797 pSMB->DataCount = cpu_to_le16(count);
1798 pSMB->ParameterCount = cpu_to_le16(params);
1799 pSMB->TotalDataCount = pSMB->DataCount;
1800 pSMB->TotalParameterCount = pSMB->ParameterCount;
1801 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001802 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001803 (((char *) &pSMB->hdr.Protocol) + offset);
1804
1805 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001806 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001807 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001808 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001809 pSMB->Timeout = cpu_to_le32(-1);
1810 } else
1811 pSMB->Timeout = 0;
1812
Steve French08547b02006-02-28 22:39:25 +00001813 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001814 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001815 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001816
1817 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001818 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001819 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1820 pSMB->Reserved4 = 0;
1821 pSMB->hdr.smb_buf_length += byte_count;
1822 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001823 if (waitFlag) {
1824 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1825 (struct smb_hdr *) pSMBr, &bytes_returned);
1826 } else {
Steve French133672e2007-11-13 22:41:37 +00001827 iov[0].iov_base = (char *)pSMB;
1828 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1829 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1830 &resp_buf_type, timeout);
1831 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1832 not try to free it twice below on exit */
1833 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001834 }
1835
Steve French08547b02006-02-28 22:39:25 +00001836 if (rc) {
1837 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001838 } else if (get_flag) {
1839 /* lock structure can be returned on get */
1840 __u16 data_offset;
1841 __u16 data_count;
1842 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001843
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001844 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1845 rc = -EIO; /* bad smb */
1846 goto plk_err_exit;
1847 }
Steve French790fe572007-07-07 19:25:05 +00001848 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001849 rc = -EINVAL;
1850 goto plk_err_exit;
1851 }
1852 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1853 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001854 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001855 rc = -EIO;
1856 goto plk_err_exit;
1857 }
1858 parm_data = (struct cifs_posix_lock *)
1859 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001860 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001861 pLockData->fl_type = F_UNLCK;
1862 }
Steve French50c2f752007-07-13 00:33:32 +00001863
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001864plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001865 if (pSMB)
1866 cifs_small_buf_release(pSMB);
1867
Steve French133672e2007-11-13 22:41:37 +00001868 if (resp_buf_type == CIFS_SMALL_BUFFER)
1869 cifs_small_buf_release(iov[0].iov_base);
1870 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1871 cifs_buf_release(iov[0].iov_base);
1872
Steve French08547b02006-02-28 22:39:25 +00001873 /* Note: On -EAGAIN error only caller can retry on handle based calls
1874 since file handle passed in no longer valid */
1875
1876 return rc;
1877}
1878
1879
1880int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1882{
1883 int rc = 0;
1884 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 cFYI(1, ("In CIFSSMBClose"));
1886
1887/* do not retry on dead session on close */
1888 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001889 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 return 0;
1891 if (rc)
1892 return rc;
1893
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001895 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001897 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001898 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001900 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 /* EINTR is expected when user ctl-c to kill app */
1902 cERROR(1, ("Send error in Close = %d", rc));
1903 }
1904 }
1905
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001907 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 rc = 0;
1909
1910 return rc;
1911}
1912
1913int
1914CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1915 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001916 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917{
1918 int rc = 0;
1919 RENAME_REQ *pSMB = NULL;
1920 RENAME_RSP *pSMBr = NULL;
1921 int bytes_returned;
1922 int name_len, name_len2;
1923 __u16 count;
1924
1925 cFYI(1, ("In CIFSSMBRename"));
1926renameRetry:
1927 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1928 (void **) &pSMBr);
1929 if (rc)
1930 return rc;
1931
1932 pSMB->BufferFormat = 0x04;
1933 pSMB->SearchAttributes =
1934 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1935 ATTR_DIRECTORY);
1936
1937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1938 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001939 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001940 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 name_len++; /* trailing null */
1942 name_len *= 2;
1943 pSMB->OldFileName[name_len] = 0x04; /* pad */
1944 /* protocol requires ASCII signature byte on Unicode string */
1945 pSMB->OldFileName[name_len + 1] = 0x00;
1946 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001947 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001948 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1950 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001951 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 name_len = strnlen(fromName, PATH_MAX);
1953 name_len++; /* trailing null */
1954 strncpy(pSMB->OldFileName, fromName, name_len);
1955 name_len2 = strnlen(toName, PATH_MAX);
1956 name_len2++; /* trailing null */
1957 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1958 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1959 name_len2++; /* trailing null */
1960 name_len2++; /* signature byte */
1961 }
1962
1963 count = 1 /* 1st signature byte */ + name_len + name_len2;
1964 pSMB->hdr.smb_buf_length += count;
1965 pSMB->ByteCount = cpu_to_le16(count);
1966
1967 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1968 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001969 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001970 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 cifs_buf_release(pSMB);
1974
1975 if (rc == -EAGAIN)
1976 goto renameRetry;
1977
1978 return rc;
1979}
1980
Steve French50c2f752007-07-13 00:33:32 +00001981int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1982 int netfid, char *target_name,
1983 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984{
1985 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1986 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001987 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 char *data_offset;
1989 char dummy_string[30];
1990 int rc = 0;
1991 int bytes_returned = 0;
1992 int len_of_str;
1993 __u16 params, param_offset, offset, count, byte_count;
1994
1995 cFYI(1, ("Rename to File by handle"));
1996 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1997 (void **) &pSMBr);
1998 if (rc)
1999 return rc;
2000
2001 params = 6;
2002 pSMB->MaxSetupCount = 0;
2003 pSMB->Reserved = 0;
2004 pSMB->Flags = 0;
2005 pSMB->Timeout = 0;
2006 pSMB->Reserved2 = 0;
2007 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2008 offset = param_offset + params;
2009
2010 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2011 rename_info = (struct set_file_rename *) data_offset;
2012 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002013 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 pSMB->SetupCount = 1;
2015 pSMB->Reserved3 = 0;
2016 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2017 byte_count = 3 /* pad */ + params;
2018 pSMB->ParameterCount = cpu_to_le16(params);
2019 pSMB->TotalParameterCount = pSMB->ParameterCount;
2020 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2021 pSMB->DataOffset = cpu_to_le16(offset);
2022 /* construct random name ".cifs_tmp<inodenum><mid>" */
2023 rename_info->overwrite = cpu_to_le32(1);
2024 rename_info->root_fid = 0;
2025 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002026 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002027 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2028 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002029 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002031 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002032 target_name, PATH_MAX, nls_codepage,
2033 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 }
2035 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2036 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2037 byte_count += count;
2038 pSMB->DataCount = cpu_to_le16(count);
2039 pSMB->TotalDataCount = pSMB->DataCount;
2040 pSMB->Fid = netfid;
2041 pSMB->InformationLevel =
2042 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2043 pSMB->Reserved4 = 0;
2044 pSMB->hdr.smb_buf_length += byte_count;
2045 pSMB->ByteCount = cpu_to_le16(byte_count);
2046 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002047 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002048 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002049 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002050 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002051
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 cifs_buf_release(pSMB);
2053
2054 /* Note: On -EAGAIN error only caller can retry on handle based calls
2055 since file handle passed in no longer valid */
2056
2057 return rc;
2058}
2059
2060int
Steve French50c2f752007-07-13 00:33:32 +00002061CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2062 const __u16 target_tid, const char *toName, const int flags,
2063 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064{
2065 int rc = 0;
2066 COPY_REQ *pSMB = NULL;
2067 COPY_RSP *pSMBr = NULL;
2068 int bytes_returned;
2069 int name_len, name_len2;
2070 __u16 count;
2071
2072 cFYI(1, ("In CIFSSMBCopy"));
2073copyRetry:
2074 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2075 (void **) &pSMBr);
2076 if (rc)
2077 return rc;
2078
2079 pSMB->BufferFormat = 0x04;
2080 pSMB->Tid2 = target_tid;
2081
2082 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2083
2084 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002085 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002086 fromName, PATH_MAX, nls_codepage,
2087 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 name_len++; /* trailing null */
2089 name_len *= 2;
2090 pSMB->OldFileName[name_len] = 0x04; /* pad */
2091 /* protocol requires ASCII signature byte on Unicode string */
2092 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002093 name_len2 =
2094 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002095 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2097 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002098 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 name_len = strnlen(fromName, PATH_MAX);
2100 name_len++; /* trailing null */
2101 strncpy(pSMB->OldFileName, fromName, name_len);
2102 name_len2 = strnlen(toName, PATH_MAX);
2103 name_len2++; /* trailing null */
2104 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2105 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2106 name_len2++; /* trailing null */
2107 name_len2++; /* signature byte */
2108 }
2109
2110 count = 1 /* 1st signature byte */ + name_len + name_len2;
2111 pSMB->hdr.smb_buf_length += count;
2112 pSMB->ByteCount = cpu_to_le16(count);
2113
2114 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2115 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2116 if (rc) {
2117 cFYI(1, ("Send error in copy = %d with %d files copied",
2118 rc, le16_to_cpu(pSMBr->CopyCount)));
2119 }
2120 if (pSMB)
2121 cifs_buf_release(pSMB);
2122
2123 if (rc == -EAGAIN)
2124 goto copyRetry;
2125
2126 return rc;
2127}
2128
2129int
2130CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2131 const char *fromName, const char *toName,
2132 const struct nls_table *nls_codepage)
2133{
2134 TRANSACTION2_SPI_REQ *pSMB = NULL;
2135 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2136 char *data_offset;
2137 int name_len;
2138 int name_len_target;
2139 int rc = 0;
2140 int bytes_returned = 0;
2141 __u16 params, param_offset, offset, byte_count;
2142
2143 cFYI(1, ("In Symlink Unix style"));
2144createSymLinkRetry:
2145 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2146 (void **) &pSMBr);
2147 if (rc)
2148 return rc;
2149
2150 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2151 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002152 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 /* find define for this maxpathcomponent */
2154 , nls_codepage);
2155 name_len++; /* trailing null */
2156 name_len *= 2;
2157
Steve French50c2f752007-07-13 00:33:32 +00002158 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 name_len = strnlen(fromName, PATH_MAX);
2160 name_len++; /* trailing null */
2161 strncpy(pSMB->FileName, fromName, name_len);
2162 }
2163 params = 6 + name_len;
2164 pSMB->MaxSetupCount = 0;
2165 pSMB->Reserved = 0;
2166 pSMB->Flags = 0;
2167 pSMB->Timeout = 0;
2168 pSMB->Reserved2 = 0;
2169 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002170 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 offset = param_offset + params;
2172
2173 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2174 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2175 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002176 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 /* find define for this maxpathcomponent */
2178 , nls_codepage);
2179 name_len_target++; /* trailing null */
2180 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002181 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 name_len_target = strnlen(toName, PATH_MAX);
2183 name_len_target++; /* trailing null */
2184 strncpy(data_offset, toName, name_len_target);
2185 }
2186
2187 pSMB->MaxParameterCount = cpu_to_le16(2);
2188 /* BB find exact max on data count below from sess */
2189 pSMB->MaxDataCount = cpu_to_le16(1000);
2190 pSMB->SetupCount = 1;
2191 pSMB->Reserved3 = 0;
2192 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2193 byte_count = 3 /* pad */ + params + name_len_target;
2194 pSMB->DataCount = cpu_to_le16(name_len_target);
2195 pSMB->ParameterCount = cpu_to_le16(params);
2196 pSMB->TotalDataCount = pSMB->DataCount;
2197 pSMB->TotalParameterCount = pSMB->ParameterCount;
2198 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2199 pSMB->DataOffset = cpu_to_le16(offset);
2200 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2201 pSMB->Reserved4 = 0;
2202 pSMB->hdr.smb_buf_length += byte_count;
2203 pSMB->ByteCount = cpu_to_le16(byte_count);
2204 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2205 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002206 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002207 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002208 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
2210 if (pSMB)
2211 cifs_buf_release(pSMB);
2212
2213 if (rc == -EAGAIN)
2214 goto createSymLinkRetry;
2215
2216 return rc;
2217}
2218
2219int
2220CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2221 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002222 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223{
2224 TRANSACTION2_SPI_REQ *pSMB = NULL;
2225 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2226 char *data_offset;
2227 int name_len;
2228 int name_len_target;
2229 int rc = 0;
2230 int bytes_returned = 0;
2231 __u16 params, param_offset, offset, byte_count;
2232
2233 cFYI(1, ("In Create Hard link Unix style"));
2234createHardLinkRetry:
2235 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2236 (void **) &pSMBr);
2237 if (rc)
2238 return rc;
2239
2240 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002241 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002242 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 name_len++; /* trailing null */
2244 name_len *= 2;
2245
Steve French50c2f752007-07-13 00:33:32 +00002246 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 name_len = strnlen(toName, PATH_MAX);
2248 name_len++; /* trailing null */
2249 strncpy(pSMB->FileName, toName, name_len);
2250 }
2251 params = 6 + name_len;
2252 pSMB->MaxSetupCount = 0;
2253 pSMB->Reserved = 0;
2254 pSMB->Flags = 0;
2255 pSMB->Timeout = 0;
2256 pSMB->Reserved2 = 0;
2257 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002258 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 offset = param_offset + params;
2260
2261 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2262 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2263 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002264 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002265 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 name_len_target++; /* trailing null */
2267 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002268 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 name_len_target = strnlen(fromName, PATH_MAX);
2270 name_len_target++; /* trailing null */
2271 strncpy(data_offset, fromName, name_len_target);
2272 }
2273
2274 pSMB->MaxParameterCount = cpu_to_le16(2);
2275 /* BB find exact max on data count below from sess*/
2276 pSMB->MaxDataCount = cpu_to_le16(1000);
2277 pSMB->SetupCount = 1;
2278 pSMB->Reserved3 = 0;
2279 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2280 byte_count = 3 /* pad */ + params + name_len_target;
2281 pSMB->ParameterCount = cpu_to_le16(params);
2282 pSMB->TotalParameterCount = pSMB->ParameterCount;
2283 pSMB->DataCount = cpu_to_le16(name_len_target);
2284 pSMB->TotalDataCount = pSMB->DataCount;
2285 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2286 pSMB->DataOffset = cpu_to_le16(offset);
2287 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2288 pSMB->Reserved4 = 0;
2289 pSMB->hdr.smb_buf_length += byte_count;
2290 pSMB->ByteCount = cpu_to_le16(byte_count);
2291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2292 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002293 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002294 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297 cifs_buf_release(pSMB);
2298 if (rc == -EAGAIN)
2299 goto createHardLinkRetry;
2300
2301 return rc;
2302}
2303
2304int
2305CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2306 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002307 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308{
2309 int rc = 0;
2310 NT_RENAME_REQ *pSMB = NULL;
2311 RENAME_RSP *pSMBr = NULL;
2312 int bytes_returned;
2313 int name_len, name_len2;
2314 __u16 count;
2315
2316 cFYI(1, ("In CIFSCreateHardLink"));
2317winCreateHardLinkRetry:
2318
2319 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2320 (void **) &pSMBr);
2321 if (rc)
2322 return rc;
2323
2324 pSMB->SearchAttributes =
2325 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2326 ATTR_DIRECTORY);
2327 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2328 pSMB->ClusterCount = 0;
2329
2330 pSMB->BufferFormat = 0x04;
2331
2332 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2333 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002334 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002335 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 name_len++; /* trailing null */
2337 name_len *= 2;
2338 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002339 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002341 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002342 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2344 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002345 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 name_len = strnlen(fromName, PATH_MAX);
2347 name_len++; /* trailing null */
2348 strncpy(pSMB->OldFileName, fromName, name_len);
2349 name_len2 = strnlen(toName, PATH_MAX);
2350 name_len2++; /* trailing null */
2351 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2352 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2353 name_len2++; /* trailing null */
2354 name_len2++; /* signature byte */
2355 }
2356
2357 count = 1 /* string type byte */ + name_len + name_len2;
2358 pSMB->hdr.smb_buf_length += count;
2359 pSMB->ByteCount = cpu_to_le16(count);
2360
2361 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2362 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002363 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002364 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002366
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 cifs_buf_release(pSMB);
2368 if (rc == -EAGAIN)
2369 goto winCreateHardLinkRetry;
2370
2371 return rc;
2372}
2373
2374int
2375CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2376 const unsigned char *searchName,
2377 char *symlinkinfo, const int buflen,
2378 const struct nls_table *nls_codepage)
2379{
2380/* SMB_QUERY_FILE_UNIX_LINK */
2381 TRANSACTION2_QPI_REQ *pSMB = NULL;
2382 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2383 int rc = 0;
2384 int bytes_returned;
2385 int name_len;
2386 __u16 params, byte_count;
2387
2388 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2389
2390querySymLinkRetry:
2391 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2392 (void **) &pSMBr);
2393 if (rc)
2394 return rc;
2395
2396 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2397 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002398 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2399 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 name_len++; /* trailing null */
2401 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002402 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 name_len = strnlen(searchName, PATH_MAX);
2404 name_len++; /* trailing null */
2405 strncpy(pSMB->FileName, searchName, name_len);
2406 }
2407
2408 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2409 pSMB->TotalDataCount = 0;
2410 pSMB->MaxParameterCount = cpu_to_le16(2);
2411 /* BB find exact max data count below from sess structure BB */
2412 pSMB->MaxDataCount = cpu_to_le16(4000);
2413 pSMB->MaxSetupCount = 0;
2414 pSMB->Reserved = 0;
2415 pSMB->Flags = 0;
2416 pSMB->Timeout = 0;
2417 pSMB->Reserved2 = 0;
2418 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002419 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 pSMB->DataCount = 0;
2421 pSMB->DataOffset = 0;
2422 pSMB->SetupCount = 1;
2423 pSMB->Reserved3 = 0;
2424 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2425 byte_count = params + 1 /* pad */ ;
2426 pSMB->TotalParameterCount = cpu_to_le16(params);
2427 pSMB->ParameterCount = pSMB->TotalParameterCount;
2428 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2429 pSMB->Reserved4 = 0;
2430 pSMB->hdr.smb_buf_length += byte_count;
2431 pSMB->ByteCount = cpu_to_le16(byte_count);
2432
2433 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2434 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2435 if (rc) {
2436 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2437 } else {
2438 /* decode response */
2439
2440 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2441 if (rc || (pSMBr->ByteCount < 2))
2442 /* BB also check enough total bytes returned */
2443 rc = -EIO; /* bad smb */
2444 else {
2445 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2446 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2447
2448 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2449 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002450 &pSMBr->hdr.Protocol + data_offset),
2451 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002452 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002454 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2455 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 name_len, nls_codepage);
2457 } else {
2458 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002459 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 data_offset,
2461 min_t(const int, buflen, count));
2462 }
2463 symlinkinfo[buflen] = 0;
2464 /* just in case so calling code does not go off the end of buffer */
2465 }
2466 }
2467 cifs_buf_release(pSMB);
2468 if (rc == -EAGAIN)
2469 goto querySymLinkRetry;
2470 return rc;
2471}
2472
Parag Warudkarc9489772007-10-23 18:09:48 +00002473#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002474/* Initialize NT TRANSACT SMB into small smb request buffer.
2475 This assumes that all NT TRANSACTS that we init here have
2476 total parm and data under about 400 bytes (to fit in small cifs
2477 buffer size), which is the case so far, it easily fits. NB:
2478 Setup words themselves and ByteCount
2479 MaxSetupCount (size of returned setup area) and
2480 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002481static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002482smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002483 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002484 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002485{
2486 int rc;
2487 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002488 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002489
2490 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2491 (void **)&pSMB);
2492 if (rc)
2493 return rc;
2494 *ret_buf = (void *)pSMB;
2495 pSMB->Reserved = 0;
2496 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2497 pSMB->TotalDataCount = 0;
2498 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2499 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2500 pSMB->ParameterCount = pSMB->TotalParameterCount;
2501 pSMB->DataCount = pSMB->TotalDataCount;
2502 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2503 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2504 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2505 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2506 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2507 pSMB->SubCommand = cpu_to_le16(sub_command);
2508 return 0;
2509}
2510
2511static int
Steve French50c2f752007-07-13 00:33:32 +00002512validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002513 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002514{
Steve French50c2f752007-07-13 00:33:32 +00002515 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002516 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002517 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002518
Steve French630f3f02007-10-25 21:17:17 +00002519 *pdatalen = 0;
2520 *pparmlen = 0;
2521
Steve French790fe572007-07-07 19:25:05 +00002522 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002523 return -EINVAL;
2524
2525 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2526
2527 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002528 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002529 (char *)&pSMBr->ByteCount;
2530
Steve French0a4b92c2006-01-12 15:44:21 -08002531 data_offset = le32_to_cpu(pSMBr->DataOffset);
2532 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002533 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002534 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2535
2536 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2537 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2538
2539 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002540 if (*ppparm > end_of_smb) {
2541 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002542 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002543 } else if (parm_count + *ppparm > end_of_smb) {
2544 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002545 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002546 } else if (*ppdata > end_of_smb) {
2547 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002548 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002549 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002550 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002551 *ppdata, data_count, (data_count + *ppdata),
2552 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002553 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002554 } else if (parm_count + data_count > pSMBr->ByteCount) {
2555 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002556 return -EINVAL;
2557 }
Steve French630f3f02007-10-25 21:17:17 +00002558 *pdatalen = data_count;
2559 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002560 return 0;
2561}
Parag Warudkarc9489772007-10-23 18:09:48 +00002562#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002563
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564int
2565CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2566 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002567 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 const struct nls_table *nls_codepage)
2569{
2570 int rc = 0;
2571 int bytes_returned;
2572 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002573 struct smb_com_transaction_ioctl_req *pSMB;
2574 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575
2576 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2577 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2578 (void **) &pSMBr);
2579 if (rc)
2580 return rc;
2581
2582 pSMB->TotalParameterCount = 0 ;
2583 pSMB->TotalDataCount = 0;
2584 pSMB->MaxParameterCount = cpu_to_le32(2);
2585 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002586 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2587 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 pSMB->MaxSetupCount = 4;
2589 pSMB->Reserved = 0;
2590 pSMB->ParameterOffset = 0;
2591 pSMB->DataCount = 0;
2592 pSMB->DataOffset = 0;
2593 pSMB->SetupCount = 4;
2594 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2595 pSMB->ParameterCount = pSMB->TotalParameterCount;
2596 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2597 pSMB->IsFsctl = 1; /* FSCTL */
2598 pSMB->IsRootFlag = 0;
2599 pSMB->Fid = fid; /* file handle always le */
2600 pSMB->ByteCount = 0;
2601
2602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2604 if (rc) {
2605 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2606 } else { /* decode response */
2607 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2608 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2609 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2610 /* BB also check enough total bytes returned */
2611 rc = -EIO; /* bad smb */
2612 else {
Steve French790fe572007-07-07 19:25:05 +00002613 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002614 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002615 pSMBr->ByteCount +
2616 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617
Steve French50c2f752007-07-13 00:33:32 +00002618 struct reparse_data *reparse_buf =
2619 (struct reparse_data *)
2620 ((char *)&pSMBr->hdr.Protocol
2621 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002622 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 rc = -EIO;
2624 goto qreparse_out;
2625 }
Steve French790fe572007-07-07 19:25:05 +00002626 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 reparse_buf->TargetNameOffset +
2628 reparse_buf->TargetNameLen) >
2629 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002630 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 rc = -EIO;
2632 goto qreparse_out;
2633 }
Steve French50c2f752007-07-13 00:33:32 +00002634
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2636 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002637 (reparse_buf->LinkNamesBuf +
2638 reparse_buf->TargetNameOffset),
2639 min(buflen/2,
2640 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002642 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 reparse_buf->TargetNameOffset),
2644 name_len, nls_codepage);
2645 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002646 strncpy(symlinkinfo,
2647 reparse_buf->LinkNamesBuf +
2648 reparse_buf->TargetNameOffset,
2649 min_t(const int, buflen,
2650 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 }
2652 } else {
2653 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002654 cFYI(1, ("Invalid return data count on "
2655 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 }
2657 symlinkinfo[buflen] = 0; /* just in case so the caller
2658 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002659 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 }
2661 }
2662qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002663 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
2665 /* Note: On -EAGAIN error only caller can retry on handle based calls
2666 since file handle passed in no longer valid */
2667
2668 return rc;
2669}
2670
2671#ifdef CONFIG_CIFS_POSIX
2672
2673/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002674static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2675 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676{
2677 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002678 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2679 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2680 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2682
2683 return;
2684}
2685
2686/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002687static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2688 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689{
2690 int size = 0;
2691 int i;
2692 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002693 struct cifs_posix_ace *pACE;
2694 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2695 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
2697 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2698 return -EOPNOTSUPP;
2699
Steve French790fe572007-07-07 19:25:05 +00002700 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 count = le16_to_cpu(cifs_acl->access_entry_count);
2702 pACE = &cifs_acl->ace_array[0];
2703 size = sizeof(struct cifs_posix_acl);
2704 size += sizeof(struct cifs_posix_ace) * count;
2705 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002706 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002707 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2708 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 return -EINVAL;
2710 }
Steve French790fe572007-07-07 19:25:05 +00002711 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 count = le16_to_cpu(cifs_acl->access_entry_count);
2713 size = sizeof(struct cifs_posix_acl);
2714 size += sizeof(struct cifs_posix_ace) * count;
2715/* skip past access ACEs to get to default ACEs */
2716 pACE = &cifs_acl->ace_array[count];
2717 count = le16_to_cpu(cifs_acl->default_entry_count);
2718 size += sizeof(struct cifs_posix_ace) * count;
2719 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002720 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 return -EINVAL;
2722 } else {
2723 /* illegal type */
2724 return -EINVAL;
2725 }
2726
2727 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002728 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002729 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002730 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 return -ERANGE;
2732 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002733 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002734 for (i = 0; i < count ; i++) {
2735 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2736 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 }
2738 }
2739 return size;
2740}
2741
Steve French50c2f752007-07-13 00:33:32 +00002742static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2743 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744{
2745 __u16 rc = 0; /* 0 = ACL converted ok */
2746
Steve Frenchff7feac2005-11-15 16:45:16 -08002747 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2748 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002750 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 /* Probably no need to le convert -1 on any arch but can not hurt */
2752 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002753 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002754 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002755 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 return rc;
2757}
2758
2759/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002760static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2761 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762{
2763 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002764 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2765 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 int count;
2767 int i;
2768
Steve French790fe572007-07-07 19:25:05 +00002769 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 return 0;
2771
2772 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002773 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002774 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002775 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002776 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002777 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002778 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 return 0;
2780 }
2781 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002782 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002783 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002784 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002785 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 else {
Steve French50c2f752007-07-13 00:33:32 +00002787 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 return 0;
2789 }
Steve French50c2f752007-07-13 00:33:32 +00002790 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2792 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002793 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 /* ACE not converted */
2795 break;
2796 }
2797 }
Steve French790fe572007-07-07 19:25:05 +00002798 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2800 rc += sizeof(struct cifs_posix_acl);
2801 /* BB add check to make sure ACL does not overflow SMB */
2802 }
2803 return rc;
2804}
2805
2806int
2807CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002808 const unsigned char *searchName,
2809 char *acl_inf, const int buflen, const int acl_type,
2810 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811{
2812/* SMB_QUERY_POSIX_ACL */
2813 TRANSACTION2_QPI_REQ *pSMB = NULL;
2814 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2815 int rc = 0;
2816 int bytes_returned;
2817 int name_len;
2818 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002819
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2821
2822queryAclRetry:
2823 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2824 (void **) &pSMBr);
2825 if (rc)
2826 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002827
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2829 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002830 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002831 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 name_len++; /* trailing null */
2833 name_len *= 2;
2834 pSMB->FileName[name_len] = 0;
2835 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002836 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 name_len = strnlen(searchName, PATH_MAX);
2838 name_len++; /* trailing null */
2839 strncpy(pSMB->FileName, searchName, name_len);
2840 }
2841
2842 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2843 pSMB->TotalDataCount = 0;
2844 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002845 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 pSMB->MaxDataCount = cpu_to_le16(4000);
2847 pSMB->MaxSetupCount = 0;
2848 pSMB->Reserved = 0;
2849 pSMB->Flags = 0;
2850 pSMB->Timeout = 0;
2851 pSMB->Reserved2 = 0;
2852 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002853 offsetof(struct smb_com_transaction2_qpi_req,
2854 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 pSMB->DataCount = 0;
2856 pSMB->DataOffset = 0;
2857 pSMB->SetupCount = 1;
2858 pSMB->Reserved3 = 0;
2859 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2860 byte_count = params + 1 /* pad */ ;
2861 pSMB->TotalParameterCount = cpu_to_le16(params);
2862 pSMB->ParameterCount = pSMB->TotalParameterCount;
2863 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2864 pSMB->Reserved4 = 0;
2865 pSMB->hdr.smb_buf_length += byte_count;
2866 pSMB->ByteCount = cpu_to_le16(byte_count);
2867
2868 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002870 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 if (rc) {
2872 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2873 } else {
2874 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002875
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2877 if (rc || (pSMBr->ByteCount < 2))
2878 /* BB also check enough total bytes returned */
2879 rc = -EIO; /* bad smb */
2880 else {
2881 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2882 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2883 rc = cifs_copy_posix_acl(acl_inf,
2884 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002885 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 }
2887 }
2888 cifs_buf_release(pSMB);
2889 if (rc == -EAGAIN)
2890 goto queryAclRetry;
2891 return rc;
2892}
2893
2894int
2895CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002896 const unsigned char *fileName,
2897 const char *local_acl, const int buflen,
2898 const int acl_type,
2899 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900{
2901 struct smb_com_transaction2_spi_req *pSMB = NULL;
2902 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2903 char *parm_data;
2904 int name_len;
2905 int rc = 0;
2906 int bytes_returned = 0;
2907 __u16 params, byte_count, data_count, param_offset, offset;
2908
2909 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2910setAclRetry:
2911 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002912 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 if (rc)
2914 return rc;
2915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2916 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002917 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002918 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 name_len++; /* trailing null */
2920 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002921 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 name_len = strnlen(fileName, PATH_MAX);
2923 name_len++; /* trailing null */
2924 strncpy(pSMB->FileName, fileName, name_len);
2925 }
2926 params = 6 + name_len;
2927 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002928 /* BB find max SMB size from sess */
2929 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 pSMB->MaxSetupCount = 0;
2931 pSMB->Reserved = 0;
2932 pSMB->Flags = 0;
2933 pSMB->Timeout = 0;
2934 pSMB->Reserved2 = 0;
2935 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002936 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 offset = param_offset + params;
2938 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2939 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2940
2941 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002942 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
Steve French790fe572007-07-07 19:25:05 +00002944 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 rc = -EOPNOTSUPP;
2946 goto setACLerrorExit;
2947 }
2948 pSMB->DataOffset = cpu_to_le16(offset);
2949 pSMB->SetupCount = 1;
2950 pSMB->Reserved3 = 0;
2951 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2952 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2953 byte_count = 3 /* pad */ + params + data_count;
2954 pSMB->DataCount = cpu_to_le16(data_count);
2955 pSMB->TotalDataCount = pSMB->DataCount;
2956 pSMB->ParameterCount = cpu_to_le16(params);
2957 pSMB->TotalParameterCount = pSMB->ParameterCount;
2958 pSMB->Reserved4 = 0;
2959 pSMB->hdr.smb_buf_length += byte_count;
2960 pSMB->ByteCount = cpu_to_le16(byte_count);
2961 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002962 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002963 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965
2966setACLerrorExit:
2967 cifs_buf_release(pSMB);
2968 if (rc == -EAGAIN)
2969 goto setAclRetry;
2970 return rc;
2971}
2972
Steve Frenchf654bac2005-04-28 22:41:04 -07002973/* BB fix tabs in this function FIXME BB */
2974int
2975CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002976 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002977{
Steve French50c2f752007-07-13 00:33:32 +00002978 int rc = 0;
2979 struct smb_t2_qfi_req *pSMB = NULL;
2980 struct smb_t2_qfi_rsp *pSMBr = NULL;
2981 int bytes_returned;
2982 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002983
Steve French790fe572007-07-07 19:25:05 +00002984 cFYI(1, ("In GetExtAttr"));
2985 if (tcon == NULL)
2986 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002987
2988GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002989 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2990 (void **) &pSMBr);
2991 if (rc)
2992 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002993
Steve Frenchad7a2922008-02-07 23:25:02 +00002994 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002995 pSMB->t2.TotalDataCount = 0;
2996 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2997 /* BB find exact max data count below from sess structure BB */
2998 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2999 pSMB->t2.MaxSetupCount = 0;
3000 pSMB->t2.Reserved = 0;
3001 pSMB->t2.Flags = 0;
3002 pSMB->t2.Timeout = 0;
3003 pSMB->t2.Reserved2 = 0;
3004 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3005 Fid) - 4);
3006 pSMB->t2.DataCount = 0;
3007 pSMB->t2.DataOffset = 0;
3008 pSMB->t2.SetupCount = 1;
3009 pSMB->t2.Reserved3 = 0;
3010 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3011 byte_count = params + 1 /* pad */ ;
3012 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3013 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3014 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3015 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003016 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003017 pSMB->hdr.smb_buf_length += byte_count;
3018 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003019
Steve French790fe572007-07-07 19:25:05 +00003020 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3021 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3022 if (rc) {
3023 cFYI(1, ("error %d in GetExtAttr", rc));
3024 } else {
3025 /* decode response */
3026 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3027 if (rc || (pSMBr->ByteCount < 2))
3028 /* BB also check enough total bytes returned */
3029 /* If rc should we check for EOPNOSUPP and
3030 disable the srvino flag? or in caller? */
3031 rc = -EIO; /* bad smb */
3032 else {
3033 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3034 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3035 struct file_chattr_info *pfinfo;
3036 /* BB Do we need a cast or hash here ? */
3037 if (count != 16) {
3038 cFYI(1, ("Illegal size ret in GetExtAttr"));
3039 rc = -EIO;
3040 goto GetExtAttrOut;
3041 }
3042 pfinfo = (struct file_chattr_info *)
3043 (data_offset + (char *) &pSMBr->hdr.Protocol);
3044 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003045 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003046 }
3047 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003048GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003049 cifs_buf_release(pSMB);
3050 if (rc == -EAGAIN)
3051 goto GetExtAttrRetry;
3052 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003053}
3054
Steve Frenchf654bac2005-04-28 22:41:04 -07003055#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
Steve French297647c2007-10-12 04:11:59 +00003057#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003058/* Get Security Descriptor (by handle) from remote server for a file or dir */
3059int
3060CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003061 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003062{
3063 int rc = 0;
3064 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003065 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003066 struct kvec iov[1];
3067
3068 cFYI(1, ("GetCifsACL"));
3069
Steve French630f3f02007-10-25 21:17:17 +00003070 *pbuflen = 0;
3071 *acl_inf = NULL;
3072
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003073 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003074 8 /* parm len */, tcon, (void **) &pSMB);
3075 if (rc)
3076 return rc;
3077
3078 pSMB->MaxParameterCount = cpu_to_le32(4);
3079 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3080 pSMB->MaxSetupCount = 0;
3081 pSMB->Fid = fid; /* file handle always le */
3082 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3083 CIFS_ACL_DACL);
3084 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3085 pSMB->hdr.smb_buf_length += 11;
3086 iov[0].iov_base = (char *)pSMB;
3087 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3088
Steve Frencha761ac52007-10-18 21:45:27 +00003089 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003090 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003091 cifs_stats_inc(&tcon->num_acl_get);
3092 if (rc) {
3093 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3094 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003095 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003096 __u32 parm_len;
3097 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003098 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003099 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003100
3101/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003102 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003103 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003104 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003105 goto qsec_out;
3106 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3107
Steve French630f3f02007-10-25 21:17:17 +00003108 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003109
3110 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3111 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003112 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003113 goto qsec_out;
3114 }
3115
3116/* BB check that data area is minimum length and as big as acl_len */
3117
Steve Frenchaf6f4612007-10-16 18:40:37 +00003118 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003119 if (acl_len != *pbuflen) {
3120 cERROR(1, ("acl length %d does not match %d",
3121 acl_len, *pbuflen));
3122 if (*pbuflen > acl_len)
3123 *pbuflen = acl_len;
3124 }
Steve French0a4b92c2006-01-12 15:44:21 -08003125
Steve French630f3f02007-10-25 21:17:17 +00003126 /* check if buffer is big enough for the acl
3127 header followed by the smallest SID */
3128 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3129 (*pbuflen >= 64 * 1024)) {
3130 cERROR(1, ("bad acl length %d", *pbuflen));
3131 rc = -EINVAL;
3132 *pbuflen = 0;
3133 } else {
3134 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3135 if (*acl_inf == NULL) {
3136 *pbuflen = 0;
3137 rc = -ENOMEM;
3138 }
3139 memcpy(*acl_inf, pdata, *pbuflen);
3140 }
Steve French0a4b92c2006-01-12 15:44:21 -08003141 }
3142qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003143 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003144 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003145 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003146 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003147/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003148 return rc;
3149}
Steve French97837582007-12-31 07:47:21 +00003150
3151int
3152CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3153 struct cifs_ntsd *pntsd, __u32 acllen)
3154{
3155 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3156 int rc = 0;
3157 int bytes_returned = 0;
3158 SET_SEC_DESC_REQ *pSMB = NULL;
3159 NTRANSACT_RSP *pSMBr = NULL;
3160
3161setCifsAclRetry:
3162 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3163 (void **) &pSMBr);
3164 if (rc)
3165 return (rc);
3166
3167 pSMB->MaxSetupCount = 0;
3168 pSMB->Reserved = 0;
3169
3170 param_count = 8;
3171 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3172 data_count = acllen;
3173 data_offset = param_offset + param_count;
3174 byte_count = 3 /* pad */ + param_count;
3175
3176 pSMB->DataCount = cpu_to_le32(data_count);
3177 pSMB->TotalDataCount = pSMB->DataCount;
3178 pSMB->MaxParameterCount = cpu_to_le32(4);
3179 pSMB->MaxDataCount = cpu_to_le32(16384);
3180 pSMB->ParameterCount = cpu_to_le32(param_count);
3181 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3182 pSMB->TotalParameterCount = pSMB->ParameterCount;
3183 pSMB->DataOffset = cpu_to_le32(data_offset);
3184 pSMB->SetupCount = 0;
3185 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3186 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3187
3188 pSMB->Fid = fid; /* file handle always le */
3189 pSMB->Reserved2 = 0;
3190 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3191
3192 if (pntsd && acllen) {
3193 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3194 (char *) pntsd,
3195 acllen);
3196 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3197
3198 } else
3199 pSMB->hdr.smb_buf_length += byte_count;
3200
3201 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3202 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3203
3204 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3205 if (rc)
3206 cFYI(1, ("Set CIFS ACL returned %d", rc));
3207 cifs_buf_release(pSMB);
3208
3209 if (rc == -EAGAIN)
3210 goto setCifsAclRetry;
3211
3212 return (rc);
3213}
3214
Steve French297647c2007-10-12 04:11:59 +00003215#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003216
Steve French6b8edfe2005-08-23 20:26:03 -07003217/* Legacy Query Path Information call for lookup to old servers such
3218 as Win9x/WinME */
3219int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003220 const unsigned char *searchName,
3221 FILE_ALL_INFO *pFinfo,
3222 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003223{
Steve Frenchad7a2922008-02-07 23:25:02 +00003224 QUERY_INFORMATION_REQ *pSMB;
3225 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003226 int rc = 0;
3227 int bytes_returned;
3228 int name_len;
3229
Steve French50c2f752007-07-13 00:33:32 +00003230 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003231QInfRetry:
3232 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003233 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003234 if (rc)
3235 return rc;
3236
3237 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3238 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003239 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3240 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003241 name_len++; /* trailing null */
3242 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003243 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003244 name_len = strnlen(searchName, PATH_MAX);
3245 name_len++; /* trailing null */
3246 strncpy(pSMB->FileName, searchName, name_len);
3247 }
3248 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003249 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003250 pSMB->hdr.smb_buf_length += (__u16) name_len;
3251 pSMB->ByteCount = cpu_to_le16(name_len);
3252
3253 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003254 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003255 if (rc) {
3256 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003257 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003258 struct timespec ts;
3259 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003260
3261 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003262 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003263 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003264 ts.tv_nsec = 0;
3265 ts.tv_sec = time;
3266 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003267 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003268 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3269 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003270 pFinfo->AllocationSize =
3271 cpu_to_le64(le32_to_cpu(pSMBr->size));
3272 pFinfo->EndOfFile = pFinfo->AllocationSize;
3273 pFinfo->Attributes =
3274 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003275 } else
3276 rc = -EIO; /* bad buffer passed in */
3277
3278 cifs_buf_release(pSMB);
3279
3280 if (rc == -EAGAIN)
3281 goto QInfRetry;
3282
3283 return rc;
3284}
3285
3286
3287
3288
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289int
3290CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3291 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003292 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003293 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003294 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295{
3296/* level 263 SMB_QUERY_FILE_ALL_INFO */
3297 TRANSACTION2_QPI_REQ *pSMB = NULL;
3298 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3299 int rc = 0;
3300 int bytes_returned;
3301 int name_len;
3302 __u16 params, byte_count;
3303
3304/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3305QPathInfoRetry:
3306 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3307 (void **) &pSMBr);
3308 if (rc)
3309 return rc;
3310
3311 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3312 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003313 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003314 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 name_len++; /* trailing null */
3316 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003317 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 name_len = strnlen(searchName, PATH_MAX);
3319 name_len++; /* trailing null */
3320 strncpy(pSMB->FileName, searchName, name_len);
3321 }
3322
Steve French50c2f752007-07-13 00:33:32 +00003323 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 pSMB->TotalDataCount = 0;
3325 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003326 /* BB find exact max SMB PDU from sess structure BB */
3327 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 pSMB->MaxSetupCount = 0;
3329 pSMB->Reserved = 0;
3330 pSMB->Flags = 0;
3331 pSMB->Timeout = 0;
3332 pSMB->Reserved2 = 0;
3333 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003334 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 pSMB->DataCount = 0;
3336 pSMB->DataOffset = 0;
3337 pSMB->SetupCount = 1;
3338 pSMB->Reserved3 = 0;
3339 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3340 byte_count = params + 1 /* pad */ ;
3341 pSMB->TotalParameterCount = cpu_to_le16(params);
3342 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003343 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003344 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3345 else
3346 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 pSMB->Reserved4 = 0;
3348 pSMB->hdr.smb_buf_length += byte_count;
3349 pSMB->ByteCount = cpu_to_le16(byte_count);
3350
3351 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3352 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3353 if (rc) {
3354 cFYI(1, ("Send error in QPathInfo = %d", rc));
3355 } else { /* decode response */
3356 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3357
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003358 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3359 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003360 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003362 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003363 rc = -EIO; /* 24 or 26 expected but we do not read
3364 last field */
3365 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003366 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003368
3369 /* On legacy responses we do not read the last field,
3370 EAsize, fortunately since it varies by subdialect and
3371 also note it differs on Set vs. Get, ie two bytes or 4
3372 bytes depending but we don't care here */
3373 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003374 size = sizeof(FILE_INFO_STANDARD);
3375 else
3376 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 memcpy((char *) pFindData,
3378 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003379 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 } else
3381 rc = -ENOMEM;
3382 }
3383 cifs_buf_release(pSMB);
3384 if (rc == -EAGAIN)
3385 goto QPathInfoRetry;
3386
3387 return rc;
3388}
3389
3390int
3391CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3392 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003393 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003394 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395{
3396/* SMB_QUERY_FILE_UNIX_BASIC */
3397 TRANSACTION2_QPI_REQ *pSMB = NULL;
3398 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3399 int rc = 0;
3400 int bytes_returned = 0;
3401 int name_len;
3402 __u16 params, byte_count;
3403
3404 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3405UnixQPathInfoRetry:
3406 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3407 (void **) &pSMBr);
3408 if (rc)
3409 return rc;
3410
3411 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3412 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003413 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003414 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 name_len++; /* trailing null */
3416 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003417 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 name_len = strnlen(searchName, PATH_MAX);
3419 name_len++; /* trailing null */
3420 strncpy(pSMB->FileName, searchName, name_len);
3421 }
3422
Steve French50c2f752007-07-13 00:33:32 +00003423 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 pSMB->TotalDataCount = 0;
3425 pSMB->MaxParameterCount = cpu_to_le16(2);
3426 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003427 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 pSMB->MaxSetupCount = 0;
3429 pSMB->Reserved = 0;
3430 pSMB->Flags = 0;
3431 pSMB->Timeout = 0;
3432 pSMB->Reserved2 = 0;
3433 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003434 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 pSMB->DataCount = 0;
3436 pSMB->DataOffset = 0;
3437 pSMB->SetupCount = 1;
3438 pSMB->Reserved3 = 0;
3439 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3440 byte_count = params + 1 /* pad */ ;
3441 pSMB->TotalParameterCount = cpu_to_le16(params);
3442 pSMB->ParameterCount = pSMB->TotalParameterCount;
3443 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3444 pSMB->Reserved4 = 0;
3445 pSMB->hdr.smb_buf_length += byte_count;
3446 pSMB->ByteCount = cpu_to_le16(byte_count);
3447
3448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3450 if (rc) {
3451 cFYI(1, ("Send error in QPathInfo = %d", rc));
3452 } else { /* decode response */
3453 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3454
3455 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003456 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3457 "Unix Extensions can be disabled on mount "
3458 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 rc = -EIO; /* bad smb */
3460 } else {
3461 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3462 memcpy((char *) pFindData,
3463 (char *) &pSMBr->hdr.Protocol +
3464 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003465 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 }
3467 }
3468 cifs_buf_release(pSMB);
3469 if (rc == -EAGAIN)
3470 goto UnixQPathInfoRetry;
3471
3472 return rc;
3473}
3474
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475/* xid, tcon, searchName and codepage are input parms, rest are returned */
3476int
3477CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003478 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003480 __u16 *pnetfid,
3481 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482{
3483/* level 257 SMB_ */
3484 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3485 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003486 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 int rc = 0;
3488 int bytes_returned = 0;
3489 int name_len;
3490 __u16 params, byte_count;
3491
Steve French50c2f752007-07-13 00:33:32 +00003492 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
3494findFirstRetry:
3495 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3496 (void **) &pSMBr);
3497 if (rc)
3498 return rc;
3499
3500 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3501 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003502 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003503 PATH_MAX, nls_codepage, remap);
3504 /* We can not add the asterik earlier in case
3505 it got remapped to 0xF03A as if it were part of the
3506 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003508 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003509 pSMB->FileName[name_len+1] = 0;
3510 pSMB->FileName[name_len+2] = '*';
3511 pSMB->FileName[name_len+3] = 0;
3512 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3514 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003515 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 } else { /* BB add check for overrun of SMB buf BB */
3517 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003519 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 free buffer exit; BB */
3521 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003522 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003523 pSMB->FileName[name_len+1] = '*';
3524 pSMB->FileName[name_len+2] = 0;
3525 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 }
3527
3528 params = 12 + name_len /* includes null */ ;
3529 pSMB->TotalDataCount = 0; /* no EAs */
3530 pSMB->MaxParameterCount = cpu_to_le16(10);
3531 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3532 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3533 pSMB->MaxSetupCount = 0;
3534 pSMB->Reserved = 0;
3535 pSMB->Flags = 0;
3536 pSMB->Timeout = 0;
3537 pSMB->Reserved2 = 0;
3538 byte_count = params + 1 /* pad */ ;
3539 pSMB->TotalParameterCount = cpu_to_le16(params);
3540 pSMB->ParameterCount = pSMB->TotalParameterCount;
3541 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003542 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3543 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 pSMB->DataCount = 0;
3545 pSMB->DataOffset = 0;
3546 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3547 pSMB->Reserved3 = 0;
3548 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3549 pSMB->SearchAttributes =
3550 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3551 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003552 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3553 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 CIFS_SEARCH_RETURN_RESUME);
3555 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3556
3557 /* BB what should we set StorageType to? Does it matter? BB */
3558 pSMB->SearchStorageType = 0;
3559 pSMB->hdr.smb_buf_length += byte_count;
3560 pSMB->ByteCount = cpu_to_le16(byte_count);
3561
3562 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3563 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003564 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
Steve French88274812006-03-09 22:21:45 +00003566 if (rc) {/* BB add logic to retry regular search if Unix search
3567 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 /* BB Add code to handle unsupported level rc */
3569 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003570
Steve French88274812006-03-09 22:21:45 +00003571 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
3573 /* BB eventually could optimize out free and realloc of buf */
3574 /* for this case */
3575 if (rc == -EAGAIN)
3576 goto findFirstRetry;
3577 } else { /* decode response */
3578 /* BB remember to free buffer if error BB */
3579 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003580 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003582 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 else
Steve French4b18f2a2008-04-29 00:06:05 +00003584 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585
3586 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003587 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003588 psrch_inf->srch_entries_start =
3589 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3592 le16_to_cpu(pSMBr->t2.ParameterOffset));
3593
Steve French790fe572007-07-07 19:25:05 +00003594 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003595 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 else
Steve French4b18f2a2008-04-29 00:06:05 +00003597 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
Steve French50c2f752007-07-13 00:33:32 +00003599 psrch_inf->entries_in_buffer =
3600 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003601 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 *pnetfid = parms->SearchHandle;
3604 } else {
3605 cifs_buf_release(pSMB);
3606 }
3607 }
3608
3609 return rc;
3610}
3611
3612int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003613 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614{
3615 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3616 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003617 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 char *response_data;
3619 int rc = 0;
3620 int bytes_returned, name_len;
3621 __u16 params, byte_count;
3622
3623 cFYI(1, ("In FindNext"));
3624
Steve French4b18f2a2008-04-29 00:06:05 +00003625 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 return -ENOENT;
3627
3628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3629 (void **) &pSMBr);
3630 if (rc)
3631 return rc;
3632
Steve French50c2f752007-07-13 00:33:32 +00003633 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 byte_count = 0;
3635 pSMB->TotalDataCount = 0; /* no EAs */
3636 pSMB->MaxParameterCount = cpu_to_le16(8);
3637 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003638 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3639 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 pSMB->MaxSetupCount = 0;
3641 pSMB->Reserved = 0;
3642 pSMB->Flags = 0;
3643 pSMB->Timeout = 0;
3644 pSMB->Reserved2 = 0;
3645 pSMB->ParameterOffset = cpu_to_le16(
3646 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3647 pSMB->DataCount = 0;
3648 pSMB->DataOffset = 0;
3649 pSMB->SetupCount = 1;
3650 pSMB->Reserved3 = 0;
3651 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3652 pSMB->SearchHandle = searchHandle; /* always kept as le */
3653 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003654 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3656 pSMB->ResumeKey = psrch_inf->resume_key;
3657 pSMB->SearchFlags =
3658 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3659
3660 name_len = psrch_inf->resume_name_len;
3661 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003662 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3664 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003665 /* 14 byte parm len above enough for 2 byte null terminator */
3666 pSMB->ResumeFileName[name_len] = 0;
3667 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 } else {
3669 rc = -EINVAL;
3670 goto FNext2_err_exit;
3671 }
3672 byte_count = params + 1 /* pad */ ;
3673 pSMB->TotalParameterCount = cpu_to_le16(params);
3674 pSMB->ParameterCount = pSMB->TotalParameterCount;
3675 pSMB->hdr.smb_buf_length += byte_count;
3676 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3679 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003680 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 if (rc) {
3682 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003683 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003684 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003685 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 } else
3687 cFYI(1, ("FindNext returned = %d", rc));
3688 } else { /* decode response */
3689 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003690
Steve French790fe572007-07-07 19:25:05 +00003691 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 /* BB fixme add lock for file (srch_info) struct here */
3693 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003694 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 else
Steve French4b18f2a2008-04-29 00:06:05 +00003696 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 response_data = (char *) &pSMBr->hdr.Protocol +
3698 le16_to_cpu(pSMBr->t2.ParameterOffset);
3699 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3700 response_data = (char *)&pSMBr->hdr.Protocol +
3701 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003702 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003703 cifs_small_buf_release(
3704 psrch_inf->ntwrk_buf_start);
3705 else
3706 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 psrch_inf->srch_entries_start = response_data;
3708 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003709 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003710 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003711 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 else
Steve French4b18f2a2008-04-29 00:06:05 +00003713 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003714 psrch_inf->entries_in_buffer =
3715 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 psrch_inf->index_of_last_entry +=
3717 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003718/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3719 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720
3721 /* BB fixme add unlock here */
3722 }
3723
3724 }
3725
3726 /* BB On error, should we leave previous search buf (and count and
3727 last entry fields) intact or free the previous one? */
3728
3729 /* Note: On -EAGAIN error only caller can retry on handle based calls
3730 since file handle passed in no longer valid */
3731FNext2_err_exit:
3732 if (rc != 0)
3733 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 return rc;
3735}
3736
3737int
Steve French50c2f752007-07-13 00:33:32 +00003738CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3739 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740{
3741 int rc = 0;
3742 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743
3744 cFYI(1, ("In CIFSSMBFindClose"));
3745 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3746
3747 /* no sense returning error if session restarted
3748 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003749 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 return 0;
3751 if (rc)
3752 return rc;
3753
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 pSMB->FileID = searchHandle;
3755 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003756 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003757 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003759
Steve Frencha4544342005-08-24 13:59:35 -07003760 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
3762 /* Since session is dead, search handle closed on server already */
3763 if (rc == -EAGAIN)
3764 rc = 0;
3765
3766 return rc;
3767}
3768
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769int
3770CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003771 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003772 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003773 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774{
3775 int rc = 0;
3776 TRANSACTION2_QPI_REQ *pSMB = NULL;
3777 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3778 int name_len, bytes_returned;
3779 __u16 params, byte_count;
3780
Steve French50c2f752007-07-13 00:33:32 +00003781 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003782 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003783 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
3785GetInodeNumberRetry:
3786 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003787 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 if (rc)
3789 return rc;
3790
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3792 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003793 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003794 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 name_len++; /* trailing null */
3796 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003797 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 name_len = strnlen(searchName, PATH_MAX);
3799 name_len++; /* trailing null */
3800 strncpy(pSMB->FileName, searchName, name_len);
3801 }
3802
3803 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3804 pSMB->TotalDataCount = 0;
3805 pSMB->MaxParameterCount = cpu_to_le16(2);
3806 /* BB find exact max data count below from sess structure BB */
3807 pSMB->MaxDataCount = cpu_to_le16(4000);
3808 pSMB->MaxSetupCount = 0;
3809 pSMB->Reserved = 0;
3810 pSMB->Flags = 0;
3811 pSMB->Timeout = 0;
3812 pSMB->Reserved2 = 0;
3813 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003814 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 pSMB->DataCount = 0;
3816 pSMB->DataOffset = 0;
3817 pSMB->SetupCount = 1;
3818 pSMB->Reserved3 = 0;
3819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3820 byte_count = params + 1 /* pad */ ;
3821 pSMB->TotalParameterCount = cpu_to_le16(params);
3822 pSMB->ParameterCount = pSMB->TotalParameterCount;
3823 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3824 pSMB->Reserved4 = 0;
3825 pSMB->hdr.smb_buf_length += byte_count;
3826 pSMB->ByteCount = cpu_to_le16(byte_count);
3827
3828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3830 if (rc) {
3831 cFYI(1, ("error %d in QueryInternalInfo", rc));
3832 } else {
3833 /* decode response */
3834 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3835 if (rc || (pSMBr->ByteCount < 2))
3836 /* BB also check enough total bytes returned */
3837 /* If rc should we check for EOPNOSUPP and
3838 disable the srvino flag? or in caller? */
3839 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003840 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3842 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003843 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003845 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3847 rc = -EIO;
3848 goto GetInodeNumOut;
3849 }
3850 pfinfo = (struct file_internal_info *)
3851 (data_offset + (char *) &pSMBr->hdr.Protocol);
3852 *inode_number = pfinfo->UniqueId;
3853 }
3854 }
3855GetInodeNumOut:
3856 cifs_buf_release(pSMB);
3857 if (rc == -EAGAIN)
3858 goto GetInodeNumberRetry;
3859 return rc;
3860}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861
3862int
3863CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3864 const unsigned char *searchName,
3865 unsigned char **targetUNCs,
3866 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003867 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868{
3869/* TRANS2_GET_DFS_REFERRAL */
3870 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3871 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003872 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 int rc = 0;
3874 int bytes_returned;
3875 int name_len;
3876 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003877 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 __u16 params, byte_count;
3879 *number_of_UNC_in_array = 0;
3880 *targetUNCs = NULL;
3881
3882 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3883 if (ses == NULL)
3884 return -ENODEV;
3885getDFSRetry:
3886 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3887 (void **) &pSMBr);
3888 if (rc)
3889 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003890
3891 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003892 but should never be null here anyway */
3893 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 pSMB->hdr.Tid = ses->ipc_tid;
3895 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003896 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003898 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900
3901 if (ses->capabilities & CAP_UNICODE) {
3902 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3903 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003904 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003905 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 name_len++; /* trailing null */
3907 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003908 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 name_len = strnlen(searchName, PATH_MAX);
3910 name_len++; /* trailing null */
3911 strncpy(pSMB->RequestFileName, searchName, name_len);
3912 }
3913
Steve French790fe572007-07-07 19:25:05 +00003914 if (ses->server) {
3915 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003916 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3917 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3918 }
3919
Steve French50c2f752007-07-13 00:33:32 +00003920 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003921
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 params = 2 /* level */ + name_len /*includes null */ ;
3923 pSMB->TotalDataCount = 0;
3924 pSMB->DataCount = 0;
3925 pSMB->DataOffset = 0;
3926 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00003927 /* BB find exact max SMB PDU from sess structure BB */
3928 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 pSMB->MaxSetupCount = 0;
3930 pSMB->Reserved = 0;
3931 pSMB->Flags = 0;
3932 pSMB->Timeout = 0;
3933 pSMB->Reserved2 = 0;
3934 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003935 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 pSMB->SetupCount = 1;
3937 pSMB->Reserved3 = 0;
3938 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3939 byte_count = params + 3 /* pad */ ;
3940 pSMB->ParameterCount = cpu_to_le16(params);
3941 pSMB->TotalParameterCount = pSMB->ParameterCount;
3942 pSMB->MaxReferralLevel = cpu_to_le16(3);
3943 pSMB->hdr.smb_buf_length += byte_count;
3944 pSMB->ByteCount = cpu_to_le16(byte_count);
3945
3946 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3948 if (rc) {
3949 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3950 } else { /* decode response */
3951/* BB Add logic to parse referrals here */
3952 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3953
Steve French50c2f752007-07-13 00:33:32 +00003954 /* BB Also check if enough total bytes returned? */
3955 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 rc = -EIO; /* bad smb */
3957 else {
Steve French50c2f752007-07-13 00:33:32 +00003958 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3960
3961 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003962 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003964 referrals =
3965 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 (8 /* sizeof start of data block */ +
3967 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003968 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003969 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003970 "for referral one refer size: 0x%x srv "
3971 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003972 le16_to_cpu(pSMBr->NumberOfReferrals),
3973 le16_to_cpu(pSMBr->DFSFlags),
3974 le16_to_cpu(referrals->ReferralSize),
3975 le16_to_cpu(referrals->ServerType),
3976 le16_to_cpu(referrals->ReferralFlags),
3977 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 /* BB This field is actually two bytes in from start of
3979 data block so we could do safety check that DataBlock
3980 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003981 *number_of_UNC_in_array =
3982 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
3984 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003985 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 *number_of_UNC_in_array = 1;
3987
3988 /* get the length of the strings describing refs */
3989 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003990 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003992 __u16 offset =
3993 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003995 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 not try to copy any more */
3997 *number_of_UNC_in_array = i;
3998 break;
Steve French50c2f752007-07-13 00:33:32 +00003999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 temp = ((char *)referrals) + offset;
4001
4002 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004003 name_len += UniStrnlen((wchar_t *)temp,
4004 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 } else {
Steve French50c2f752007-07-13 00:33:32 +00004006 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 }
4008 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004009 /* BB add check that referral pointer does
4010 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 }
4012 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004013 *targetUNCs =
4014 kmalloc(name_len+1+(*number_of_UNC_in_array),
4015 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004016 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 rc = -ENOMEM;
4018 goto GetDFSRefExit;
4019 }
4020 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004021 referrals = (struct dfs_referral_level_3 *)
4022 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 (char *) &pSMBr->hdr.Protocol);
4024
Steve French50c2f752007-07-13 00:33:32 +00004025 for (i = 0; i < *number_of_UNC_in_array; i++) {
4026 temp = ((char *)referrals) +
4027 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4029 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004030 (__le16 *) temp,
4031 name_len,
4032 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 } else {
Steve French50c2f752007-07-13 00:33:32 +00004034 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 }
4036 /* BB update target_uncs pointers */
4037 referrals++;
4038 }
4039 temp = *targetUNCs;
4040 temp[name_len] = 0;
4041 }
4042
4043 }
4044GetDFSRefExit:
4045 if (pSMB)
4046 cifs_buf_release(pSMB);
4047
4048 if (rc == -EAGAIN)
4049 goto getDFSRetry;
4050
4051 return rc;
4052}
4053
Steve French20962432005-09-21 22:05:57 -07004054/* Query File System Info such as free space to old servers such as Win 9x */
4055int
4056SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4057{
4058/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4059 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4060 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4061 FILE_SYSTEM_ALLOC_INFO *response_data;
4062 int rc = 0;
4063 int bytes_returned = 0;
4064 __u16 params, byte_count;
4065
4066 cFYI(1, ("OldQFSInfo"));
4067oldQFSInfoRetry:
4068 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4069 (void **) &pSMBr);
4070 if (rc)
4071 return rc;
Steve French20962432005-09-21 22:05:57 -07004072
4073 params = 2; /* level */
4074 pSMB->TotalDataCount = 0;
4075 pSMB->MaxParameterCount = cpu_to_le16(2);
4076 pSMB->MaxDataCount = cpu_to_le16(1000);
4077 pSMB->MaxSetupCount = 0;
4078 pSMB->Reserved = 0;
4079 pSMB->Flags = 0;
4080 pSMB->Timeout = 0;
4081 pSMB->Reserved2 = 0;
4082 byte_count = params + 1 /* pad */ ;
4083 pSMB->TotalParameterCount = cpu_to_le16(params);
4084 pSMB->ParameterCount = pSMB->TotalParameterCount;
4085 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4086 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4087 pSMB->DataCount = 0;
4088 pSMB->DataOffset = 0;
4089 pSMB->SetupCount = 1;
4090 pSMB->Reserved3 = 0;
4091 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4092 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4093 pSMB->hdr.smb_buf_length += byte_count;
4094 pSMB->ByteCount = cpu_to_le16(byte_count);
4095
4096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4098 if (rc) {
4099 cFYI(1, ("Send error in QFSInfo = %d", rc));
4100 } else { /* decode response */
4101 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4102
4103 if (rc || (pSMBr->ByteCount < 18))
4104 rc = -EIO; /* bad smb */
4105 else {
4106 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004107 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004108 pSMBr->ByteCount, data_offset));
4109
Steve French50c2f752007-07-13 00:33:32 +00004110 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004111 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4112 FSData->f_bsize =
4113 le16_to_cpu(response_data->BytesPerSector) *
4114 le32_to_cpu(response_data->
4115 SectorsPerAllocationUnit);
4116 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004117 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004118 FSData->f_bfree = FSData->f_bavail =
4119 le32_to_cpu(response_data->FreeAllocationUnits);
4120 cFYI(1,
4121 ("Blocks: %lld Free: %lld Block size %ld",
4122 (unsigned long long)FSData->f_blocks,
4123 (unsigned long long)FSData->f_bfree,
4124 FSData->f_bsize));
4125 }
4126 }
4127 cifs_buf_release(pSMB);
4128
4129 if (rc == -EAGAIN)
4130 goto oldQFSInfoRetry;
4131
4132 return rc;
4133}
4134
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135int
Steve French737b7582005-04-28 22:41:06 -07004136CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137{
4138/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4139 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4140 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4141 FILE_SYSTEM_INFO *response_data;
4142 int rc = 0;
4143 int bytes_returned = 0;
4144 __u16 params, byte_count;
4145
4146 cFYI(1, ("In QFSInfo"));
4147QFSInfoRetry:
4148 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4149 (void **) &pSMBr);
4150 if (rc)
4151 return rc;
4152
4153 params = 2; /* level */
4154 pSMB->TotalDataCount = 0;
4155 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004156 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 pSMB->MaxSetupCount = 0;
4158 pSMB->Reserved = 0;
4159 pSMB->Flags = 0;
4160 pSMB->Timeout = 0;
4161 pSMB->Reserved2 = 0;
4162 byte_count = params + 1 /* pad */ ;
4163 pSMB->TotalParameterCount = cpu_to_le16(params);
4164 pSMB->ParameterCount = pSMB->TotalParameterCount;
4165 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004166 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 pSMB->DataCount = 0;
4168 pSMB->DataOffset = 0;
4169 pSMB->SetupCount = 1;
4170 pSMB->Reserved3 = 0;
4171 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4172 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4173 pSMB->hdr.smb_buf_length += byte_count;
4174 pSMB->ByteCount = cpu_to_le16(byte_count);
4175
4176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4178 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004179 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004181 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
Steve French20962432005-09-21 22:05:57 -07004183 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 rc = -EIO; /* bad smb */
4185 else {
4186 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
4188 response_data =
4189 (FILE_SYSTEM_INFO
4190 *) (((char *) &pSMBr->hdr.Protocol) +
4191 data_offset);
4192 FSData->f_bsize =
4193 le32_to_cpu(response_data->BytesPerSector) *
4194 le32_to_cpu(response_data->
4195 SectorsPerAllocationUnit);
4196 FSData->f_blocks =
4197 le64_to_cpu(response_data->TotalAllocationUnits);
4198 FSData->f_bfree = FSData->f_bavail =
4199 le64_to_cpu(response_data->FreeAllocationUnits);
4200 cFYI(1,
4201 ("Blocks: %lld Free: %lld Block size %ld",
4202 (unsigned long long)FSData->f_blocks,
4203 (unsigned long long)FSData->f_bfree,
4204 FSData->f_bsize));
4205 }
4206 }
4207 cifs_buf_release(pSMB);
4208
4209 if (rc == -EAGAIN)
4210 goto QFSInfoRetry;
4211
4212 return rc;
4213}
4214
4215int
Steve French737b7582005-04-28 22:41:06 -07004216CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4219 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4220 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4221 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4222 int rc = 0;
4223 int bytes_returned = 0;
4224 __u16 params, byte_count;
4225
4226 cFYI(1, ("In QFSAttributeInfo"));
4227QFSAttributeRetry:
4228 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4229 (void **) &pSMBr);
4230 if (rc)
4231 return rc;
4232
4233 params = 2; /* level */
4234 pSMB->TotalDataCount = 0;
4235 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004236 /* BB find exact max SMB PDU from sess structure BB */
4237 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 pSMB->MaxSetupCount = 0;
4239 pSMB->Reserved = 0;
4240 pSMB->Flags = 0;
4241 pSMB->Timeout = 0;
4242 pSMB->Reserved2 = 0;
4243 byte_count = params + 1 /* pad */ ;
4244 pSMB->TotalParameterCount = cpu_to_le16(params);
4245 pSMB->ParameterCount = pSMB->TotalParameterCount;
4246 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004247 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 pSMB->DataCount = 0;
4249 pSMB->DataOffset = 0;
4250 pSMB->SetupCount = 1;
4251 pSMB->Reserved3 = 0;
4252 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4253 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4254 pSMB->hdr.smb_buf_length += byte_count;
4255 pSMB->ByteCount = cpu_to_le16(byte_count);
4256
4257 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4258 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4259 if (rc) {
4260 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4261 } else { /* decode response */
4262 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4263
Steve French50c2f752007-07-13 00:33:32 +00004264 if (rc || (pSMBr->ByteCount < 13)) {
4265 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 rc = -EIO; /* bad smb */
4267 } else {
4268 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4269 response_data =
4270 (FILE_SYSTEM_ATTRIBUTE_INFO
4271 *) (((char *) &pSMBr->hdr.Protocol) +
4272 data_offset);
4273 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004274 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 }
4276 }
4277 cifs_buf_release(pSMB);
4278
4279 if (rc == -EAGAIN)
4280 goto QFSAttributeRetry;
4281
4282 return rc;
4283}
4284
4285int
Steve French737b7582005-04-28 22:41:06 -07004286CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287{
4288/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4289 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4290 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4291 FILE_SYSTEM_DEVICE_INFO *response_data;
4292 int rc = 0;
4293 int bytes_returned = 0;
4294 __u16 params, byte_count;
4295
4296 cFYI(1, ("In QFSDeviceInfo"));
4297QFSDeviceRetry:
4298 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4299 (void **) &pSMBr);
4300 if (rc)
4301 return rc;
4302
4303 params = 2; /* level */
4304 pSMB->TotalDataCount = 0;
4305 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004306 /* BB find exact max SMB PDU from sess structure BB */
4307 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 pSMB->MaxSetupCount = 0;
4309 pSMB->Reserved = 0;
4310 pSMB->Flags = 0;
4311 pSMB->Timeout = 0;
4312 pSMB->Reserved2 = 0;
4313 byte_count = params + 1 /* pad */ ;
4314 pSMB->TotalParameterCount = cpu_to_le16(params);
4315 pSMB->ParameterCount = pSMB->TotalParameterCount;
4316 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004317 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
4319 pSMB->DataCount = 0;
4320 pSMB->DataOffset = 0;
4321 pSMB->SetupCount = 1;
4322 pSMB->Reserved3 = 0;
4323 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4324 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4325 pSMB->hdr.smb_buf_length += byte_count;
4326 pSMB->ByteCount = cpu_to_le16(byte_count);
4327
4328 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4329 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4330 if (rc) {
4331 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4332 } else { /* decode response */
4333 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4334
Steve French630f3f02007-10-25 21:17:17 +00004335 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 rc = -EIO; /* bad smb */
4337 else {
4338 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4339 response_data =
Steve French737b7582005-04-28 22:41:06 -07004340 (FILE_SYSTEM_DEVICE_INFO *)
4341 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 data_offset);
4343 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004344 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 }
4346 }
4347 cifs_buf_release(pSMB);
4348
4349 if (rc == -EAGAIN)
4350 goto QFSDeviceRetry;
4351
4352 return rc;
4353}
4354
4355int
Steve French737b7582005-04-28 22:41:06 -07004356CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357{
4358/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4359 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4360 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4361 FILE_SYSTEM_UNIX_INFO *response_data;
4362 int rc = 0;
4363 int bytes_returned = 0;
4364 __u16 params, byte_count;
4365
4366 cFYI(1, ("In QFSUnixInfo"));
4367QFSUnixRetry:
4368 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4369 (void **) &pSMBr);
4370 if (rc)
4371 return rc;
4372
4373 params = 2; /* level */
4374 pSMB->TotalDataCount = 0;
4375 pSMB->DataCount = 0;
4376 pSMB->DataOffset = 0;
4377 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004378 /* BB find exact max SMB PDU from sess structure BB */
4379 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 pSMB->MaxSetupCount = 0;
4381 pSMB->Reserved = 0;
4382 pSMB->Flags = 0;
4383 pSMB->Timeout = 0;
4384 pSMB->Reserved2 = 0;
4385 byte_count = params + 1 /* pad */ ;
4386 pSMB->ParameterCount = cpu_to_le16(params);
4387 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004388 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4389 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 pSMB->SetupCount = 1;
4391 pSMB->Reserved3 = 0;
4392 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4393 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4394 pSMB->hdr.smb_buf_length += byte_count;
4395 pSMB->ByteCount = cpu_to_le16(byte_count);
4396
4397 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4398 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4399 if (rc) {
4400 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4401 } else { /* decode response */
4402 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4403
4404 if (rc || (pSMBr->ByteCount < 13)) {
4405 rc = -EIO; /* bad smb */
4406 } else {
4407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4408 response_data =
4409 (FILE_SYSTEM_UNIX_INFO
4410 *) (((char *) &pSMBr->hdr.Protocol) +
4411 data_offset);
4412 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004413 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 }
4415 }
4416 cifs_buf_release(pSMB);
4417
4418 if (rc == -EAGAIN)
4419 goto QFSUnixRetry;
4420
4421
4422 return rc;
4423}
4424
Jeremy Allisonac670552005-06-22 17:26:35 -07004425int
Steve French45abc6e2005-06-23 13:42:03 -05004426CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004427{
4428/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4429 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4430 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4431 int rc = 0;
4432 int bytes_returned = 0;
4433 __u16 params, param_offset, offset, byte_count;
4434
4435 cFYI(1, ("In SETFSUnixInfo"));
4436SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004437 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4439 (void **) &pSMBr);
4440 if (rc)
4441 return rc;
4442
4443 params = 4; /* 2 bytes zero followed by info level. */
4444 pSMB->MaxSetupCount = 0;
4445 pSMB->Reserved = 0;
4446 pSMB->Flags = 0;
4447 pSMB->Timeout = 0;
4448 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004449 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4450 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004451 offset = param_offset + params;
4452
4453 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004454 /* BB find exact max SMB PDU from sess structure BB */
4455 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004456 pSMB->SetupCount = 1;
4457 pSMB->Reserved3 = 0;
4458 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4459 byte_count = 1 /* pad */ + params + 12;
4460
4461 pSMB->DataCount = cpu_to_le16(12);
4462 pSMB->ParameterCount = cpu_to_le16(params);
4463 pSMB->TotalDataCount = pSMB->DataCount;
4464 pSMB->TotalParameterCount = pSMB->ParameterCount;
4465 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4466 pSMB->DataOffset = cpu_to_le16(offset);
4467
4468 /* Params. */
4469 pSMB->FileNum = 0;
4470 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4471
4472 /* Data. */
4473 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4474 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4475 pSMB->ClientUnixCap = cpu_to_le64(cap);
4476
4477 pSMB->hdr.smb_buf_length += byte_count;
4478 pSMB->ByteCount = cpu_to_le16(byte_count);
4479
4480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4482 if (rc) {
4483 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4484 } else { /* decode response */
4485 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004486 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004487 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004488 }
4489 cifs_buf_release(pSMB);
4490
4491 if (rc == -EAGAIN)
4492 goto SETFSUnixRetry;
4493
4494 return rc;
4495}
4496
4497
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498
4499int
4500CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004501 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502{
4503/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4504 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4505 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4506 FILE_SYSTEM_POSIX_INFO *response_data;
4507 int rc = 0;
4508 int bytes_returned = 0;
4509 __u16 params, byte_count;
4510
4511 cFYI(1, ("In QFSPosixInfo"));
4512QFSPosixRetry:
4513 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4514 (void **) &pSMBr);
4515 if (rc)
4516 return rc;
4517
4518 params = 2; /* level */
4519 pSMB->TotalDataCount = 0;
4520 pSMB->DataCount = 0;
4521 pSMB->DataOffset = 0;
4522 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004523 /* BB find exact max SMB PDU from sess structure BB */
4524 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 pSMB->MaxSetupCount = 0;
4526 pSMB->Reserved = 0;
4527 pSMB->Flags = 0;
4528 pSMB->Timeout = 0;
4529 pSMB->Reserved2 = 0;
4530 byte_count = params + 1 /* pad */ ;
4531 pSMB->ParameterCount = cpu_to_le16(params);
4532 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004533 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4534 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 pSMB->SetupCount = 1;
4536 pSMB->Reserved3 = 0;
4537 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4538 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4539 pSMB->hdr.smb_buf_length += byte_count;
4540 pSMB->ByteCount = cpu_to_le16(byte_count);
4541
4542 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4543 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4544 if (rc) {
4545 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4546 } else { /* decode response */
4547 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4548
4549 if (rc || (pSMBr->ByteCount < 13)) {
4550 rc = -EIO; /* bad smb */
4551 } else {
4552 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4553 response_data =
4554 (FILE_SYSTEM_POSIX_INFO
4555 *) (((char *) &pSMBr->hdr.Protocol) +
4556 data_offset);
4557 FSData->f_bsize =
4558 le32_to_cpu(response_data->BlockSize);
4559 FSData->f_blocks =
4560 le64_to_cpu(response_data->TotalBlocks);
4561 FSData->f_bfree =
4562 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004563 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 FSData->f_bavail = FSData->f_bfree;
4565 } else {
4566 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004567 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 }
Steve French790fe572007-07-07 19:25:05 +00004569 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004571 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004572 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004574 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 }
4576 }
4577 cifs_buf_release(pSMB);
4578
4579 if (rc == -EAGAIN)
4580 goto QFSPosixRetry;
4581
4582 return rc;
4583}
4584
4585
Steve French50c2f752007-07-13 00:33:32 +00004586/* We can not use write of zero bytes trick to
4587 set file size due to need for large file support. Also note that
4588 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 routine which is only needed to work around a sharing violation bug
4590 in Samba which this routine can run into */
4591
4592int
4593CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004594 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004595 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596{
4597 struct smb_com_transaction2_spi_req *pSMB = NULL;
4598 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4599 struct file_end_of_file_info *parm_data;
4600 int name_len;
4601 int rc = 0;
4602 int bytes_returned = 0;
4603 __u16 params, byte_count, data_count, param_offset, offset;
4604
4605 cFYI(1, ("In SetEOF"));
4606SetEOFRetry:
4607 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4608 (void **) &pSMBr);
4609 if (rc)
4610 return rc;
4611
4612 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4613 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004614 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004615 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 name_len++; /* trailing null */
4617 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004618 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 name_len = strnlen(fileName, PATH_MAX);
4620 name_len++; /* trailing null */
4621 strncpy(pSMB->FileName, fileName, name_len);
4622 }
4623 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004624 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004626 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 pSMB->MaxSetupCount = 0;
4628 pSMB->Reserved = 0;
4629 pSMB->Flags = 0;
4630 pSMB->Timeout = 0;
4631 pSMB->Reserved2 = 0;
4632 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004633 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004635 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004636 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4637 pSMB->InformationLevel =
4638 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4639 else
4640 pSMB->InformationLevel =
4641 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4642 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4644 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004645 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 else
4647 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004648 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 }
4650
4651 parm_data =
4652 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4653 offset);
4654 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4655 pSMB->DataOffset = cpu_to_le16(offset);
4656 pSMB->SetupCount = 1;
4657 pSMB->Reserved3 = 0;
4658 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4659 byte_count = 3 /* pad */ + params + data_count;
4660 pSMB->DataCount = cpu_to_le16(data_count);
4661 pSMB->TotalDataCount = pSMB->DataCount;
4662 pSMB->ParameterCount = cpu_to_le16(params);
4663 pSMB->TotalParameterCount = pSMB->ParameterCount;
4664 pSMB->Reserved4 = 0;
4665 pSMB->hdr.smb_buf_length += byte_count;
4666 parm_data->FileSize = cpu_to_le64(size);
4667 pSMB->ByteCount = cpu_to_le16(byte_count);
4668 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4669 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004670 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672
4673 cifs_buf_release(pSMB);
4674
4675 if (rc == -EAGAIN)
4676 goto SetEOFRetry;
4677
4678 return rc;
4679}
4680
4681int
Steve French50c2f752007-07-13 00:33:32 +00004682CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004683 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684{
4685 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 char *data_offset;
4687 struct file_end_of_file_info *parm_data;
4688 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 __u16 params, param_offset, offset, byte_count, count;
4690
4691 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4692 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004693 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4694
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 if (rc)
4696 return rc;
4697
4698 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4699 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004700
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 params = 6;
4702 pSMB->MaxSetupCount = 0;
4703 pSMB->Reserved = 0;
4704 pSMB->Flags = 0;
4705 pSMB->Timeout = 0;
4706 pSMB->Reserved2 = 0;
4707 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4708 offset = param_offset + params;
4709
Steve French50c2f752007-07-13 00:33:32 +00004710 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
4712 count = sizeof(struct file_end_of_file_info);
4713 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004714 /* BB find exact max SMB PDU from sess structure BB */
4715 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 pSMB->SetupCount = 1;
4717 pSMB->Reserved3 = 0;
4718 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4719 byte_count = 3 /* pad */ + params + count;
4720 pSMB->DataCount = cpu_to_le16(count);
4721 pSMB->ParameterCount = cpu_to_le16(params);
4722 pSMB->TotalDataCount = pSMB->DataCount;
4723 pSMB->TotalParameterCount = pSMB->ParameterCount;
4724 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4725 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004726 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4727 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 pSMB->DataOffset = cpu_to_le16(offset);
4729 parm_data->FileSize = cpu_to_le64(size);
4730 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004731 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733 pSMB->InformationLevel =
4734 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4735 else
4736 pSMB->InformationLevel =
4737 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004738 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4740 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004741 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 else
4743 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004744 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 }
4746 pSMB->Reserved4 = 0;
4747 pSMB->hdr.smb_buf_length += byte_count;
4748 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004749 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 if (rc) {
4751 cFYI(1,
4752 ("Send error in SetFileInfo (SetFileSize) = %d",
4753 rc));
4754 }
4755
Steve French50c2f752007-07-13 00:33:32 +00004756 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 since file handle passed in no longer valid */
4758
4759 return rc;
4760}
4761
Steve French50c2f752007-07-13 00:33:32 +00004762/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 an open handle, rather than by pathname - this is awkward due to
4764 potential access conflicts on the open, but it is unavoidable for these
4765 old servers since the only other choice is to go from 100 nanosecond DCE
4766 time and resort to the original setpathinfo level which takes the ancient
4767 DOS time format with 2 second granularity */
4768int
Steve French50c2f752007-07-13 00:33:32 +00004769CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4770 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771{
4772 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 char *data_offset;
4774 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 __u16 params, param_offset, offset, byte_count, count;
4776
4777 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004778 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4779
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 if (rc)
4781 return rc;
4782
4783 /* At this point there is no need to override the current pid
4784 with the pid of the opener, but that could change if we someday
4785 use an existing handle (rather than opening one on the fly) */
4786 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4787 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004788
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 params = 6;
4790 pSMB->MaxSetupCount = 0;
4791 pSMB->Reserved = 0;
4792 pSMB->Flags = 0;
4793 pSMB->Timeout = 0;
4794 pSMB->Reserved2 = 0;
4795 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4796 offset = param_offset + params;
4797
Steve French50c2f752007-07-13 00:33:32 +00004798 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799
Steve French26f57362007-08-30 22:09:15 +00004800 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004802 /* BB find max SMB PDU from sess */
4803 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 pSMB->SetupCount = 1;
4805 pSMB->Reserved3 = 0;
4806 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4807 byte_count = 3 /* pad */ + params + count;
4808 pSMB->DataCount = cpu_to_le16(count);
4809 pSMB->ParameterCount = cpu_to_le16(params);
4810 pSMB->TotalDataCount = pSMB->DataCount;
4811 pSMB->TotalParameterCount = pSMB->ParameterCount;
4812 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4813 pSMB->DataOffset = cpu_to_le16(offset);
4814 pSMB->Fid = fid;
4815 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4816 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4817 else
4818 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4819 pSMB->Reserved4 = 0;
4820 pSMB->hdr.smb_buf_length += byte_count;
4821 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004822 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004823 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004824 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004825 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826
Steve French50c2f752007-07-13 00:33:32 +00004827 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 since file handle passed in no longer valid */
4829
4830 return rc;
4831}
4832
4833
4834int
4835CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004836 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004837 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838{
4839 TRANSACTION2_SPI_REQ *pSMB = NULL;
4840 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4841 int name_len;
4842 int rc = 0;
4843 int bytes_returned = 0;
4844 char *data_offset;
4845 __u16 params, param_offset, offset, byte_count, count;
4846
4847 cFYI(1, ("In SetTimes"));
4848
4849SetTimesRetry:
4850 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4851 (void **) &pSMBr);
4852 if (rc)
4853 return rc;
4854
4855 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4856 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004857 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004858 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 name_len++; /* trailing null */
4860 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004861 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 name_len = strnlen(fileName, PATH_MAX);
4863 name_len++; /* trailing null */
4864 strncpy(pSMB->FileName, fileName, name_len);
4865 }
4866
4867 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004868 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004870 /* BB find max SMB PDU from sess structure BB */
4871 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 pSMB->MaxSetupCount = 0;
4873 pSMB->Reserved = 0;
4874 pSMB->Flags = 0;
4875 pSMB->Timeout = 0;
4876 pSMB->Reserved2 = 0;
4877 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004878 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 offset = param_offset + params;
4880 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4881 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4882 pSMB->DataOffset = cpu_to_le16(offset);
4883 pSMB->SetupCount = 1;
4884 pSMB->Reserved3 = 0;
4885 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4886 byte_count = 3 /* pad */ + params + count;
4887
4888 pSMB->DataCount = cpu_to_le16(count);
4889 pSMB->ParameterCount = cpu_to_le16(params);
4890 pSMB->TotalDataCount = pSMB->DataCount;
4891 pSMB->TotalParameterCount = pSMB->ParameterCount;
4892 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4893 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4894 else
4895 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4896 pSMB->Reserved4 = 0;
4897 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004898 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 pSMB->ByteCount = cpu_to_le16(byte_count);
4900 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4901 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004902 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904
4905 cifs_buf_release(pSMB);
4906
4907 if (rc == -EAGAIN)
4908 goto SetTimesRetry;
4909
4910 return rc;
4911}
4912
4913/* Can not be used to set time stamps yet (due to old DOS time format) */
4914/* Can be used to set attributes */
4915#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4916 handling it anyway and NT4 was what we thought it would be needed for
4917 Do not delete it until we prove whether needed for Win9x though */
4918int
4919CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4920 __u16 dos_attrs, const struct nls_table *nls_codepage)
4921{
4922 SETATTR_REQ *pSMB = NULL;
4923 SETATTR_RSP *pSMBr = NULL;
4924 int rc = 0;
4925 int bytes_returned;
4926 int name_len;
4927
4928 cFYI(1, ("In SetAttrLegacy"));
4929
4930SetAttrLgcyRetry:
4931 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4932 (void **) &pSMBr);
4933 if (rc)
4934 return rc;
4935
4936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4937 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004938 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 PATH_MAX, nls_codepage);
4940 name_len++; /* trailing null */
4941 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004942 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 name_len = strnlen(fileName, PATH_MAX);
4944 name_len++; /* trailing null */
4945 strncpy(pSMB->fileName, fileName, name_len);
4946 }
4947 pSMB->attr = cpu_to_le16(dos_attrs);
4948 pSMB->BufferFormat = 0x04;
4949 pSMB->hdr.smb_buf_length += name_len + 1;
4950 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004953 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955
4956 cifs_buf_release(pSMB);
4957
4958 if (rc == -EAGAIN)
4959 goto SetAttrLgcyRetry;
4960
4961 return rc;
4962}
4963#endif /* temporarily unneeded SetAttr legacy function */
4964
4965int
4966CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004967 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4968 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004969 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970{
4971 TRANSACTION2_SPI_REQ *pSMB = NULL;
4972 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4973 int name_len;
4974 int rc = 0;
4975 int bytes_returned = 0;
4976 FILE_UNIX_BASIC_INFO *data_offset;
4977 __u16 params, param_offset, offset, count, byte_count;
4978
4979 cFYI(1, ("In SetUID/GID/Mode"));
4980setPermsRetry:
4981 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4982 (void **) &pSMBr);
4983 if (rc)
4984 return rc;
4985
4986 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4987 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004988 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004989 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 name_len++; /* trailing null */
4991 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004992 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 name_len = strnlen(fileName, PATH_MAX);
4994 name_len++; /* trailing null */
4995 strncpy(pSMB->FileName, fileName, name_len);
4996 }
4997
4998 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004999 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005001 /* BB find max SMB PDU from sess structure BB */
5002 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 pSMB->MaxSetupCount = 0;
5004 pSMB->Reserved = 0;
5005 pSMB->Flags = 0;
5006 pSMB->Timeout = 0;
5007 pSMB->Reserved2 = 0;
5008 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005009 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 offset = param_offset + params;
5011 data_offset =
5012 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5013 offset);
5014 memset(data_offset, 0, count);
5015 pSMB->DataOffset = cpu_to_le16(offset);
5016 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5017 pSMB->SetupCount = 1;
5018 pSMB->Reserved3 = 0;
5019 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5020 byte_count = 3 /* pad */ + params + count;
5021 pSMB->ParameterCount = cpu_to_le16(params);
5022 pSMB->DataCount = cpu_to_le16(count);
5023 pSMB->TotalParameterCount = pSMB->ParameterCount;
5024 pSMB->TotalDataCount = pSMB->DataCount;
5025 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5026 pSMB->Reserved4 = 0;
5027 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005028 /* Samba server ignores set of file size to zero due to bugs in some
5029 older clients, but we should be precise - we use SetFileSize to
5030 set file size and do not want to truncate file size to zero
5031 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005032 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005033 data_offset->EndOfFile = NO_CHANGE_64;
5034 data_offset->NumOfBytes = NO_CHANGE_64;
5035 data_offset->LastStatusChange = NO_CHANGE_64;
5036 data_offset->LastAccessTime = NO_CHANGE_64;
5037 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 data_offset->Uid = cpu_to_le64(uid);
5039 data_offset->Gid = cpu_to_le64(gid);
5040 /* better to leave device as zero when it is */
5041 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5042 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5043 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005044
Steve French790fe572007-07-07 19:25:05 +00005045 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005047 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005049 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005051 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005053 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005055 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005057 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5059
5060
5061 pSMB->ByteCount = cpu_to_le16(byte_count);
5062 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5063 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005064 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066
5067 if (pSMB)
5068 cifs_buf_release(pSMB);
5069 if (rc == -EAGAIN)
5070 goto setPermsRetry;
5071 return rc;
5072}
5073
Steve French50c2f752007-07-13 00:33:32 +00005074int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005075 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005076 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005077 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078{
5079 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005080 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5081 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005082 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 int bytes_returned;
5084
Steve French50c2f752007-07-13 00:33:32 +00005085 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005087 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 if (rc)
5089 return rc;
5090
5091 pSMB->TotalParameterCount = 0 ;
5092 pSMB->TotalDataCount = 0;
5093 pSMB->MaxParameterCount = cpu_to_le32(2);
5094 /* BB find exact data count max from sess structure BB */
5095 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005096/* BB VERIFY verify which is correct for above BB */
5097 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5098 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5099
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 pSMB->MaxSetupCount = 4;
5101 pSMB->Reserved = 0;
5102 pSMB->ParameterOffset = 0;
5103 pSMB->DataCount = 0;
5104 pSMB->DataOffset = 0;
5105 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5106 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5107 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005108 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5110 pSMB->Reserved2 = 0;
5111 pSMB->CompletionFilter = cpu_to_le32(filter);
5112 pSMB->Fid = netfid; /* file handle always le */
5113 pSMB->ByteCount = 0;
5114
5115 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005116 (struct smb_hdr *)pSMBr, &bytes_returned,
5117 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 if (rc) {
5119 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005120 } else {
5121 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005122 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005123 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005124 sizeof(struct dir_notify_req),
5125 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005126 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005127 dnotify_req->Pid = pSMB->hdr.Pid;
5128 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5129 dnotify_req->Mid = pSMB->hdr.Mid;
5130 dnotify_req->Tid = pSMB->hdr.Tid;
5131 dnotify_req->Uid = pSMB->hdr.Uid;
5132 dnotify_req->netfid = netfid;
5133 dnotify_req->pfile = pfile;
5134 dnotify_req->filter = filter;
5135 dnotify_req->multishot = multishot;
5136 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005137 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005138 &GlobalDnotifyReqList);
5139 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005140 } else
Steve French47c786e2005-10-11 20:03:18 -07005141 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 }
5143 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005144 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145}
5146#ifdef CONFIG_CIFS_XATTR
5147ssize_t
5148CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5149 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005150 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005151 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152{
5153 /* BB assumes one setup word */
5154 TRANSACTION2_QPI_REQ *pSMB = NULL;
5155 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5156 int rc = 0;
5157 int bytes_returned;
5158 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005159 struct fea *temp_fea;
5160 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 __u16 params, byte_count;
5162
5163 cFYI(1, ("In Query All EAs path %s", searchName));
5164QAllEAsRetry:
5165 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5166 (void **) &pSMBr);
5167 if (rc)
5168 return rc;
5169
5170 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5171 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005172 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005173 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 name_len++; /* trailing null */
5175 name_len *= 2;
5176 } else { /* BB improve the check for buffer overruns BB */
5177 name_len = strnlen(searchName, PATH_MAX);
5178 name_len++; /* trailing null */
5179 strncpy(pSMB->FileName, searchName, name_len);
5180 }
5181
Steve French50c2f752007-07-13 00:33:32 +00005182 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 pSMB->TotalDataCount = 0;
5184 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005185 /* BB find exact max SMB PDU from sess structure BB */
5186 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 pSMB->MaxSetupCount = 0;
5188 pSMB->Reserved = 0;
5189 pSMB->Flags = 0;
5190 pSMB->Timeout = 0;
5191 pSMB->Reserved2 = 0;
5192 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005193 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 pSMB->DataCount = 0;
5195 pSMB->DataOffset = 0;
5196 pSMB->SetupCount = 1;
5197 pSMB->Reserved3 = 0;
5198 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5199 byte_count = params + 1 /* pad */ ;
5200 pSMB->TotalParameterCount = cpu_to_le16(params);
5201 pSMB->ParameterCount = pSMB->TotalParameterCount;
5202 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5203 pSMB->Reserved4 = 0;
5204 pSMB->hdr.smb_buf_length += byte_count;
5205 pSMB->ByteCount = cpu_to_le16(byte_count);
5206
5207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5209 if (rc) {
5210 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5211 } else { /* decode response */
5212 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5213
5214 /* BB also check enough total bytes returned */
5215 /* BB we need to improve the validity checking
5216 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005217 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 rc = -EIO; /* bad smb */
5219 /* else if (pFindData){
5220 memcpy((char *) pFindData,
5221 (char *) &pSMBr->hdr.Protocol +
5222 data_offset, kl);
5223 }*/ else {
5224 /* check that length of list is not more than bcc */
5225 /* check that each entry does not go beyond length
5226 of list */
5227 /* check that each element of each entry does not
5228 go beyond end of list */
5229 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005230 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 rc = 0;
5232 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005233 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 ea_response_data = (struct fealist *)
5235 (((char *) &pSMBr->hdr.Protocol) +
5236 data_offset);
5237 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005238 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005239 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005241 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 } else {
5243 /* account for ea list len */
5244 name_len -= 4;
5245 temp_fea = ea_response_data->list;
5246 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005247 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 __u16 value_len;
5249 name_len -= 4;
5250 temp_ptr += 4;
5251 rc += temp_fea->name_len;
5252 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005253 rc = rc + 5 + 1;
5254 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005255 memcpy(EAData, "user.", 5);
5256 EAData += 5;
5257 memcpy(EAData, temp_ptr,
5258 temp_fea->name_len);
5259 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 /* null terminate name */
5261 *EAData = 0;
5262 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005263 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 /* skip copy - calc size only */
5265 } else {
5266 /* stop before overrun buffer */
5267 rc = -ERANGE;
5268 break;
5269 }
5270 name_len -= temp_fea->name_len;
5271 temp_ptr += temp_fea->name_len;
5272 /* account for trailing null */
5273 name_len--;
5274 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005275 value_len =
5276 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 name_len -= value_len;
5278 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005279 /* BB check that temp_ptr is still
5280 within the SMB BB*/
5281
5282 /* no trailing null to account for
5283 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 /* go on to next EA */
5285 temp_fea = (struct fea *)temp_ptr;
5286 }
5287 }
5288 }
5289 }
5290 if (pSMB)
5291 cifs_buf_release(pSMB);
5292 if (rc == -EAGAIN)
5293 goto QAllEAsRetry;
5294
5295 return (ssize_t)rc;
5296}
5297
Steve French50c2f752007-07-13 00:33:32 +00005298ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5299 const unsigned char *searchName, const unsigned char *ea_name,
5300 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005301 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302{
5303 TRANSACTION2_QPI_REQ *pSMB = NULL;
5304 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5305 int rc = 0;
5306 int bytes_returned;
5307 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005308 struct fea *temp_fea;
5309 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 __u16 params, byte_count;
5311
5312 cFYI(1, ("In Query EA path %s", searchName));
5313QEARetry:
5314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5315 (void **) &pSMBr);
5316 if (rc)
5317 return rc;
5318
5319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5320 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005321 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005322 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 name_len++; /* trailing null */
5324 name_len *= 2;
5325 } else { /* BB improve the check for buffer overruns BB */
5326 name_len = strnlen(searchName, PATH_MAX);
5327 name_len++; /* trailing null */
5328 strncpy(pSMB->FileName, searchName, name_len);
5329 }
5330
Steve French50c2f752007-07-13 00:33:32 +00005331 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 pSMB->TotalDataCount = 0;
5333 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005334 /* BB find exact max SMB PDU from sess structure BB */
5335 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 pSMB->MaxSetupCount = 0;
5337 pSMB->Reserved = 0;
5338 pSMB->Flags = 0;
5339 pSMB->Timeout = 0;
5340 pSMB->Reserved2 = 0;
5341 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005342 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 pSMB->DataCount = 0;
5344 pSMB->DataOffset = 0;
5345 pSMB->SetupCount = 1;
5346 pSMB->Reserved3 = 0;
5347 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5348 byte_count = params + 1 /* pad */ ;
5349 pSMB->TotalParameterCount = cpu_to_le16(params);
5350 pSMB->ParameterCount = pSMB->TotalParameterCount;
5351 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5352 pSMB->Reserved4 = 0;
5353 pSMB->hdr.smb_buf_length += byte_count;
5354 pSMB->ByteCount = cpu_to_le16(byte_count);
5355
5356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5358 if (rc) {
5359 cFYI(1, ("Send error in Query EA = %d", rc));
5360 } else { /* decode response */
5361 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5362
5363 /* BB also check enough total bytes returned */
5364 /* BB we need to improve the validity checking
5365 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005366 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 rc = -EIO; /* bad smb */
5368 /* else if (pFindData){
5369 memcpy((char *) pFindData,
5370 (char *) &pSMBr->hdr.Protocol +
5371 data_offset, kl);
5372 }*/ else {
5373 /* check that length of list is not more than bcc */
5374 /* check that each entry does not go beyond length
5375 of list */
5376 /* check that each element of each entry does not
5377 go beyond end of list */
5378 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005379 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 rc = -ENODATA;
5381 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005382 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 ea_response_data = (struct fealist *)
5384 (((char *) &pSMBr->hdr.Protocol) +
5385 data_offset);
5386 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005387 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005388 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005390 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 } else {
5392 /* account for ea list len */
5393 name_len -= 4;
5394 temp_fea = ea_response_data->list;
5395 temp_ptr = (char *)temp_fea;
5396 /* loop through checking if we have a matching
5397 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005398 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 __u16 value_len;
5400 name_len -= 4;
5401 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005402 value_len =
5403 le16_to_cpu(temp_fea->value_len);
5404 /* BB validate that value_len falls within SMB,
5405 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005406 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 temp_fea->name_len) == 0) {
5408 /* found a match */
5409 rc = value_len;
5410 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005411 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 memcpy(ea_value,
5413 temp_fea->name+temp_fea->name_len+1,
5414 rc);
Steve French50c2f752007-07-13 00:33:32 +00005415 /* ea values, unlike ea
5416 names, are not null
5417 terminated */
Steve French790fe572007-07-07 19:25:05 +00005418 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 /* skip copy - calc size only */
5420 } else {
Steve French50c2f752007-07-13 00:33:32 +00005421 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 rc = -ERANGE;
5423 }
5424 break;
5425 }
5426 name_len -= temp_fea->name_len;
5427 temp_ptr += temp_fea->name_len;
5428 /* account for trailing null */
5429 name_len--;
5430 temp_ptr++;
5431 name_len -= value_len;
5432 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005433 /* No trailing null to account for in
5434 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 temp_fea = (struct fea *)temp_ptr;
5436 }
Steve French50c2f752007-07-13 00:33:32 +00005437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 }
5439 }
5440 if (pSMB)
5441 cifs_buf_release(pSMB);
5442 if (rc == -EAGAIN)
5443 goto QEARetry;
5444
5445 return (ssize_t)rc;
5446}
5447
5448int
5449CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005450 const char *ea_name, const void *ea_value,
5451 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5452 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453{
5454 struct smb_com_transaction2_spi_req *pSMB = NULL;
5455 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5456 struct fealist *parm_data;
5457 int name_len;
5458 int rc = 0;
5459 int bytes_returned = 0;
5460 __u16 params, param_offset, byte_count, offset, count;
5461
5462 cFYI(1, ("In SetEA"));
5463SetEARetry:
5464 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5465 (void **) &pSMBr);
5466 if (rc)
5467 return rc;
5468
5469 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5470 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005471 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005472 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 name_len++; /* trailing null */
5474 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005475 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 name_len = strnlen(fileName, PATH_MAX);
5477 name_len++; /* trailing null */
5478 strncpy(pSMB->FileName, fileName, name_len);
5479 }
5480
5481 params = 6 + name_len;
5482
5483 /* done calculating parms using name_len of file name,
5484 now use name_len to calculate length of ea name
5485 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005486 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 name_len = 0;
5488 else
Steve French50c2f752007-07-13 00:33:32 +00005489 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005491 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005493 /* BB find max SMB PDU from sess */
5494 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 pSMB->MaxSetupCount = 0;
5496 pSMB->Reserved = 0;
5497 pSMB->Flags = 0;
5498 pSMB->Timeout = 0;
5499 pSMB->Reserved2 = 0;
5500 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005501 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 offset = param_offset + params;
5503 pSMB->InformationLevel =
5504 cpu_to_le16(SMB_SET_FILE_EA);
5505
5506 parm_data =
5507 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5508 offset);
5509 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5510 pSMB->DataOffset = cpu_to_le16(offset);
5511 pSMB->SetupCount = 1;
5512 pSMB->Reserved3 = 0;
5513 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5514 byte_count = 3 /* pad */ + params + count;
5515 pSMB->DataCount = cpu_to_le16(count);
5516 parm_data->list_len = cpu_to_le32(count);
5517 parm_data->list[0].EA_flags = 0;
5518 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005519 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005521 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005522 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 parm_data->list[0].name[name_len] = 0;
5524 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5525 /* caller ensures that ea_value_len is less than 64K but
5526 we need to ensure that it fits within the smb */
5527
Steve French50c2f752007-07-13 00:33:32 +00005528 /*BB add length check to see if it would fit in
5529 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005530 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5531 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005532 memcpy(parm_data->list[0].name+name_len+1,
5533 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534
5535 pSMB->TotalDataCount = pSMB->DataCount;
5536 pSMB->ParameterCount = cpu_to_le16(params);
5537 pSMB->TotalParameterCount = pSMB->ParameterCount;
5538 pSMB->Reserved4 = 0;
5539 pSMB->hdr.smb_buf_length += byte_count;
5540 pSMB->ByteCount = cpu_to_le16(byte_count);
5541 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5542 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005543 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545
5546 cifs_buf_release(pSMB);
5547
5548 if (rc == -EAGAIN)
5549 goto SetEARetry;
5550
5551 return rc;
5552}
5553
5554#endif