blob: fc297383cb0e349bb1519b59848b3135f60af270 [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 Frencha45443472005-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 Frencha45443472005-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-10-02 05:53:29 +0000533 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000534 } else {
Steve Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-08-24 13:59:35 -07001010 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001011 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07001013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 cifs_buf_release(pSMB);
1015 if (rc == -EAGAIN)
1016 goto MkDirRetry;
1017 return rc;
1018}
1019
Steve French2dd29d32007-04-23 22:07:35 +00001020int
1021CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001022 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001023 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001024 const struct nls_table *nls_codepage, int remap)
1025{
1026 TRANSACTION2_SPI_REQ *pSMB = NULL;
1027 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1028 int name_len;
1029 int rc = 0;
1030 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001031 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001032 OPEN_PSX_REQ *pdata;
1033 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001034
1035 cFYI(1, ("In POSIX Create"));
1036PsxCreat:
1037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1038 (void **) &pSMBr);
1039 if (rc)
1040 return rc;
1041
1042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1043 name_len =
1044 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1045 PATH_MAX, nls_codepage, remap);
1046 name_len++; /* trailing null */
1047 name_len *= 2;
1048 } else { /* BB improve the check for buffer overruns BB */
1049 name_len = strnlen(name, PATH_MAX);
1050 name_len++; /* trailing null */
1051 strncpy(pSMB->FileName, name, name_len);
1052 }
1053
1054 params = 6 + name_len;
1055 count = sizeof(OPEN_PSX_REQ);
1056 pSMB->MaxParameterCount = cpu_to_le16(2);
1057 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1058 pSMB->MaxSetupCount = 0;
1059 pSMB->Reserved = 0;
1060 pSMB->Flags = 0;
1061 pSMB->Timeout = 0;
1062 pSMB->Reserved2 = 0;
1063 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001064 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001065 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001066 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001067 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001068 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001069 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001070 pdata->OpenFlags = cpu_to_le32(*pOplock);
1071 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1072 pSMB->DataOffset = cpu_to_le16(offset);
1073 pSMB->SetupCount = 1;
1074 pSMB->Reserved3 = 0;
1075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1076 byte_count = 3 /* pad */ + params + count;
1077
1078 pSMB->DataCount = cpu_to_le16(count);
1079 pSMB->ParameterCount = cpu_to_le16(params);
1080 pSMB->TotalDataCount = pSMB->DataCount;
1081 pSMB->TotalParameterCount = pSMB->ParameterCount;
1082 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1083 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001084 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001085 pSMB->ByteCount = cpu_to_le16(byte_count);
1086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1088 if (rc) {
1089 cFYI(1, ("Posix create returned %d", rc));
1090 goto psx_create_err;
1091 }
1092
Steve French790fe572007-07-07 19:25:05 +00001093 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1095
1096 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1097 rc = -EIO; /* bad smb */
1098 goto psx_create_err;
1099 }
1100
1101 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001102 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001103 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001104
Steve French2dd29d32007-04-23 22:07:35 +00001105 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001106 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001107 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1108 /* Let caller know file was created so we can set the mode. */
1109 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001110 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001111 *pOplock |= CIFS_CREATE_ACTION;
1112 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001113 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1114 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001115 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001116 } else {
Steve French790fe572007-07-07 19:25:05 +00001117 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001118 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001119 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001120 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001121 goto psx_create_err;
1122 }
Steve French50c2f752007-07-13 00:33:32 +00001123 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001124 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001125 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001126 }
Steve French2dd29d32007-04-23 22:07:35 +00001127
1128psx_create_err:
1129 cifs_buf_release(pSMB);
1130
1131 cifs_stats_inc(&tcon->num_mkdirs);
1132
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1135
Steve French50c2f752007-07-13 00:33:32 +00001136 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001137}
1138
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139static __u16 convert_disposition(int disposition)
1140{
1141 __u16 ofun = 0;
1142
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
Steve French790fe572007-07-07 19:25:05 +00001163 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 ofun = SMBOPEN_OAPPEND; /* regular open */
1165 }
1166 return ofun;
1167}
1168
Jeff Layton35fc37d2008-05-14 10:22:03 -07001169static int
1170access_flags_to_smbopen_mode(const int access_flags)
1171{
1172 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1173
1174 if (masked_flags == GENERIC_READ)
1175 return SMBOPEN_READ;
1176 else if (masked_flags == GENERIC_WRITE)
1177 return SMBOPEN_WRITE;
1178
1179 /* just go for read/write */
1180 return SMBOPEN_READWRITE;
1181}
1182
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183int
1184SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1185 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001186 const int access_flags, const int create_options, __u16 *netfid,
1187 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 const struct nls_table *nls_codepage, int remap)
1189{
1190 int rc = -EACCES;
1191 OPENX_REQ *pSMB = NULL;
1192 OPENX_RSP *pSMBr = NULL;
1193 int bytes_returned;
1194 int name_len;
1195 __u16 count;
1196
1197OldOpenRetry:
1198 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1199 (void **) &pSMBr);
1200 if (rc)
1201 return rc;
1202
1203 pSMB->AndXCommand = 0xFF; /* none */
1204
1205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1206 count = 1; /* account for one byte pad to word boundary */
1207 name_len =
1208 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1209 fileName, PATH_MAX, nls_codepage, remap);
1210 name_len++; /* trailing null */
1211 name_len *= 2;
1212 } else { /* BB improve check for buffer overruns BB */
1213 count = 0; /* no pad */
1214 name_len = strnlen(fileName, PATH_MAX);
1215 name_len++; /* trailing null */
1216 strncpy(pSMB->fileName, fileName, name_len);
1217 }
1218 if (*pOplock & REQ_OPLOCK)
1219 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001222
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001224 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1226 /* set file as system file if special file such
1227 as fifo and server expecting SFU style and
1228 no Unix extensions */
1229
Steve French790fe572007-07-07 19:25:05 +00001230 if (create_options & CREATE_OPTION_SPECIAL)
1231 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001232 else /* BB FIXME BB */
1233 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
Jeff Layton67750fb2008-05-09 22:28:02 +00001235 if (create_options & CREATE_OPTION_READONLY)
1236 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237
1238 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001239/* pSMB->CreateOptions = cpu_to_le32(create_options &
1240 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001242
1243 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001244 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245 count += name_len;
1246 pSMB->hdr.smb_buf_length += count;
1247
1248 pSMB->ByteCount = cpu_to_le16(count);
1249 /* long_op set to 1 to allow for oplock break timeouts */
1250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001251 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 cifs_stats_inc(&tcon->num_opens);
1253 if (rc) {
1254 cFYI(1, ("Error in Open = %d", rc));
1255 } else {
1256 /* BB verify if wct == 15 */
1257
Steve French582d21e2008-05-13 04:54:12 +00001258/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259
1260 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1261 /* Let caller know file was created so we can set the mode. */
1262 /* Do we care about the CreateAction in any other cases? */
1263 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001264/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 *pOplock |= CIFS_CREATE_ACTION; */
1266 /* BB FIXME END */
1267
Steve French790fe572007-07-07 19:25:05 +00001268 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1270 pfile_info->LastAccessTime = 0; /* BB fixme */
1271 pfile_info->LastWriteTime = 0; /* BB fixme */
1272 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001273 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001274 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001276 pfile_info->AllocationSize =
1277 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1278 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 pfile_info->NumberOfLinks = cpu_to_le32(1);
1280 }
1281 }
1282
1283 cifs_buf_release(pSMB);
1284 if (rc == -EAGAIN)
1285 goto OldOpenRetry;
1286 return rc;
1287}
1288
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289int
1290CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1291 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001292 const int access_flags, const int create_options, __u16 *netfid,
1293 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001294 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
1296 int rc = -EACCES;
1297 OPEN_REQ *pSMB = NULL;
1298 OPEN_RSP *pSMBr = NULL;
1299 int bytes_returned;
1300 int name_len;
1301 __u16 count;
1302
1303openRetry:
1304 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1305 (void **) &pSMBr);
1306 if (rc)
1307 return rc;
1308
1309 pSMB->AndXCommand = 0xFF; /* none */
1310
1311 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1312 count = 1; /* account for one byte pad to word boundary */
1313 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001314 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001315 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 name_len++; /* trailing null */
1317 name_len *= 2;
1318 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001319 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 count = 0; /* no pad */
1321 name_len = strnlen(fileName, PATH_MAX);
1322 name_len++; /* trailing null */
1323 pSMB->NameLength = cpu_to_le16(name_len);
1324 strncpy(pSMB->fileName, fileName, name_len);
1325 }
1326 if (*pOplock & REQ_OPLOCK)
1327 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001328 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1331 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001332 /* set file as system file if special file such
1333 as fifo and server expecting SFU style and
1334 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001335 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001336 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1337 else
1338 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 /* XP does not handle ATTR_POSIX_SEMANTICS */
1341 /* but it helps speed up case sensitive checks for other
1342 servers such as Samba */
1343 if (tcon->ses->capabilities & CAP_UNIX)
1344 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1345
Jeff Layton67750fb2008-05-09 22:28:02 +00001346 if (create_options & CREATE_OPTION_READONLY)
1347 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1348
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1350 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001351 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001352 /* BB Expirement with various impersonation levels and verify */
1353 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pSMB->SecurityFlags =
1355 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1356
1357 count += name_len;
1358 pSMB->hdr.smb_buf_length += count;
1359
1360 pSMB->ByteCount = cpu_to_le16(count);
1361 /* long_op set to 1 to allow for oplock break timeouts */
1362 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001363 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha45443472005-08-24 13:59:35 -07001364 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (rc) {
1366 cFYI(1, ("Error in Open = %d", rc));
1367 } else {
Steve French09d1db52005-04-28 22:41:08 -07001368 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1370 /* Let caller know file was created so we can set the mode. */
1371 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001372 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001373 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001374 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001375 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 36 /* CreationTime to Attributes */);
1377 /* the file_info buf is endian converted by caller */
1378 pfile_info->AllocationSize = pSMBr->AllocationSize;
1379 pfile_info->EndOfFile = pSMBr->EndOfFile;
1380 pfile_info->NumberOfLinks = cpu_to_le32(1);
1381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 cifs_buf_release(pSMB);
1385 if (rc == -EAGAIN)
1386 goto openRetry;
1387 return rc;
1388}
1389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390int
Steve French50c2f752007-07-13 00:33:32 +00001391CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1392 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1393 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
1395 int rc = -EACCES;
1396 READ_REQ *pSMB = NULL;
1397 READ_RSP *pSMBr = NULL;
1398 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001399 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001400 int resp_buf_type = 0;
1401 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Steve French790fe572007-07-07 19:25:05 +00001403 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1404 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001405 wct = 12;
1406 else
1407 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
1409 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001410 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if (rc)
1412 return rc;
1413
1414 /* tcon and ses pointer are checked in smb_init */
1415 if (tcon->ses->server == NULL)
1416 return -ECONNABORTED;
1417
Steve Frenchec637e32005-12-12 20:53:18 -08001418 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 pSMB->Fid = netfid;
1420 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001421 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001422 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001423 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001424 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001425
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 pSMB->Remaining = 0;
1427 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1428 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001429 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001430 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1431 else {
1432 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001433 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001434 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001435 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001436 }
Steve Frenchec637e32005-12-12 20:53:18 -08001437
1438 iov[0].iov_base = (char *)pSMB;
1439 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001440 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001441 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha45443472005-08-24 13:59:35 -07001442 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001443 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 if (rc) {
1445 cERROR(1, ("Send error in read = %d", rc));
1446 } else {
1447 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1448 data_length = data_length << 16;
1449 data_length += le16_to_cpu(pSMBr->DataLength);
1450 *nbytes = data_length;
1451
1452 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001453 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001455 cFYI(1, ("bad length %d for count %d",
1456 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 rc = -EIO;
1458 *nbytes = 0;
1459 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001460 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001461 le16_to_cpu(pSMBr->DataOffset);
1462/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001463 cERROR(1,("Faulting on read rc = %d",rc));
1464 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001465 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001466 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001467 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
1469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
Steve French4b8f9302006-02-26 16:41:18 +00001471/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001472 if (*buf) {
1473 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001474 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001475 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001476 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001477 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001478 /* return buffer to caller to free */
1479 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001480 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001481 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001482 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001483 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001484 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001485
1486 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 since file handle passed in no longer valid */
1488 return rc;
1489}
1490
Steve Frenchec637e32005-12-12 20:53:18 -08001491
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492int
1493CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1494 const int netfid, const unsigned int count,
1495 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001496 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497{
1498 int rc = -EACCES;
1499 WRITE_REQ *pSMB = NULL;
1500 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001501 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 __u32 bytes_sent;
1503 __u16 byte_count;
1504
1505 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001506 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001507 return -ECONNABORTED;
1508
Steve French790fe572007-07-07 19:25:05 +00001509 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001510 wct = 14;
1511 else
1512 wct = 12;
1513
1514 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 (void **) &pSMBr);
1516 if (rc)
1517 return rc;
1518 /* tcon and ses pointer are checked in smb_init */
1519 if (tcon->ses->server == NULL)
1520 return -ECONNABORTED;
1521
1522 pSMB->AndXCommand = 0xFF; /* none */
1523 pSMB->Fid = netfid;
1524 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001525 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001526 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001527 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001528 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 pSMB->Reserved = 0xFFFFFFFF;
1531 pSMB->WriteMode = 0;
1532 pSMB->Remaining = 0;
1533
Steve French50c2f752007-07-13 00:33:32 +00001534 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 can send more if LARGE_WRITE_X capability returned by the server and if
1536 our buffer is big enough or if we convert to iovecs on socket writes
1537 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001538 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1540 } else {
1541 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1542 & ~0xFF;
1543 }
1544
1545 if (bytes_sent > count)
1546 bytes_sent = count;
1547 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001548 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001549 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001550 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001551 else if (ubuf) {
1552 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 cifs_buf_release(pSMB);
1554 return -EFAULT;
1555 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 /* No buffer */
1558 cifs_buf_release(pSMB);
1559 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001560 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001561 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001562 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001563 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001565
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1567 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001568 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001569
Steve French790fe572007-07-07 19:25:05 +00001570 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001571 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001572 else { /* old style write has byte count 4 bytes earlier
1573 so 4 bytes pad */
1574 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001575 (struct smb_com_writex_req *)pSMB;
1576 pSMBW->ByteCount = cpu_to_le16(byte_count);
1577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
1579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1580 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001581 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 if (rc) {
1583 cFYI(1, ("Send error in write = %d", rc));
1584 *nbytes = 0;
1585 } else {
1586 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1587 *nbytes = (*nbytes) << 16;
1588 *nbytes += le16_to_cpu(pSMBr->Count);
1589 }
1590
1591 cifs_buf_release(pSMB);
1592
Steve French50c2f752007-07-13 00:33:32 +00001593 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 since file handle passed in no longer valid */
1595
1596 return rc;
1597}
1598
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001599int
1600CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001602 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1603 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604{
1605 int rc = -EACCES;
1606 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001607 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001608 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001609 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
Steve French790fe572007-07-07 19:25:05 +00001611 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001612
Steve French790fe572007-07-07 19:25:05 +00001613 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001614 wct = 14;
1615 else
1616 wct = 12;
1617 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if (rc)
1619 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 /* tcon and ses pointer are checked in smb_init */
1621 if (tcon->ses->server == NULL)
1622 return -ECONNABORTED;
1623
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001624 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 pSMB->Fid = netfid;
1626 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001627 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001628 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001629 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001630 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 pSMB->Reserved = 0xFFFFFFFF;
1632 pSMB->WriteMode = 0;
1633 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001636 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
Steve French3e844692005-10-03 13:37:24 -07001638 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1639 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001640 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001641 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001642 pSMB->hdr.smb_buf_length += count+1;
1643 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001644 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1645 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001646 pSMB->ByteCount = cpu_to_le16(count + 1);
1647 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001648 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001649 (struct smb_com_writex_req *)pSMB;
1650 pSMBW->ByteCount = cpu_to_le16(count + 5);
1651 }
Steve French3e844692005-10-03 13:37:24 -07001652 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001653 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001654 iov[0].iov_len = smb_hdr_len + 4;
1655 else /* wct == 12 pad bigger by four bytes */
1656 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001657
Steve French3e844692005-10-03 13:37:24 -07001658
Steve Frenchec637e32005-12-12 20:53:18 -08001659 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001660 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001661 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001663 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001665 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001666 /* presumably this can not happen, but best to be safe */
1667 rc = -EIO;
1668 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001669 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001670 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001671 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1672 *nbytes = (*nbytes) << 16;
1673 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
Steve French4b8f9302006-02-26 16:41:18 +00001676/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001677 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001678 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001679 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001680 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
Steve French50c2f752007-07-13 00:33:32 +00001682 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 since file handle passed in no longer valid */
1684
1685 return rc;
1686}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001687
1688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689int
1690CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1691 const __u16 smb_file_id, const __u64 len,
1692 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001693 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
1695 int rc = 0;
1696 LOCK_REQ *pSMB = NULL;
1697 LOCK_RSP *pSMBr = NULL;
1698 int bytes_returned;
1699 int timeout = 0;
1700 __u16 count;
1701
Steve French4b18f2a2008-04-29 00:06:05 +00001702 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001703 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 if (rc)
1706 return rc;
1707
Steve French46810cb2005-04-28 22:41:09 -07001708 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1709
Steve French790fe572007-07-07 19:25:05 +00001710 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001711 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001713 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001714 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1716 } else {
1717 pSMB->Timeout = 0;
1718 }
1719
1720 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1721 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1722 pSMB->LockType = lockType;
1723 pSMB->AndXCommand = 0xFF; /* none */
1724 pSMB->Fid = smb_file_id; /* netfid stays le */
1725
Steve French790fe572007-07-07 19:25:05 +00001726 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1728 /* BB where to store pid high? */
1729 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1730 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1731 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1732 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1733 count = sizeof(LOCKING_ANDX_RANGE);
1734 } else {
1735 /* oplock break */
1736 count = 0;
1737 }
1738 pSMB->hdr.smb_buf_length += count;
1739 pSMB->ByteCount = cpu_to_le16(count);
1740
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001741 if (waitFlag) {
1742 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1743 (struct smb_hdr *) pSMBr, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001744 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001745 } else {
Steve French133672e2007-11-13 22:41:37 +00001746 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1747 timeout);
1748 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001749 }
Steve Frencha45443472005-08-24 13:59:35 -07001750 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001751 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Steve French50c2f752007-07-13 00:33:32 +00001754 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 since file handle passed in no longer valid */
1756 return rc;
1757}
1758
1759int
Steve French08547b02006-02-28 22:39:25 +00001760CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1761 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001762 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001763 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001764{
1765 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1766 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001767 struct cifs_posix_lock *parm_data;
1768 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001769 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001770 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001771 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001772 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001773 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001774
1775 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001776
Steve French790fe572007-07-07 19:25:05 +00001777 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001778 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001779
Steve French08547b02006-02-28 22:39:25 +00001780 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1781
1782 if (rc)
1783 return rc;
1784
1785 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1786
Steve French50c2f752007-07-13 00:33:32 +00001787 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001788 pSMB->MaxSetupCount = 0;
1789 pSMB->Reserved = 0;
1790 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001791 pSMB->Reserved2 = 0;
1792 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1793 offset = param_offset + params;
1794
Steve French08547b02006-02-28 22:39:25 +00001795 count = sizeof(struct cifs_posix_lock);
1796 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001797 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001798 pSMB->SetupCount = 1;
1799 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001800 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001801 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1802 else
1803 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1804 byte_count = 3 /* pad */ + params + count;
1805 pSMB->DataCount = cpu_to_le16(count);
1806 pSMB->ParameterCount = cpu_to_le16(params);
1807 pSMB->TotalDataCount = pSMB->DataCount;
1808 pSMB->TotalParameterCount = pSMB->ParameterCount;
1809 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001810 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001811 (((char *) &pSMB->hdr.Protocol) + offset);
1812
1813 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001814 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001815 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001816 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001817 pSMB->Timeout = cpu_to_le32(-1);
1818 } else
1819 pSMB->Timeout = 0;
1820
Steve French08547b02006-02-28 22:39:25 +00001821 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001822 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001823 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001824
1825 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001826 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001827 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1828 pSMB->Reserved4 = 0;
1829 pSMB->hdr.smb_buf_length += byte_count;
1830 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001831 if (waitFlag) {
1832 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1833 (struct smb_hdr *) pSMBr, &bytes_returned);
1834 } else {
Steve French133672e2007-11-13 22:41:37 +00001835 iov[0].iov_base = (char *)pSMB;
1836 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1837 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1838 &resp_buf_type, timeout);
1839 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1840 not try to free it twice below on exit */
1841 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001842 }
1843
Steve French08547b02006-02-28 22:39:25 +00001844 if (rc) {
1845 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001846 } else if (get_flag) {
1847 /* lock structure can be returned on get */
1848 __u16 data_offset;
1849 __u16 data_count;
1850 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001851
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001852 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1853 rc = -EIO; /* bad smb */
1854 goto plk_err_exit;
1855 }
Steve French790fe572007-07-07 19:25:05 +00001856 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001857 rc = -EINVAL;
1858 goto plk_err_exit;
1859 }
1860 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1861 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001862 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001863 rc = -EIO;
1864 goto plk_err_exit;
1865 }
1866 parm_data = (struct cifs_posix_lock *)
1867 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001868 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001869 pLockData->fl_type = F_UNLCK;
1870 }
Steve French50c2f752007-07-13 00:33:32 +00001871
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001872plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001873 if (pSMB)
1874 cifs_small_buf_release(pSMB);
1875
Steve French133672e2007-11-13 22:41:37 +00001876 if (resp_buf_type == CIFS_SMALL_BUFFER)
1877 cifs_small_buf_release(iov[0].iov_base);
1878 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1879 cifs_buf_release(iov[0].iov_base);
1880
Steve French08547b02006-02-28 22:39:25 +00001881 /* Note: On -EAGAIN error only caller can retry on handle based calls
1882 since file handle passed in no longer valid */
1883
1884 return rc;
1885}
1886
1887
1888int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1890{
1891 int rc = 0;
1892 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 cFYI(1, ("In CIFSSMBClose"));
1894
1895/* do not retry on dead session on close */
1896 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001897 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 return 0;
1899 if (rc)
1900 return rc;
1901
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001903 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001905 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001906 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001908 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 /* EINTR is expected when user ctl-c to kill app */
1910 cERROR(1, ("Send error in Close = %d", rc));
1911 }
1912 }
1913
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001915 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 rc = 0;
1917
1918 return rc;
1919}
1920
1921int
1922CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1923 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001924 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925{
1926 int rc = 0;
1927 RENAME_REQ *pSMB = NULL;
1928 RENAME_RSP *pSMBr = NULL;
1929 int bytes_returned;
1930 int name_len, name_len2;
1931 __u16 count;
1932
1933 cFYI(1, ("In CIFSSMBRename"));
1934renameRetry:
1935 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1936 (void **) &pSMBr);
1937 if (rc)
1938 return rc;
1939
1940 pSMB->BufferFormat = 0x04;
1941 pSMB->SearchAttributes =
1942 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1943 ATTR_DIRECTORY);
1944
1945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1946 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001947 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001948 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 name_len++; /* trailing null */
1950 name_len *= 2;
1951 pSMB->OldFileName[name_len] = 0x04; /* pad */
1952 /* protocol requires ASCII signature byte on Unicode string */
1953 pSMB->OldFileName[name_len + 1] = 0x00;
1954 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001955 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001956 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1958 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001959 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 name_len = strnlen(fromName, PATH_MAX);
1961 name_len++; /* trailing null */
1962 strncpy(pSMB->OldFileName, fromName, name_len);
1963 name_len2 = strnlen(toName, PATH_MAX);
1964 name_len2++; /* trailing null */
1965 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1966 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1967 name_len2++; /* trailing null */
1968 name_len2++; /* signature byte */
1969 }
1970
1971 count = 1 /* 1st signature byte */ + name_len + name_len2;
1972 pSMB->hdr.smb_buf_length += count;
1973 pSMB->ByteCount = cpu_to_le16(count);
1974
1975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001977 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001978 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 cifs_buf_release(pSMB);
1982
1983 if (rc == -EAGAIN)
1984 goto renameRetry;
1985
1986 return rc;
1987}
1988
Steve French50c2f752007-07-13 00:33:32 +00001989int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1990 int netfid, char *target_name,
1991 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992{
1993 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1994 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001995 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 char *data_offset;
1997 char dummy_string[30];
1998 int rc = 0;
1999 int bytes_returned = 0;
2000 int len_of_str;
2001 __u16 params, param_offset, offset, count, byte_count;
2002
2003 cFYI(1, ("Rename to File by handle"));
2004 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2005 (void **) &pSMBr);
2006 if (rc)
2007 return rc;
2008
2009 params = 6;
2010 pSMB->MaxSetupCount = 0;
2011 pSMB->Reserved = 0;
2012 pSMB->Flags = 0;
2013 pSMB->Timeout = 0;
2014 pSMB->Reserved2 = 0;
2015 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2016 offset = param_offset + params;
2017
2018 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2019 rename_info = (struct set_file_rename *) data_offset;
2020 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002021 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 pSMB->SetupCount = 1;
2023 pSMB->Reserved3 = 0;
2024 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2025 byte_count = 3 /* pad */ + params;
2026 pSMB->ParameterCount = cpu_to_le16(params);
2027 pSMB->TotalParameterCount = pSMB->ParameterCount;
2028 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2029 pSMB->DataOffset = cpu_to_le16(offset);
2030 /* construct random name ".cifs_tmp<inodenum><mid>" */
2031 rename_info->overwrite = cpu_to_le32(1);
2032 rename_info->root_fid = 0;
2033 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002034 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002035 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2036 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002037 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002039 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002040 target_name, PATH_MAX, nls_codepage,
2041 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2044 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2045 byte_count += count;
2046 pSMB->DataCount = cpu_to_le16(count);
2047 pSMB->TotalDataCount = pSMB->DataCount;
2048 pSMB->Fid = netfid;
2049 pSMB->InformationLevel =
2050 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2051 pSMB->Reserved4 = 0;
2052 pSMB->hdr.smb_buf_length += byte_count;
2053 pSMB->ByteCount = cpu_to_le16(byte_count);
2054 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002056 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002057 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002058 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002059
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 cifs_buf_release(pSMB);
2061
2062 /* Note: On -EAGAIN error only caller can retry on handle based calls
2063 since file handle passed in no longer valid */
2064
2065 return rc;
2066}
2067
2068int
Steve French50c2f752007-07-13 00:33:32 +00002069CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2070 const __u16 target_tid, const char *toName, const int flags,
2071 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072{
2073 int rc = 0;
2074 COPY_REQ *pSMB = NULL;
2075 COPY_RSP *pSMBr = NULL;
2076 int bytes_returned;
2077 int name_len, name_len2;
2078 __u16 count;
2079
2080 cFYI(1, ("In CIFSSMBCopy"));
2081copyRetry:
2082 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2083 (void **) &pSMBr);
2084 if (rc)
2085 return rc;
2086
2087 pSMB->BufferFormat = 0x04;
2088 pSMB->Tid2 = target_tid;
2089
2090 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2091
2092 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002093 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002094 fromName, PATH_MAX, nls_codepage,
2095 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 name_len++; /* trailing null */
2097 name_len *= 2;
2098 pSMB->OldFileName[name_len] = 0x04; /* pad */
2099 /* protocol requires ASCII signature byte on Unicode string */
2100 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002101 name_len2 =
2102 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002103 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2105 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002106 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 name_len = strnlen(fromName, PATH_MAX);
2108 name_len++; /* trailing null */
2109 strncpy(pSMB->OldFileName, fromName, name_len);
2110 name_len2 = strnlen(toName, PATH_MAX);
2111 name_len2++; /* trailing null */
2112 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2113 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2114 name_len2++; /* trailing null */
2115 name_len2++; /* signature byte */
2116 }
2117
2118 count = 1 /* 1st signature byte */ + name_len + name_len2;
2119 pSMB->hdr.smb_buf_length += count;
2120 pSMB->ByteCount = cpu_to_le16(count);
2121
2122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2124 if (rc) {
2125 cFYI(1, ("Send error in copy = %d with %d files copied",
2126 rc, le16_to_cpu(pSMBr->CopyCount)));
2127 }
2128 if (pSMB)
2129 cifs_buf_release(pSMB);
2130
2131 if (rc == -EAGAIN)
2132 goto copyRetry;
2133
2134 return rc;
2135}
2136
2137int
2138CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2139 const char *fromName, const char *toName,
2140 const struct nls_table *nls_codepage)
2141{
2142 TRANSACTION2_SPI_REQ *pSMB = NULL;
2143 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2144 char *data_offset;
2145 int name_len;
2146 int name_len_target;
2147 int rc = 0;
2148 int bytes_returned = 0;
2149 __u16 params, param_offset, offset, byte_count;
2150
2151 cFYI(1, ("In Symlink Unix style"));
2152createSymLinkRetry:
2153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154 (void **) &pSMBr);
2155 if (rc)
2156 return rc;
2157
2158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2159 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002160 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 /* find define for this maxpathcomponent */
2162 , nls_codepage);
2163 name_len++; /* trailing null */
2164 name_len *= 2;
2165
Steve French50c2f752007-07-13 00:33:32 +00002166 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 name_len = strnlen(fromName, PATH_MAX);
2168 name_len++; /* trailing null */
2169 strncpy(pSMB->FileName, fromName, name_len);
2170 }
2171 params = 6 + name_len;
2172 pSMB->MaxSetupCount = 0;
2173 pSMB->Reserved = 0;
2174 pSMB->Flags = 0;
2175 pSMB->Timeout = 0;
2176 pSMB->Reserved2 = 0;
2177 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002178 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 offset = param_offset + params;
2180
2181 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2183 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002184 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 /* find define for this maxpathcomponent */
2186 , nls_codepage);
2187 name_len_target++; /* trailing null */
2188 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002189 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 name_len_target = strnlen(toName, PATH_MAX);
2191 name_len_target++; /* trailing null */
2192 strncpy(data_offset, toName, name_len_target);
2193 }
2194
2195 pSMB->MaxParameterCount = cpu_to_le16(2);
2196 /* BB find exact max on data count below from sess */
2197 pSMB->MaxDataCount = cpu_to_le16(1000);
2198 pSMB->SetupCount = 1;
2199 pSMB->Reserved3 = 0;
2200 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2201 byte_count = 3 /* pad */ + params + name_len_target;
2202 pSMB->DataCount = cpu_to_le16(name_len_target);
2203 pSMB->ParameterCount = cpu_to_le16(params);
2204 pSMB->TotalDataCount = pSMB->DataCount;
2205 pSMB->TotalParameterCount = pSMB->ParameterCount;
2206 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2207 pSMB->DataOffset = cpu_to_le16(offset);
2208 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2209 pSMB->Reserved4 = 0;
2210 pSMB->hdr.smb_buf_length += byte_count;
2211 pSMB->ByteCount = cpu_to_le16(byte_count);
2212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002214 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002215 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002216 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
2218 if (pSMB)
2219 cifs_buf_release(pSMB);
2220
2221 if (rc == -EAGAIN)
2222 goto createSymLinkRetry;
2223
2224 return rc;
2225}
2226
2227int
2228CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2229 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002230 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231{
2232 TRANSACTION2_SPI_REQ *pSMB = NULL;
2233 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2234 char *data_offset;
2235 int name_len;
2236 int name_len_target;
2237 int rc = 0;
2238 int bytes_returned = 0;
2239 __u16 params, param_offset, offset, byte_count;
2240
2241 cFYI(1, ("In Create Hard link Unix style"));
2242createHardLinkRetry:
2243 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2244 (void **) &pSMBr);
2245 if (rc)
2246 return rc;
2247
2248 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002249 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002250 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 name_len++; /* trailing null */
2252 name_len *= 2;
2253
Steve French50c2f752007-07-13 00:33:32 +00002254 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 name_len = strnlen(toName, PATH_MAX);
2256 name_len++; /* trailing null */
2257 strncpy(pSMB->FileName, toName, name_len);
2258 }
2259 params = 6 + name_len;
2260 pSMB->MaxSetupCount = 0;
2261 pSMB->Reserved = 0;
2262 pSMB->Flags = 0;
2263 pSMB->Timeout = 0;
2264 pSMB->Reserved2 = 0;
2265 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002266 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 offset = param_offset + params;
2268
2269 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002272 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002273 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 name_len_target++; /* trailing null */
2275 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002276 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 name_len_target = strnlen(fromName, PATH_MAX);
2278 name_len_target++; /* trailing null */
2279 strncpy(data_offset, fromName, name_len_target);
2280 }
2281
2282 pSMB->MaxParameterCount = cpu_to_le16(2);
2283 /* BB find exact max on data count below from sess*/
2284 pSMB->MaxDataCount = cpu_to_le16(1000);
2285 pSMB->SetupCount = 1;
2286 pSMB->Reserved3 = 0;
2287 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2288 byte_count = 3 /* pad */ + params + name_len_target;
2289 pSMB->ParameterCount = cpu_to_le16(params);
2290 pSMB->TotalParameterCount = pSMB->ParameterCount;
2291 pSMB->DataCount = cpu_to_le16(name_len_target);
2292 pSMB->TotalDataCount = pSMB->DataCount;
2293 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2294 pSMB->DataOffset = cpu_to_le16(offset);
2295 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2296 pSMB->Reserved4 = 0;
2297 pSMB->hdr.smb_buf_length += byte_count;
2298 pSMB->ByteCount = cpu_to_le16(byte_count);
2299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002301 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002302 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
2305 cifs_buf_release(pSMB);
2306 if (rc == -EAGAIN)
2307 goto createHardLinkRetry;
2308
2309 return rc;
2310}
2311
2312int
2313CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2314 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002315 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316{
2317 int rc = 0;
2318 NT_RENAME_REQ *pSMB = NULL;
2319 RENAME_RSP *pSMBr = NULL;
2320 int bytes_returned;
2321 int name_len, name_len2;
2322 __u16 count;
2323
2324 cFYI(1, ("In CIFSCreateHardLink"));
2325winCreateHardLinkRetry:
2326
2327 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2328 (void **) &pSMBr);
2329 if (rc)
2330 return rc;
2331
2332 pSMB->SearchAttributes =
2333 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2334 ATTR_DIRECTORY);
2335 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2336 pSMB->ClusterCount = 0;
2337
2338 pSMB->BufferFormat = 0x04;
2339
2340 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2341 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002342 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002343 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 name_len++; /* trailing null */
2345 name_len *= 2;
2346 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002347 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002349 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002350 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2352 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002353 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 name_len = strnlen(fromName, PATH_MAX);
2355 name_len++; /* trailing null */
2356 strncpy(pSMB->OldFileName, fromName, name_len);
2357 name_len2 = strnlen(toName, PATH_MAX);
2358 name_len2++; /* trailing null */
2359 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2360 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2361 name_len2++; /* trailing null */
2362 name_len2++; /* signature byte */
2363 }
2364
2365 count = 1 /* string type byte */ + name_len + name_len2;
2366 pSMB->hdr.smb_buf_length += count;
2367 pSMB->ByteCount = cpu_to_le16(count);
2368
2369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002371 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002372 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002374
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 cifs_buf_release(pSMB);
2376 if (rc == -EAGAIN)
2377 goto winCreateHardLinkRetry;
2378
2379 return rc;
2380}
2381
2382int
2383CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2384 const unsigned char *searchName,
2385 char *symlinkinfo, const int buflen,
2386 const struct nls_table *nls_codepage)
2387{
2388/* SMB_QUERY_FILE_UNIX_LINK */
2389 TRANSACTION2_QPI_REQ *pSMB = NULL;
2390 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2391 int rc = 0;
2392 int bytes_returned;
2393 int name_len;
2394 __u16 params, byte_count;
2395
2396 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2397
2398querySymLinkRetry:
2399 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2400 (void **) &pSMBr);
2401 if (rc)
2402 return rc;
2403
2404 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2405 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002406 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2407 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 name_len++; /* trailing null */
2409 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002410 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 name_len = strnlen(searchName, PATH_MAX);
2412 name_len++; /* trailing null */
2413 strncpy(pSMB->FileName, searchName, name_len);
2414 }
2415
2416 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2417 pSMB->TotalDataCount = 0;
2418 pSMB->MaxParameterCount = cpu_to_le16(2);
2419 /* BB find exact max data count below from sess structure BB */
2420 pSMB->MaxDataCount = cpu_to_le16(4000);
2421 pSMB->MaxSetupCount = 0;
2422 pSMB->Reserved = 0;
2423 pSMB->Flags = 0;
2424 pSMB->Timeout = 0;
2425 pSMB->Reserved2 = 0;
2426 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002427 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 pSMB->DataCount = 0;
2429 pSMB->DataOffset = 0;
2430 pSMB->SetupCount = 1;
2431 pSMB->Reserved3 = 0;
2432 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2433 byte_count = params + 1 /* pad */ ;
2434 pSMB->TotalParameterCount = cpu_to_le16(params);
2435 pSMB->ParameterCount = pSMB->TotalParameterCount;
2436 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2437 pSMB->Reserved4 = 0;
2438 pSMB->hdr.smb_buf_length += byte_count;
2439 pSMB->ByteCount = cpu_to_le16(byte_count);
2440
2441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2443 if (rc) {
2444 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2445 } else {
2446 /* decode response */
2447
2448 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2449 if (rc || (pSMBr->ByteCount < 2))
2450 /* BB also check enough total bytes returned */
2451 rc = -EIO; /* bad smb */
2452 else {
2453 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2454 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2455
2456 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2457 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002458 &pSMBr->hdr.Protocol + data_offset),
2459 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002460 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002462 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2463 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 name_len, nls_codepage);
2465 } else {
2466 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002467 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 data_offset,
2469 min_t(const int, buflen, count));
2470 }
2471 symlinkinfo[buflen] = 0;
2472 /* just in case so calling code does not go off the end of buffer */
2473 }
2474 }
2475 cifs_buf_release(pSMB);
2476 if (rc == -EAGAIN)
2477 goto querySymLinkRetry;
2478 return rc;
2479}
2480
Parag Warudkarc94897792007-10-23 18:09:48 +00002481#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002482/* Initialize NT TRANSACT SMB into small smb request buffer.
2483 This assumes that all NT TRANSACTS that we init here have
2484 total parm and data under about 400 bytes (to fit in small cifs
2485 buffer size), which is the case so far, it easily fits. NB:
2486 Setup words themselves and ByteCount
2487 MaxSetupCount (size of returned setup area) and
2488 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002489static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002490smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002491 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002492 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002493{
2494 int rc;
2495 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002496 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002497
2498 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2499 (void **)&pSMB);
2500 if (rc)
2501 return rc;
2502 *ret_buf = (void *)pSMB;
2503 pSMB->Reserved = 0;
2504 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2505 pSMB->TotalDataCount = 0;
2506 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2507 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2508 pSMB->ParameterCount = pSMB->TotalParameterCount;
2509 pSMB->DataCount = pSMB->TotalDataCount;
2510 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2511 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2512 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2513 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2514 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2515 pSMB->SubCommand = cpu_to_le16(sub_command);
2516 return 0;
2517}
2518
2519static int
Steve French50c2f752007-07-13 00:33:32 +00002520validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002521 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002522{
Steve French50c2f752007-07-13 00:33:32 +00002523 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002524 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002525 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002526
Steve French630f3f0c2007-10-25 21:17:17 +00002527 *pdatalen = 0;
2528 *pparmlen = 0;
2529
Steve French790fe572007-07-07 19:25:05 +00002530 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002531 return -EINVAL;
2532
2533 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2534
2535 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002536 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002537 (char *)&pSMBr->ByteCount;
2538
Steve French0a4b92c2006-01-12 15:44:21 -08002539 data_offset = le32_to_cpu(pSMBr->DataOffset);
2540 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002541 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002542 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2543
2544 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2545 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2546
2547 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002548 if (*ppparm > end_of_smb) {
2549 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002550 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002551 } else if (parm_count + *ppparm > end_of_smb) {
2552 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002553 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002554 } else if (*ppdata > end_of_smb) {
2555 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002556 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002557 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002558 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002559 *ppdata, data_count, (data_count + *ppdata),
2560 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002561 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002562 } else if (parm_count + data_count > pSMBr->ByteCount) {
2563 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002564 return -EINVAL;
2565 }
Steve French630f3f0c2007-10-25 21:17:17 +00002566 *pdatalen = data_count;
2567 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002568 return 0;
2569}
Parag Warudkarc94897792007-10-23 18:09:48 +00002570#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002571
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572int
2573CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2574 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002575 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 const struct nls_table *nls_codepage)
2577{
2578 int rc = 0;
2579 int bytes_returned;
2580 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002581 struct smb_com_transaction_ioctl_req *pSMB;
2582 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2585 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2586 (void **) &pSMBr);
2587 if (rc)
2588 return rc;
2589
2590 pSMB->TotalParameterCount = 0 ;
2591 pSMB->TotalDataCount = 0;
2592 pSMB->MaxParameterCount = cpu_to_le32(2);
2593 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002594 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2595 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 pSMB->MaxSetupCount = 4;
2597 pSMB->Reserved = 0;
2598 pSMB->ParameterOffset = 0;
2599 pSMB->DataCount = 0;
2600 pSMB->DataOffset = 0;
2601 pSMB->SetupCount = 4;
2602 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2603 pSMB->ParameterCount = pSMB->TotalParameterCount;
2604 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2605 pSMB->IsFsctl = 1; /* FSCTL */
2606 pSMB->IsRootFlag = 0;
2607 pSMB->Fid = fid; /* file handle always le */
2608 pSMB->ByteCount = 0;
2609
2610 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2611 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2612 if (rc) {
2613 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2614 } else { /* decode response */
2615 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2616 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2617 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2618 /* BB also check enough total bytes returned */
2619 rc = -EIO; /* bad smb */
2620 else {
Steve French790fe572007-07-07 19:25:05 +00002621 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002622 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002623 pSMBr->ByteCount +
2624 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
Steve French50c2f752007-07-13 00:33:32 +00002626 struct reparse_data *reparse_buf =
2627 (struct reparse_data *)
2628 ((char *)&pSMBr->hdr.Protocol
2629 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002630 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 rc = -EIO;
2632 goto qreparse_out;
2633 }
Steve French790fe572007-07-07 19:25:05 +00002634 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 reparse_buf->TargetNameOffset +
2636 reparse_buf->TargetNameLen) >
2637 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002638 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 rc = -EIO;
2640 goto qreparse_out;
2641 }
Steve French50c2f752007-07-13 00:33:32 +00002642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2644 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002645 (reparse_buf->LinkNamesBuf +
2646 reparse_buf->TargetNameOffset),
2647 min(buflen/2,
2648 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002650 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 reparse_buf->TargetNameOffset),
2652 name_len, nls_codepage);
2653 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002654 strncpy(symlinkinfo,
2655 reparse_buf->LinkNamesBuf +
2656 reparse_buf->TargetNameOffset,
2657 min_t(const int, buflen,
2658 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 }
2660 } else {
2661 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002662 cFYI(1, ("Invalid return data count on "
2663 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665 symlinkinfo[buflen] = 0; /* just in case so the caller
2666 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002667 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 }
2669 }
2670qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002671 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673 /* Note: On -EAGAIN error only caller can retry on handle based calls
2674 since file handle passed in no longer valid */
2675
2676 return rc;
2677}
2678
2679#ifdef CONFIG_CIFS_POSIX
2680
2681/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002682static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2683 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684{
2685 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002686 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2687 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2688 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2690
2691 return;
2692}
2693
2694/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002695static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2696 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
2698 int size = 0;
2699 int i;
2700 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002701 struct cifs_posix_ace *pACE;
2702 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2703 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2706 return -EOPNOTSUPP;
2707
Steve French790fe572007-07-07 19:25:05 +00002708 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 count = le16_to_cpu(cifs_acl->access_entry_count);
2710 pACE = &cifs_acl->ace_array[0];
2711 size = sizeof(struct cifs_posix_acl);
2712 size += sizeof(struct cifs_posix_ace) * count;
2713 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002714 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002715 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2716 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return -EINVAL;
2718 }
Steve French790fe572007-07-07 19:25:05 +00002719 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 count = le16_to_cpu(cifs_acl->access_entry_count);
2721 size = sizeof(struct cifs_posix_acl);
2722 size += sizeof(struct cifs_posix_ace) * count;
2723/* skip past access ACEs to get to default ACEs */
2724 pACE = &cifs_acl->ace_array[count];
2725 count = le16_to_cpu(cifs_acl->default_entry_count);
2726 size += sizeof(struct cifs_posix_ace) * count;
2727 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002728 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 return -EINVAL;
2730 } else {
2731 /* illegal type */
2732 return -EINVAL;
2733 }
2734
2735 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002736 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002737 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002738 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 return -ERANGE;
2740 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002741 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002742 for (i = 0; i < count ; i++) {
2743 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2744 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 }
2746 }
2747 return size;
2748}
2749
Steve French50c2f752007-07-13 00:33:32 +00002750static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2751 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752{
2753 __u16 rc = 0; /* 0 = ACL converted ok */
2754
Steve Frenchff7feac2005-11-15 16:45:16 -08002755 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2756 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002758 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 /* Probably no need to le convert -1 on any arch but can not hurt */
2760 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002761 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002762 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002763 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 return rc;
2765}
2766
2767/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002768static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2769 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770{
2771 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002772 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2773 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 int count;
2775 int i;
2776
Steve French790fe572007-07-07 19:25:05 +00002777 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 return 0;
2779
2780 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002781 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002782 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002783 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002784 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002785 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002786 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 return 0;
2788 }
2789 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002790 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002791 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002792 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002793 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 else {
Steve French50c2f752007-07-13 00:33:32 +00002795 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 return 0;
2797 }
Steve French50c2f752007-07-13 00:33:32 +00002798 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2800 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002801 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 /* ACE not converted */
2803 break;
2804 }
2805 }
Steve French790fe572007-07-07 19:25:05 +00002806 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2808 rc += sizeof(struct cifs_posix_acl);
2809 /* BB add check to make sure ACL does not overflow SMB */
2810 }
2811 return rc;
2812}
2813
2814int
2815CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002816 const unsigned char *searchName,
2817 char *acl_inf, const int buflen, const int acl_type,
2818 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819{
2820/* SMB_QUERY_POSIX_ACL */
2821 TRANSACTION2_QPI_REQ *pSMB = NULL;
2822 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2823 int rc = 0;
2824 int bytes_returned;
2825 int name_len;
2826 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002827
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2829
2830queryAclRetry:
2831 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2832 (void **) &pSMBr);
2833 if (rc)
2834 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002835
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2837 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002838 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002839 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 name_len++; /* trailing null */
2841 name_len *= 2;
2842 pSMB->FileName[name_len] = 0;
2843 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002844 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 name_len = strnlen(searchName, PATH_MAX);
2846 name_len++; /* trailing null */
2847 strncpy(pSMB->FileName, searchName, name_len);
2848 }
2849
2850 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2851 pSMB->TotalDataCount = 0;
2852 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002853 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 pSMB->MaxDataCount = cpu_to_le16(4000);
2855 pSMB->MaxSetupCount = 0;
2856 pSMB->Reserved = 0;
2857 pSMB->Flags = 0;
2858 pSMB->Timeout = 0;
2859 pSMB->Reserved2 = 0;
2860 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002861 offsetof(struct smb_com_transaction2_qpi_req,
2862 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 pSMB->DataCount = 0;
2864 pSMB->DataOffset = 0;
2865 pSMB->SetupCount = 1;
2866 pSMB->Reserved3 = 0;
2867 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2868 byte_count = params + 1 /* pad */ ;
2869 pSMB->TotalParameterCount = cpu_to_le16(params);
2870 pSMB->ParameterCount = pSMB->TotalParameterCount;
2871 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2872 pSMB->Reserved4 = 0;
2873 pSMB->hdr.smb_buf_length += byte_count;
2874 pSMB->ByteCount = cpu_to_le16(byte_count);
2875
2876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002878 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 if (rc) {
2880 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2881 } else {
2882 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002883
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2885 if (rc || (pSMBr->ByteCount < 2))
2886 /* BB also check enough total bytes returned */
2887 rc = -EIO; /* bad smb */
2888 else {
2889 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2890 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2891 rc = cifs_copy_posix_acl(acl_inf,
2892 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002893 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 }
2895 }
2896 cifs_buf_release(pSMB);
2897 if (rc == -EAGAIN)
2898 goto queryAclRetry;
2899 return rc;
2900}
2901
2902int
2903CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002904 const unsigned char *fileName,
2905 const char *local_acl, const int buflen,
2906 const int acl_type,
2907 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908{
2909 struct smb_com_transaction2_spi_req *pSMB = NULL;
2910 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2911 char *parm_data;
2912 int name_len;
2913 int rc = 0;
2914 int bytes_returned = 0;
2915 __u16 params, byte_count, data_count, param_offset, offset;
2916
2917 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2918setAclRetry:
2919 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002920 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 if (rc)
2922 return rc;
2923 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2924 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002925 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002926 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 name_len++; /* trailing null */
2928 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002929 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 name_len = strnlen(fileName, PATH_MAX);
2931 name_len++; /* trailing null */
2932 strncpy(pSMB->FileName, fileName, name_len);
2933 }
2934 params = 6 + name_len;
2935 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002936 /* BB find max SMB size from sess */
2937 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 pSMB->MaxSetupCount = 0;
2939 pSMB->Reserved = 0;
2940 pSMB->Flags = 0;
2941 pSMB->Timeout = 0;
2942 pSMB->Reserved2 = 0;
2943 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002944 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 offset = param_offset + params;
2946 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2947 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2948
2949 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002950 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
Steve French790fe572007-07-07 19:25:05 +00002952 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 rc = -EOPNOTSUPP;
2954 goto setACLerrorExit;
2955 }
2956 pSMB->DataOffset = cpu_to_le16(offset);
2957 pSMB->SetupCount = 1;
2958 pSMB->Reserved3 = 0;
2959 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2960 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2961 byte_count = 3 /* pad */ + params + data_count;
2962 pSMB->DataCount = cpu_to_le16(data_count);
2963 pSMB->TotalDataCount = pSMB->DataCount;
2964 pSMB->ParameterCount = cpu_to_le16(params);
2965 pSMB->TotalParameterCount = pSMB->ParameterCount;
2966 pSMB->Reserved4 = 0;
2967 pSMB->hdr.smb_buf_length += byte_count;
2968 pSMB->ByteCount = cpu_to_le16(byte_count);
2969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002971 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
2974setACLerrorExit:
2975 cifs_buf_release(pSMB);
2976 if (rc == -EAGAIN)
2977 goto setAclRetry;
2978 return rc;
2979}
2980
Steve Frenchf654bac2005-04-28 22:41:04 -07002981/* BB fix tabs in this function FIXME BB */
2982int
2983CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002984 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002985{
Steve French50c2f752007-07-13 00:33:32 +00002986 int rc = 0;
2987 struct smb_t2_qfi_req *pSMB = NULL;
2988 struct smb_t2_qfi_rsp *pSMBr = NULL;
2989 int bytes_returned;
2990 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002991
Steve French790fe572007-07-07 19:25:05 +00002992 cFYI(1, ("In GetExtAttr"));
2993 if (tcon == NULL)
2994 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002995
2996GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2998 (void **) &pSMBr);
2999 if (rc)
3000 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003001
Steve Frenchad7a2922008-02-07 23:25:02 +00003002 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003003 pSMB->t2.TotalDataCount = 0;
3004 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3005 /* BB find exact max data count below from sess structure BB */
3006 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3007 pSMB->t2.MaxSetupCount = 0;
3008 pSMB->t2.Reserved = 0;
3009 pSMB->t2.Flags = 0;
3010 pSMB->t2.Timeout = 0;
3011 pSMB->t2.Reserved2 = 0;
3012 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3013 Fid) - 4);
3014 pSMB->t2.DataCount = 0;
3015 pSMB->t2.DataOffset = 0;
3016 pSMB->t2.SetupCount = 1;
3017 pSMB->t2.Reserved3 = 0;
3018 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3019 byte_count = params + 1 /* pad */ ;
3020 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3021 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3022 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3023 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003024 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003025 pSMB->hdr.smb_buf_length += byte_count;
3026 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003027
Steve French790fe572007-07-07 19:25:05 +00003028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3030 if (rc) {
3031 cFYI(1, ("error %d in GetExtAttr", rc));
3032 } else {
3033 /* decode response */
3034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3035 if (rc || (pSMBr->ByteCount < 2))
3036 /* BB also check enough total bytes returned */
3037 /* If rc should we check for EOPNOSUPP and
3038 disable the srvino flag? or in caller? */
3039 rc = -EIO; /* bad smb */
3040 else {
3041 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3042 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3043 struct file_chattr_info *pfinfo;
3044 /* BB Do we need a cast or hash here ? */
3045 if (count != 16) {
3046 cFYI(1, ("Illegal size ret in GetExtAttr"));
3047 rc = -EIO;
3048 goto GetExtAttrOut;
3049 }
3050 pfinfo = (struct file_chattr_info *)
3051 (data_offset + (char *) &pSMBr->hdr.Protocol);
3052 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003053 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003054 }
3055 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003056GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003057 cifs_buf_release(pSMB);
3058 if (rc == -EAGAIN)
3059 goto GetExtAttrRetry;
3060 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003061}
3062
Steve Frenchf654bac2005-04-28 22:41:04 -07003063#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
Steve French297647c2007-10-12 04:11:59 +00003065#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003066/* Get Security Descriptor (by handle) from remote server for a file or dir */
3067int
3068CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003069 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003070{
3071 int rc = 0;
3072 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003073 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003074 struct kvec iov[1];
3075
3076 cFYI(1, ("GetCifsACL"));
3077
Steve French630f3f0c2007-10-25 21:17:17 +00003078 *pbuflen = 0;
3079 *acl_inf = NULL;
3080
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003081 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003082 8 /* parm len */, tcon, (void **) &pSMB);
3083 if (rc)
3084 return rc;
3085
3086 pSMB->MaxParameterCount = cpu_to_le32(4);
3087 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3088 pSMB->MaxSetupCount = 0;
3089 pSMB->Fid = fid; /* file handle always le */
3090 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3091 CIFS_ACL_DACL);
3092 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3093 pSMB->hdr.smb_buf_length += 11;
3094 iov[0].iov_base = (char *)pSMB;
3095 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3096
Steve Frencha761ac52007-10-18 21:45:27 +00003097 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003098 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003099 cifs_stats_inc(&tcon->num_acl_get);
3100 if (rc) {
3101 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3102 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003103 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003104 __u32 parm_len;
3105 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003106 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003107 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003108
3109/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003110 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003111 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003112 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003113 goto qsec_out;
3114 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3115
Steve French630f3f0c2007-10-25 21:17:17 +00003116 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003117
3118 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3119 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003120 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003121 goto qsec_out;
3122 }
3123
3124/* BB check that data area is minimum length and as big as acl_len */
3125
Steve Frenchaf6f4612007-10-16 18:40:37 +00003126 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003127 if (acl_len != *pbuflen) {
3128 cERROR(1, ("acl length %d does not match %d",
3129 acl_len, *pbuflen));
3130 if (*pbuflen > acl_len)
3131 *pbuflen = acl_len;
3132 }
Steve French0a4b92c2006-01-12 15:44:21 -08003133
Steve French630f3f0c2007-10-25 21:17:17 +00003134 /* check if buffer is big enough for the acl
3135 header followed by the smallest SID */
3136 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3137 (*pbuflen >= 64 * 1024)) {
3138 cERROR(1, ("bad acl length %d", *pbuflen));
3139 rc = -EINVAL;
3140 *pbuflen = 0;
3141 } else {
3142 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3143 if (*acl_inf == NULL) {
3144 *pbuflen = 0;
3145 rc = -ENOMEM;
3146 }
3147 memcpy(*acl_inf, pdata, *pbuflen);
3148 }
Steve French0a4b92c2006-01-12 15:44:21 -08003149 }
3150qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003151 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003152 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003153 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003154 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003155/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003156 return rc;
3157}
Steve French97837582007-12-31 07:47:21 +00003158
3159int
3160CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3161 struct cifs_ntsd *pntsd, __u32 acllen)
3162{
3163 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3164 int rc = 0;
3165 int bytes_returned = 0;
3166 SET_SEC_DESC_REQ *pSMB = NULL;
3167 NTRANSACT_RSP *pSMBr = NULL;
3168
3169setCifsAclRetry:
3170 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3171 (void **) &pSMBr);
3172 if (rc)
3173 return (rc);
3174
3175 pSMB->MaxSetupCount = 0;
3176 pSMB->Reserved = 0;
3177
3178 param_count = 8;
3179 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3180 data_count = acllen;
3181 data_offset = param_offset + param_count;
3182 byte_count = 3 /* pad */ + param_count;
3183
3184 pSMB->DataCount = cpu_to_le32(data_count);
3185 pSMB->TotalDataCount = pSMB->DataCount;
3186 pSMB->MaxParameterCount = cpu_to_le32(4);
3187 pSMB->MaxDataCount = cpu_to_le32(16384);
3188 pSMB->ParameterCount = cpu_to_le32(param_count);
3189 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3190 pSMB->TotalParameterCount = pSMB->ParameterCount;
3191 pSMB->DataOffset = cpu_to_le32(data_offset);
3192 pSMB->SetupCount = 0;
3193 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3194 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3195
3196 pSMB->Fid = fid; /* file handle always le */
3197 pSMB->Reserved2 = 0;
3198 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3199
3200 if (pntsd && acllen) {
3201 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3202 (char *) pntsd,
3203 acllen);
3204 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3205
3206 } else
3207 pSMB->hdr.smb_buf_length += byte_count;
3208
3209 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3210 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3211
3212 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3213 if (rc)
3214 cFYI(1, ("Set CIFS ACL returned %d", rc));
3215 cifs_buf_release(pSMB);
3216
3217 if (rc == -EAGAIN)
3218 goto setCifsAclRetry;
3219
3220 return (rc);
3221}
3222
Steve French297647c2007-10-12 04:11:59 +00003223#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003224
Steve French6b8edfe2005-08-23 20:26:03 -07003225/* Legacy Query Path Information call for lookup to old servers such
3226 as Win9x/WinME */
3227int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003228 const unsigned char *searchName,
3229 FILE_ALL_INFO *pFinfo,
3230 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003231{
Steve Frenchad7a2922008-02-07 23:25:02 +00003232 QUERY_INFORMATION_REQ *pSMB;
3233 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003234 int rc = 0;
3235 int bytes_returned;
3236 int name_len;
3237
Steve French50c2f752007-07-13 00:33:32 +00003238 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003239QInfRetry:
3240 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003241 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003242 if (rc)
3243 return rc;
3244
3245 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3246 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003247 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3248 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003249 name_len++; /* trailing null */
3250 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003251 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003252 name_len = strnlen(searchName, PATH_MAX);
3253 name_len++; /* trailing null */
3254 strncpy(pSMB->FileName, searchName, name_len);
3255 }
3256 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003257 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003258 pSMB->hdr.smb_buf_length += (__u16) name_len;
3259 pSMB->ByteCount = cpu_to_le16(name_len);
3260
3261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003263 if (rc) {
3264 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003265 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003266 struct timespec ts;
3267 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003268
3269 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003270 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003271 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003272 ts.tv_nsec = 0;
3273 ts.tv_sec = time;
3274 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003275 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003276 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3277 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003278 pFinfo->AllocationSize =
3279 cpu_to_le64(le32_to_cpu(pSMBr->size));
3280 pFinfo->EndOfFile = pFinfo->AllocationSize;
3281 pFinfo->Attributes =
3282 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003283 } else
3284 rc = -EIO; /* bad buffer passed in */
3285
3286 cifs_buf_release(pSMB);
3287
3288 if (rc == -EAGAIN)
3289 goto QInfRetry;
3290
3291 return rc;
3292}
3293
3294
3295
3296
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297int
3298CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3299 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003300 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003301 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003302 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303{
3304/* level 263 SMB_QUERY_FILE_ALL_INFO */
3305 TRANSACTION2_QPI_REQ *pSMB = NULL;
3306 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3307 int rc = 0;
3308 int bytes_returned;
3309 int name_len;
3310 __u16 params, byte_count;
3311
3312/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3313QPathInfoRetry:
3314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3315 (void **) &pSMBr);
3316 if (rc)
3317 return rc;
3318
3319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3320 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003321 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003322 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 name_len++; /* trailing null */
3324 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003325 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 name_len = strnlen(searchName, PATH_MAX);
3327 name_len++; /* trailing null */
3328 strncpy(pSMB->FileName, searchName, name_len);
3329 }
3330
Steve French50c2f752007-07-13 00:33:32 +00003331 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 pSMB->TotalDataCount = 0;
3333 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003334 /* BB find exact max SMB PDU from sess structure BB */
3335 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 pSMB->MaxSetupCount = 0;
3337 pSMB->Reserved = 0;
3338 pSMB->Flags = 0;
3339 pSMB->Timeout = 0;
3340 pSMB->Reserved2 = 0;
3341 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003342 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 pSMB->DataCount = 0;
3344 pSMB->DataOffset = 0;
3345 pSMB->SetupCount = 1;
3346 pSMB->Reserved3 = 0;
3347 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3348 byte_count = params + 1 /* pad */ ;
3349 pSMB->TotalParameterCount = cpu_to_le16(params);
3350 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003351 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003352 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3353 else
3354 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 pSMB->Reserved4 = 0;
3356 pSMB->hdr.smb_buf_length += byte_count;
3357 pSMB->ByteCount = cpu_to_le16(byte_count);
3358
3359 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3360 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3361 if (rc) {
3362 cFYI(1, ("Send error in QPathInfo = %d", rc));
3363 } else { /* decode response */
3364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3365
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003366 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3367 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003368 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003370 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003371 rc = -EIO; /* 24 or 26 expected but we do not read
3372 last field */
3373 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003374 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003376
3377 /* On legacy responses we do not read the last field,
3378 EAsize, fortunately since it varies by subdialect and
3379 also note it differs on Set vs. Get, ie two bytes or 4
3380 bytes depending but we don't care here */
3381 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003382 size = sizeof(FILE_INFO_STANDARD);
3383 else
3384 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 memcpy((char *) pFindData,
3386 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003387 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 } else
3389 rc = -ENOMEM;
3390 }
3391 cifs_buf_release(pSMB);
3392 if (rc == -EAGAIN)
3393 goto QPathInfoRetry;
3394
3395 return rc;
3396}
3397
3398int
3399CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3400 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003401 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003402 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403{
3404/* SMB_QUERY_FILE_UNIX_BASIC */
3405 TRANSACTION2_QPI_REQ *pSMB = NULL;
3406 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3407 int rc = 0;
3408 int bytes_returned = 0;
3409 int name_len;
3410 __u16 params, byte_count;
3411
3412 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3413UnixQPathInfoRetry:
3414 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3415 (void **) &pSMBr);
3416 if (rc)
3417 return rc;
3418
3419 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3420 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003421 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003422 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 name_len++; /* trailing null */
3424 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003425 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 name_len = strnlen(searchName, PATH_MAX);
3427 name_len++; /* trailing null */
3428 strncpy(pSMB->FileName, searchName, name_len);
3429 }
3430
Steve French50c2f752007-07-13 00:33:32 +00003431 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 pSMB->TotalDataCount = 0;
3433 pSMB->MaxParameterCount = cpu_to_le16(2);
3434 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003435 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 pSMB->MaxSetupCount = 0;
3437 pSMB->Reserved = 0;
3438 pSMB->Flags = 0;
3439 pSMB->Timeout = 0;
3440 pSMB->Reserved2 = 0;
3441 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003442 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 pSMB->DataCount = 0;
3444 pSMB->DataOffset = 0;
3445 pSMB->SetupCount = 1;
3446 pSMB->Reserved3 = 0;
3447 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3448 byte_count = params + 1 /* pad */ ;
3449 pSMB->TotalParameterCount = cpu_to_le16(params);
3450 pSMB->ParameterCount = pSMB->TotalParameterCount;
3451 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3452 pSMB->Reserved4 = 0;
3453 pSMB->hdr.smb_buf_length += byte_count;
3454 pSMB->ByteCount = cpu_to_le16(byte_count);
3455
3456 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3457 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3458 if (rc) {
3459 cFYI(1, ("Send error in QPathInfo = %d", rc));
3460 } else { /* decode response */
3461 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3462
3463 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003464 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3465 "Unix Extensions can be disabled on mount "
3466 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 rc = -EIO; /* bad smb */
3468 } else {
3469 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3470 memcpy((char *) pFindData,
3471 (char *) &pSMBr->hdr.Protocol +
3472 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003473 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 }
3475 }
3476 cifs_buf_release(pSMB);
3477 if (rc == -EAGAIN)
3478 goto UnixQPathInfoRetry;
3479
3480 return rc;
3481}
3482
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483/* xid, tcon, searchName and codepage are input parms, rest are returned */
3484int
3485CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003486 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003488 __u16 *pnetfid,
3489 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490{
3491/* level 257 SMB_ */
3492 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3493 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003494 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 int rc = 0;
3496 int bytes_returned = 0;
3497 int name_len;
3498 __u16 params, byte_count;
3499
Steve French50c2f752007-07-13 00:33:32 +00003500 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
3502findFirstRetry:
3503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3504 (void **) &pSMBr);
3505 if (rc)
3506 return rc;
3507
3508 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3509 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003510 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003511 PATH_MAX, nls_codepage, remap);
3512 /* We can not add the asterik earlier in case
3513 it got remapped to 0xF03A as if it were part of the
3514 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003516 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003517 pSMB->FileName[name_len+1] = 0;
3518 pSMB->FileName[name_len+2] = '*';
3519 pSMB->FileName[name_len+3] = 0;
3520 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3522 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003523 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 } else { /* BB add check for overrun of SMB buf BB */
3525 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003527 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 free buffer exit; BB */
3529 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003530 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003531 pSMB->FileName[name_len+1] = '*';
3532 pSMB->FileName[name_len+2] = 0;
3533 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 }
3535
3536 params = 12 + name_len /* includes null */ ;
3537 pSMB->TotalDataCount = 0; /* no EAs */
3538 pSMB->MaxParameterCount = cpu_to_le16(10);
3539 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3540 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3541 pSMB->MaxSetupCount = 0;
3542 pSMB->Reserved = 0;
3543 pSMB->Flags = 0;
3544 pSMB->Timeout = 0;
3545 pSMB->Reserved2 = 0;
3546 byte_count = params + 1 /* pad */ ;
3547 pSMB->TotalParameterCount = cpu_to_le16(params);
3548 pSMB->ParameterCount = pSMB->TotalParameterCount;
3549 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003550 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3551 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 pSMB->DataCount = 0;
3553 pSMB->DataOffset = 0;
3554 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3555 pSMB->Reserved3 = 0;
3556 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3557 pSMB->SearchAttributes =
3558 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3559 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003560 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3561 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 CIFS_SEARCH_RETURN_RESUME);
3563 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3564
3565 /* BB what should we set StorageType to? Does it matter? BB */
3566 pSMB->SearchStorageType = 0;
3567 pSMB->hdr.smb_buf_length += byte_count;
3568 pSMB->ByteCount = cpu_to_le16(byte_count);
3569
3570 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3571 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003572 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573
Steve French88274812006-03-09 22:21:45 +00003574 if (rc) {/* BB add logic to retry regular search if Unix search
3575 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 /* BB Add code to handle unsupported level rc */
3577 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003578
Steve French88274812006-03-09 22:21:45 +00003579 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
3581 /* BB eventually could optimize out free and realloc of buf */
3582 /* for this case */
3583 if (rc == -EAGAIN)
3584 goto findFirstRetry;
3585 } else { /* decode response */
3586 /* BB remember to free buffer if error BB */
3587 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003588 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003590 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 else
Steve French4b18f2a2008-04-29 00:06:05 +00003592 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593
3594 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003595 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003596 psrch_inf->srch_entries_start =
3597 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3600 le16_to_cpu(pSMBr->t2.ParameterOffset));
3601
Steve French790fe572007-07-07 19:25:05 +00003602 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003603 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 else
Steve French4b18f2a2008-04-29 00:06:05 +00003605 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
Steve French50c2f752007-07-13 00:33:32 +00003607 psrch_inf->entries_in_buffer =
3608 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003609 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 *pnetfid = parms->SearchHandle;
3612 } else {
3613 cifs_buf_release(pSMB);
3614 }
3615 }
3616
3617 return rc;
3618}
3619
3620int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003621 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622{
3623 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3624 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003625 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 char *response_data;
3627 int rc = 0;
3628 int bytes_returned, name_len;
3629 __u16 params, byte_count;
3630
3631 cFYI(1, ("In FindNext"));
3632
Steve French4b18f2a2008-04-29 00:06:05 +00003633 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 return -ENOENT;
3635
3636 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3637 (void **) &pSMBr);
3638 if (rc)
3639 return rc;
3640
Steve French50c2f752007-07-13 00:33:32 +00003641 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 byte_count = 0;
3643 pSMB->TotalDataCount = 0; /* no EAs */
3644 pSMB->MaxParameterCount = cpu_to_le16(8);
3645 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003646 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3647 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 pSMB->MaxSetupCount = 0;
3649 pSMB->Reserved = 0;
3650 pSMB->Flags = 0;
3651 pSMB->Timeout = 0;
3652 pSMB->Reserved2 = 0;
3653 pSMB->ParameterOffset = cpu_to_le16(
3654 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3655 pSMB->DataCount = 0;
3656 pSMB->DataOffset = 0;
3657 pSMB->SetupCount = 1;
3658 pSMB->Reserved3 = 0;
3659 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3660 pSMB->SearchHandle = searchHandle; /* always kept as le */
3661 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003662 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3664 pSMB->ResumeKey = psrch_inf->resume_key;
3665 pSMB->SearchFlags =
3666 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3667
3668 name_len = psrch_inf->resume_name_len;
3669 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003670 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3672 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003673 /* 14 byte parm len above enough for 2 byte null terminator */
3674 pSMB->ResumeFileName[name_len] = 0;
3675 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 } else {
3677 rc = -EINVAL;
3678 goto FNext2_err_exit;
3679 }
3680 byte_count = params + 1 /* pad */ ;
3681 pSMB->TotalParameterCount = cpu_to_le16(params);
3682 pSMB->ParameterCount = pSMB->TotalParameterCount;
3683 pSMB->hdr.smb_buf_length += byte_count;
3684 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003685
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3687 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003688 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 if (rc) {
3690 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003691 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003692 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003693 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 } else
3695 cFYI(1, ("FindNext returned = %d", rc));
3696 } else { /* decode response */
3697 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003698
Steve French790fe572007-07-07 19:25:05 +00003699 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 /* BB fixme add lock for file (srch_info) struct here */
3701 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003702 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 else
Steve French4b18f2a2008-04-29 00:06:05 +00003704 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 response_data = (char *) &pSMBr->hdr.Protocol +
3706 le16_to_cpu(pSMBr->t2.ParameterOffset);
3707 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3708 response_data = (char *)&pSMBr->hdr.Protocol +
3709 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003710 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003711 cifs_small_buf_release(
3712 psrch_inf->ntwrk_buf_start);
3713 else
3714 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 psrch_inf->srch_entries_start = response_data;
3716 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003717 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003718 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003719 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 else
Steve French4b18f2a2008-04-29 00:06:05 +00003721 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003722 psrch_inf->entries_in_buffer =
3723 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 psrch_inf->index_of_last_entry +=
3725 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003726/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3727 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
3729 /* BB fixme add unlock here */
3730 }
3731
3732 }
3733
3734 /* BB On error, should we leave previous search buf (and count and
3735 last entry fields) intact or free the previous one? */
3736
3737 /* Note: On -EAGAIN error only caller can retry on handle based calls
3738 since file handle passed in no longer valid */
3739FNext2_err_exit:
3740 if (rc != 0)
3741 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 return rc;
3743}
3744
3745int
Steve French50c2f752007-07-13 00:33:32 +00003746CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3747 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748{
3749 int rc = 0;
3750 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
3752 cFYI(1, ("In CIFSSMBFindClose"));
3753 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3754
3755 /* no sense returning error if session restarted
3756 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003757 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 return 0;
3759 if (rc)
3760 return rc;
3761
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 pSMB->FileID = searchHandle;
3763 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003764 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003765 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003767
Steve Frencha45443472005-08-24 13:59:35 -07003768 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
3770 /* Since session is dead, search handle closed on server already */
3771 if (rc == -EAGAIN)
3772 rc = 0;
3773
3774 return rc;
3775}
3776
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777int
3778CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003779 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003780 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003781 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782{
3783 int rc = 0;
3784 TRANSACTION2_QPI_REQ *pSMB = NULL;
3785 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3786 int name_len, bytes_returned;
3787 __u16 params, byte_count;
3788
Steve French50c2f752007-07-13 00:33:32 +00003789 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003790 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003791 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792
3793GetInodeNumberRetry:
3794 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003795 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 if (rc)
3797 return rc;
3798
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3800 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003801 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003802 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 name_len++; /* trailing null */
3804 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003805 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 name_len = strnlen(searchName, PATH_MAX);
3807 name_len++; /* trailing null */
3808 strncpy(pSMB->FileName, searchName, name_len);
3809 }
3810
3811 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3812 pSMB->TotalDataCount = 0;
3813 pSMB->MaxParameterCount = cpu_to_le16(2);
3814 /* BB find exact max data count below from sess structure BB */
3815 pSMB->MaxDataCount = cpu_to_le16(4000);
3816 pSMB->MaxSetupCount = 0;
3817 pSMB->Reserved = 0;
3818 pSMB->Flags = 0;
3819 pSMB->Timeout = 0;
3820 pSMB->Reserved2 = 0;
3821 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003822 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 pSMB->DataCount = 0;
3824 pSMB->DataOffset = 0;
3825 pSMB->SetupCount = 1;
3826 pSMB->Reserved3 = 0;
3827 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3828 byte_count = params + 1 /* pad */ ;
3829 pSMB->TotalParameterCount = cpu_to_le16(params);
3830 pSMB->ParameterCount = pSMB->TotalParameterCount;
3831 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3832 pSMB->Reserved4 = 0;
3833 pSMB->hdr.smb_buf_length += byte_count;
3834 pSMB->ByteCount = cpu_to_le16(byte_count);
3835
3836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3837 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3838 if (rc) {
3839 cFYI(1, ("error %d in QueryInternalInfo", rc));
3840 } else {
3841 /* decode response */
3842 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3843 if (rc || (pSMBr->ByteCount < 2))
3844 /* BB also check enough total bytes returned */
3845 /* If rc should we check for EOPNOSUPP and
3846 disable the srvino flag? or in caller? */
3847 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003848 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3850 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003851 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003853 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3855 rc = -EIO;
3856 goto GetInodeNumOut;
3857 }
3858 pfinfo = (struct file_internal_info *)
3859 (data_offset + (char *) &pSMBr->hdr.Protocol);
3860 *inode_number = pfinfo->UniqueId;
3861 }
3862 }
3863GetInodeNumOut:
3864 cifs_buf_release(pSMB);
3865 if (rc == -EAGAIN)
3866 goto GetInodeNumberRetry;
3867 return rc;
3868}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869
3870int
3871CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3872 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003873 struct dfs_info3_param **target_nodes,
3874 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07003875 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876{
3877/* TRANS2_GET_DFS_REFERRAL */
3878 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3879 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003880 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 int rc = 0;
3882 int bytes_returned;
3883 int name_len;
3884 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003885 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003887 *num_of_nodes = 0;
3888 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889
3890 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3891 if (ses == NULL)
3892 return -ENODEV;
3893getDFSRetry:
3894 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3895 (void **) &pSMBr);
3896 if (rc)
3897 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003898
3899 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003900 but should never be null here anyway */
3901 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 pSMB->hdr.Tid = ses->ipc_tid;
3903 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003904 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003906 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
3909 if (ses->capabilities & CAP_UNICODE) {
3910 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3911 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003912 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003913 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 name_len++; /* trailing null */
3915 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003916 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 name_len = strnlen(searchName, PATH_MAX);
3918 name_len++; /* trailing null */
3919 strncpy(pSMB->RequestFileName, searchName, name_len);
3920 }
3921
Steve French790fe572007-07-07 19:25:05 +00003922 if (ses->server) {
3923 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003924 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3925 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3926 }
3927
Steve French50c2f752007-07-13 00:33:32 +00003928 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003929
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 params = 2 /* level */ + name_len /*includes null */ ;
3931 pSMB->TotalDataCount = 0;
3932 pSMB->DataCount = 0;
3933 pSMB->DataOffset = 0;
3934 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00003935 /* BB find exact max SMB PDU from sess structure BB */
3936 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 pSMB->MaxSetupCount = 0;
3938 pSMB->Reserved = 0;
3939 pSMB->Flags = 0;
3940 pSMB->Timeout = 0;
3941 pSMB->Reserved2 = 0;
3942 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003943 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 pSMB->SetupCount = 1;
3945 pSMB->Reserved3 = 0;
3946 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3947 byte_count = params + 3 /* pad */ ;
3948 pSMB->ParameterCount = cpu_to_le16(params);
3949 pSMB->TotalParameterCount = pSMB->ParameterCount;
3950 pSMB->MaxReferralLevel = cpu_to_le16(3);
3951 pSMB->hdr.smb_buf_length += byte_count;
3952 pSMB->ByteCount = cpu_to_le16(byte_count);
3953
3954 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3956 if (rc) {
3957 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003958 goto GetDFSRefExit;
3959 }
3960 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003962 /* BB Also check if enough total bytes returned? */
3963 if (rc || (pSMBr->ByteCount < 17))
3964 rc = -EIO; /* bad smb */
3965 else {
3966 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3967 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003969 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
3970 pSMBr->ByteCount, data_offset));
3971 referrals =
3972 (struct dfs_referral_level_3 *)
3973 (8 /* sizeof start of data block */ +
3974 data_offset +
3975 (char *) &pSMBr->hdr.Protocol);
3976 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
3977 "for referral one refer size: 0x%x srv "
3978 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3979 le16_to_cpu(pSMBr->NumberOfReferrals),
3980 le16_to_cpu(pSMBr->DFSFlags),
3981 le16_to_cpu(referrals->ReferralSize),
3982 le16_to_cpu(referrals->ServerType),
3983 le16_to_cpu(referrals->ReferralFlags),
3984 le16_to_cpu(referrals->TimeToLive)));
3985 /* BB This field is actually two bytes in from start of
3986 data block so we could do safety check that DataBlock
3987 begins at address of pSMBr->NumberOfReferrals */
3988 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003990 /* BB Fix below so can return more than one referral */
3991 if (*num_of_nodes > 1)
3992 *num_of_nodes = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003994 /* get the length of the strings describing refs */
3995 name_len = 0;
3996 for (i = 0; i < *num_of_nodes; i++) {
3997 /* make sure that DfsPathOffset not past end */
3998 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3999 if (offset > data_count) {
4000 /* if invalid referral, stop here and do
4001 not try to copy any more */
4002 *num_of_nodes = i;
4003 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 }
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004005 temp = ((char *)referrals) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004007 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4008 name_len += UniStrnlen((wchar_t *)temp,
4009 data_count);
4010 } else {
4011 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 }
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004013 referrals++;
4014 /* BB add check that referral pointer does
4015 not fall off end PDU */
4016 }
4017 /* BB add check for name_len bigger than bcc */
4018 *target_nodes =
4019 kmalloc(name_len+1+(*num_of_nodes),
4020 GFP_KERNEL);
4021 if (*target_nodes == NULL) {
4022 rc = -ENOMEM;
4023 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 }
4025
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004026 referrals = (struct dfs_referral_level_3 *)
4027 (8 /* sizeof data hdr */ + data_offset +
4028 (char *) &pSMBr->hdr.Protocol);
4029
4030 for (i = 0; i < *num_of_nodes; i++) {
4031 temp = ((char *)referrals) +
4032 le16_to_cpu(referrals->DfsPathOffset);
4033 /* BB update target_uncs pointers */
4034 referrals++;
4035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 }
4037GetDFSRefExit:
4038 if (pSMB)
4039 cifs_buf_release(pSMB);
4040
4041 if (rc == -EAGAIN)
4042 goto getDFSRetry;
4043
4044 return rc;
4045}
4046
Steve French20962432005-09-21 22:05:57 -07004047/* Query File System Info such as free space to old servers such as Win 9x */
4048int
4049SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4050{
4051/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4052 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4053 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4054 FILE_SYSTEM_ALLOC_INFO *response_data;
4055 int rc = 0;
4056 int bytes_returned = 0;
4057 __u16 params, byte_count;
4058
4059 cFYI(1, ("OldQFSInfo"));
4060oldQFSInfoRetry:
4061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4062 (void **) &pSMBr);
4063 if (rc)
4064 return rc;
Steve French20962432005-09-21 22:05:57 -07004065
4066 params = 2; /* level */
4067 pSMB->TotalDataCount = 0;
4068 pSMB->MaxParameterCount = cpu_to_le16(2);
4069 pSMB->MaxDataCount = cpu_to_le16(1000);
4070 pSMB->MaxSetupCount = 0;
4071 pSMB->Reserved = 0;
4072 pSMB->Flags = 0;
4073 pSMB->Timeout = 0;
4074 pSMB->Reserved2 = 0;
4075 byte_count = params + 1 /* pad */ ;
4076 pSMB->TotalParameterCount = cpu_to_le16(params);
4077 pSMB->ParameterCount = pSMB->TotalParameterCount;
4078 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4079 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4080 pSMB->DataCount = 0;
4081 pSMB->DataOffset = 0;
4082 pSMB->SetupCount = 1;
4083 pSMB->Reserved3 = 0;
4084 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4085 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4086 pSMB->hdr.smb_buf_length += byte_count;
4087 pSMB->ByteCount = cpu_to_le16(byte_count);
4088
4089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091 if (rc) {
4092 cFYI(1, ("Send error in QFSInfo = %d", rc));
4093 } else { /* decode response */
4094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4095
4096 if (rc || (pSMBr->ByteCount < 18))
4097 rc = -EIO; /* bad smb */
4098 else {
4099 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004100 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004101 pSMBr->ByteCount, data_offset));
4102
Steve French50c2f752007-07-13 00:33:32 +00004103 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004104 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4105 FSData->f_bsize =
4106 le16_to_cpu(response_data->BytesPerSector) *
4107 le32_to_cpu(response_data->
4108 SectorsPerAllocationUnit);
4109 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004110 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004111 FSData->f_bfree = FSData->f_bavail =
4112 le32_to_cpu(response_data->FreeAllocationUnits);
4113 cFYI(1,
4114 ("Blocks: %lld Free: %lld Block size %ld",
4115 (unsigned long long)FSData->f_blocks,
4116 (unsigned long long)FSData->f_bfree,
4117 FSData->f_bsize));
4118 }
4119 }
4120 cifs_buf_release(pSMB);
4121
4122 if (rc == -EAGAIN)
4123 goto oldQFSInfoRetry;
4124
4125 return rc;
4126}
4127
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128int
Steve French737b7582005-04-28 22:41:06 -07004129CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130{
4131/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4132 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4133 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4134 FILE_SYSTEM_INFO *response_data;
4135 int rc = 0;
4136 int bytes_returned = 0;
4137 __u16 params, byte_count;
4138
4139 cFYI(1, ("In QFSInfo"));
4140QFSInfoRetry:
4141 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4142 (void **) &pSMBr);
4143 if (rc)
4144 return rc;
4145
4146 params = 2; /* level */
4147 pSMB->TotalDataCount = 0;
4148 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004149 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 pSMB->MaxSetupCount = 0;
4151 pSMB->Reserved = 0;
4152 pSMB->Flags = 0;
4153 pSMB->Timeout = 0;
4154 pSMB->Reserved2 = 0;
4155 byte_count = params + 1 /* pad */ ;
4156 pSMB->TotalParameterCount = cpu_to_le16(params);
4157 pSMB->ParameterCount = pSMB->TotalParameterCount;
4158 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004159 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 pSMB->DataCount = 0;
4161 pSMB->DataOffset = 0;
4162 pSMB->SetupCount = 1;
4163 pSMB->Reserved3 = 0;
4164 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4165 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4166 pSMB->hdr.smb_buf_length += byte_count;
4167 pSMB->ByteCount = cpu_to_le16(byte_count);
4168
4169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004172 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004174 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Steve French20962432005-09-21 22:05:57 -07004176 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 rc = -EIO; /* bad smb */
4178 else {
4179 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
4181 response_data =
4182 (FILE_SYSTEM_INFO
4183 *) (((char *) &pSMBr->hdr.Protocol) +
4184 data_offset);
4185 FSData->f_bsize =
4186 le32_to_cpu(response_data->BytesPerSector) *
4187 le32_to_cpu(response_data->
4188 SectorsPerAllocationUnit);
4189 FSData->f_blocks =
4190 le64_to_cpu(response_data->TotalAllocationUnits);
4191 FSData->f_bfree = FSData->f_bavail =
4192 le64_to_cpu(response_data->FreeAllocationUnits);
4193 cFYI(1,
4194 ("Blocks: %lld Free: %lld Block size %ld",
4195 (unsigned long long)FSData->f_blocks,
4196 (unsigned long long)FSData->f_bfree,
4197 FSData->f_bsize));
4198 }
4199 }
4200 cifs_buf_release(pSMB);
4201
4202 if (rc == -EAGAIN)
4203 goto QFSInfoRetry;
4204
4205 return rc;
4206}
4207
4208int
Steve French737b7582005-04-28 22:41:06 -07004209CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210{
4211/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4212 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4213 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4214 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4215 int rc = 0;
4216 int bytes_returned = 0;
4217 __u16 params, byte_count;
4218
4219 cFYI(1, ("In QFSAttributeInfo"));
4220QFSAttributeRetry:
4221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4222 (void **) &pSMBr);
4223 if (rc)
4224 return rc;
4225
4226 params = 2; /* level */
4227 pSMB->TotalDataCount = 0;
4228 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004229 /* BB find exact max SMB PDU from sess structure BB */
4230 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 pSMB->MaxSetupCount = 0;
4232 pSMB->Reserved = 0;
4233 pSMB->Flags = 0;
4234 pSMB->Timeout = 0;
4235 pSMB->Reserved2 = 0;
4236 byte_count = params + 1 /* pad */ ;
4237 pSMB->TotalParameterCount = cpu_to_le16(params);
4238 pSMB->ParameterCount = pSMB->TotalParameterCount;
4239 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004240 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 pSMB->DataCount = 0;
4242 pSMB->DataOffset = 0;
4243 pSMB->SetupCount = 1;
4244 pSMB->Reserved3 = 0;
4245 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4246 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4247 pSMB->hdr.smb_buf_length += byte_count;
4248 pSMB->ByteCount = cpu_to_le16(byte_count);
4249
4250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4251 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4252 if (rc) {
4253 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4254 } else { /* decode response */
4255 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4256
Steve French50c2f752007-07-13 00:33:32 +00004257 if (rc || (pSMBr->ByteCount < 13)) {
4258 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 rc = -EIO; /* bad smb */
4260 } else {
4261 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4262 response_data =
4263 (FILE_SYSTEM_ATTRIBUTE_INFO
4264 *) (((char *) &pSMBr->hdr.Protocol) +
4265 data_offset);
4266 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004267 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 }
4269 }
4270 cifs_buf_release(pSMB);
4271
4272 if (rc == -EAGAIN)
4273 goto QFSAttributeRetry;
4274
4275 return rc;
4276}
4277
4278int
Steve French737b7582005-04-28 22:41:06 -07004279CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280{
4281/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4282 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4283 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4284 FILE_SYSTEM_DEVICE_INFO *response_data;
4285 int rc = 0;
4286 int bytes_returned = 0;
4287 __u16 params, byte_count;
4288
4289 cFYI(1, ("In QFSDeviceInfo"));
4290QFSDeviceRetry:
4291 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4292 (void **) &pSMBr);
4293 if (rc)
4294 return rc;
4295
4296 params = 2; /* level */
4297 pSMB->TotalDataCount = 0;
4298 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004299 /* BB find exact max SMB PDU from sess structure BB */
4300 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 pSMB->MaxSetupCount = 0;
4302 pSMB->Reserved = 0;
4303 pSMB->Flags = 0;
4304 pSMB->Timeout = 0;
4305 pSMB->Reserved2 = 0;
4306 byte_count = params + 1 /* pad */ ;
4307 pSMB->TotalParameterCount = cpu_to_le16(params);
4308 pSMB->ParameterCount = pSMB->TotalParameterCount;
4309 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004310 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311
4312 pSMB->DataCount = 0;
4313 pSMB->DataOffset = 0;
4314 pSMB->SetupCount = 1;
4315 pSMB->Reserved3 = 0;
4316 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4317 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4318 pSMB->hdr.smb_buf_length += byte_count;
4319 pSMB->ByteCount = cpu_to_le16(byte_count);
4320
4321 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4322 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4323 if (rc) {
4324 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4325 } else { /* decode response */
4326 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4327
Steve French630f3f0c2007-10-25 21:17:17 +00004328 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 rc = -EIO; /* bad smb */
4330 else {
4331 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4332 response_data =
Steve French737b7582005-04-28 22:41:06 -07004333 (FILE_SYSTEM_DEVICE_INFO *)
4334 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 data_offset);
4336 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004337 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 }
4339 }
4340 cifs_buf_release(pSMB);
4341
4342 if (rc == -EAGAIN)
4343 goto QFSDeviceRetry;
4344
4345 return rc;
4346}
4347
4348int
Steve French737b7582005-04-28 22:41:06 -07004349CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350{
4351/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4352 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4353 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4354 FILE_SYSTEM_UNIX_INFO *response_data;
4355 int rc = 0;
4356 int bytes_returned = 0;
4357 __u16 params, byte_count;
4358
4359 cFYI(1, ("In QFSUnixInfo"));
4360QFSUnixRetry:
4361 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4362 (void **) &pSMBr);
4363 if (rc)
4364 return rc;
4365
4366 params = 2; /* level */
4367 pSMB->TotalDataCount = 0;
4368 pSMB->DataCount = 0;
4369 pSMB->DataOffset = 0;
4370 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004371 /* BB find exact max SMB PDU from sess structure BB */
4372 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 pSMB->MaxSetupCount = 0;
4374 pSMB->Reserved = 0;
4375 pSMB->Flags = 0;
4376 pSMB->Timeout = 0;
4377 pSMB->Reserved2 = 0;
4378 byte_count = params + 1 /* pad */ ;
4379 pSMB->ParameterCount = cpu_to_le16(params);
4380 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004381 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4382 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 pSMB->SetupCount = 1;
4384 pSMB->Reserved3 = 0;
4385 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4386 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4387 pSMB->hdr.smb_buf_length += byte_count;
4388 pSMB->ByteCount = cpu_to_le16(byte_count);
4389
4390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4391 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4392 if (rc) {
4393 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4394 } else { /* decode response */
4395 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4396
4397 if (rc || (pSMBr->ByteCount < 13)) {
4398 rc = -EIO; /* bad smb */
4399 } else {
4400 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4401 response_data =
4402 (FILE_SYSTEM_UNIX_INFO
4403 *) (((char *) &pSMBr->hdr.Protocol) +
4404 data_offset);
4405 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004406 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 }
4408 }
4409 cifs_buf_release(pSMB);
4410
4411 if (rc == -EAGAIN)
4412 goto QFSUnixRetry;
4413
4414
4415 return rc;
4416}
4417
Jeremy Allisonac670552005-06-22 17:26:35 -07004418int
Steve French45abc6e2005-06-23 13:42:03 -05004419CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004420{
4421/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4422 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4423 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4424 int rc = 0;
4425 int bytes_returned = 0;
4426 __u16 params, param_offset, offset, byte_count;
4427
4428 cFYI(1, ("In SETFSUnixInfo"));
4429SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004430 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004431 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4432 (void **) &pSMBr);
4433 if (rc)
4434 return rc;
4435
4436 params = 4; /* 2 bytes zero followed by info level. */
4437 pSMB->MaxSetupCount = 0;
4438 pSMB->Reserved = 0;
4439 pSMB->Flags = 0;
4440 pSMB->Timeout = 0;
4441 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004442 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4443 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004444 offset = param_offset + params;
4445
4446 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004447 /* BB find exact max SMB PDU from sess structure BB */
4448 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004449 pSMB->SetupCount = 1;
4450 pSMB->Reserved3 = 0;
4451 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4452 byte_count = 1 /* pad */ + params + 12;
4453
4454 pSMB->DataCount = cpu_to_le16(12);
4455 pSMB->ParameterCount = cpu_to_le16(params);
4456 pSMB->TotalDataCount = pSMB->DataCount;
4457 pSMB->TotalParameterCount = pSMB->ParameterCount;
4458 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4459 pSMB->DataOffset = cpu_to_le16(offset);
4460
4461 /* Params. */
4462 pSMB->FileNum = 0;
4463 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4464
4465 /* Data. */
4466 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4467 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4468 pSMB->ClientUnixCap = cpu_to_le64(cap);
4469
4470 pSMB->hdr.smb_buf_length += byte_count;
4471 pSMB->ByteCount = cpu_to_le16(byte_count);
4472
4473 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4474 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4475 if (rc) {
4476 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4477 } else { /* decode response */
4478 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004479 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004480 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004481 }
4482 cifs_buf_release(pSMB);
4483
4484 if (rc == -EAGAIN)
4485 goto SETFSUnixRetry;
4486
4487 return rc;
4488}
4489
4490
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491
4492int
4493CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004494 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495{
4496/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4497 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4498 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4499 FILE_SYSTEM_POSIX_INFO *response_data;
4500 int rc = 0;
4501 int bytes_returned = 0;
4502 __u16 params, byte_count;
4503
4504 cFYI(1, ("In QFSPosixInfo"));
4505QFSPosixRetry:
4506 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4507 (void **) &pSMBr);
4508 if (rc)
4509 return rc;
4510
4511 params = 2; /* level */
4512 pSMB->TotalDataCount = 0;
4513 pSMB->DataCount = 0;
4514 pSMB->DataOffset = 0;
4515 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004516 /* BB find exact max SMB PDU from sess structure BB */
4517 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 pSMB->MaxSetupCount = 0;
4519 pSMB->Reserved = 0;
4520 pSMB->Flags = 0;
4521 pSMB->Timeout = 0;
4522 pSMB->Reserved2 = 0;
4523 byte_count = params + 1 /* pad */ ;
4524 pSMB->ParameterCount = cpu_to_le16(params);
4525 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004526 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4527 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 pSMB->SetupCount = 1;
4529 pSMB->Reserved3 = 0;
4530 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4531 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4532 pSMB->hdr.smb_buf_length += byte_count;
4533 pSMB->ByteCount = cpu_to_le16(byte_count);
4534
4535 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4536 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4537 if (rc) {
4538 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4539 } else { /* decode response */
4540 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4541
4542 if (rc || (pSMBr->ByteCount < 13)) {
4543 rc = -EIO; /* bad smb */
4544 } else {
4545 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4546 response_data =
4547 (FILE_SYSTEM_POSIX_INFO
4548 *) (((char *) &pSMBr->hdr.Protocol) +
4549 data_offset);
4550 FSData->f_bsize =
4551 le32_to_cpu(response_data->BlockSize);
4552 FSData->f_blocks =
4553 le64_to_cpu(response_data->TotalBlocks);
4554 FSData->f_bfree =
4555 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004556 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 FSData->f_bavail = FSData->f_bfree;
4558 } else {
4559 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004560 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 }
Steve French790fe572007-07-07 19:25:05 +00004562 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004564 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004565 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004567 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 }
4569 }
4570 cifs_buf_release(pSMB);
4571
4572 if (rc == -EAGAIN)
4573 goto QFSPosixRetry;
4574
4575 return rc;
4576}
4577
4578
Steve French50c2f752007-07-13 00:33:32 +00004579/* We can not use write of zero bytes trick to
4580 set file size due to need for large file support. Also note that
4581 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 routine which is only needed to work around a sharing violation bug
4583 in Samba which this routine can run into */
4584
4585int
4586CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004587 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004588 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589{
4590 struct smb_com_transaction2_spi_req *pSMB = NULL;
4591 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4592 struct file_end_of_file_info *parm_data;
4593 int name_len;
4594 int rc = 0;
4595 int bytes_returned = 0;
4596 __u16 params, byte_count, data_count, param_offset, offset;
4597
4598 cFYI(1, ("In SetEOF"));
4599SetEOFRetry:
4600 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4601 (void **) &pSMBr);
4602 if (rc)
4603 return rc;
4604
4605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4606 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004607 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004608 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 name_len++; /* trailing null */
4610 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004611 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 name_len = strnlen(fileName, PATH_MAX);
4613 name_len++; /* trailing null */
4614 strncpy(pSMB->FileName, fileName, name_len);
4615 }
4616 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004617 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004619 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 pSMB->MaxSetupCount = 0;
4621 pSMB->Reserved = 0;
4622 pSMB->Flags = 0;
4623 pSMB->Timeout = 0;
4624 pSMB->Reserved2 = 0;
4625 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004626 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004628 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004629 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4630 pSMB->InformationLevel =
4631 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4632 else
4633 pSMB->InformationLevel =
4634 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4635 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4637 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004638 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 else
4640 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004641 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 }
4643
4644 parm_data =
4645 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4646 offset);
4647 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4648 pSMB->DataOffset = cpu_to_le16(offset);
4649 pSMB->SetupCount = 1;
4650 pSMB->Reserved3 = 0;
4651 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4652 byte_count = 3 /* pad */ + params + data_count;
4653 pSMB->DataCount = cpu_to_le16(data_count);
4654 pSMB->TotalDataCount = pSMB->DataCount;
4655 pSMB->ParameterCount = cpu_to_le16(params);
4656 pSMB->TotalParameterCount = pSMB->ParameterCount;
4657 pSMB->Reserved4 = 0;
4658 pSMB->hdr.smb_buf_length += byte_count;
4659 parm_data->FileSize = cpu_to_le64(size);
4660 pSMB->ByteCount = cpu_to_le16(byte_count);
4661 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4662 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004663 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665
4666 cifs_buf_release(pSMB);
4667
4668 if (rc == -EAGAIN)
4669 goto SetEOFRetry;
4670
4671 return rc;
4672}
4673
4674int
Steve French50c2f752007-07-13 00:33:32 +00004675CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004676 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677{
4678 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 char *data_offset;
4680 struct file_end_of_file_info *parm_data;
4681 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 __u16 params, param_offset, offset, byte_count, count;
4683
4684 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4685 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4687
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 if (rc)
4689 return rc;
4690
4691 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4692 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004693
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 params = 6;
4695 pSMB->MaxSetupCount = 0;
4696 pSMB->Reserved = 0;
4697 pSMB->Flags = 0;
4698 pSMB->Timeout = 0;
4699 pSMB->Reserved2 = 0;
4700 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4701 offset = param_offset + params;
4702
Steve French50c2f752007-07-13 00:33:32 +00004703 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704
4705 count = sizeof(struct file_end_of_file_info);
4706 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004707 /* BB find exact max SMB PDU from sess structure BB */
4708 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 pSMB->SetupCount = 1;
4710 pSMB->Reserved3 = 0;
4711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4712 byte_count = 3 /* pad */ + params + count;
4713 pSMB->DataCount = cpu_to_le16(count);
4714 pSMB->ParameterCount = cpu_to_le16(params);
4715 pSMB->TotalDataCount = pSMB->DataCount;
4716 pSMB->TotalParameterCount = pSMB->ParameterCount;
4717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4718 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004719 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4720 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 pSMB->DataOffset = cpu_to_le16(offset);
4722 parm_data->FileSize = cpu_to_le64(size);
4723 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004724 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4726 pSMB->InformationLevel =
4727 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4728 else
4729 pSMB->InformationLevel =
4730 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004731 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004734 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 else
4736 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004737 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 }
4739 pSMB->Reserved4 = 0;
4740 pSMB->hdr.smb_buf_length += byte_count;
4741 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004742 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 if (rc) {
4744 cFYI(1,
4745 ("Send error in SetFileInfo (SetFileSize) = %d",
4746 rc));
4747 }
4748
Steve French50c2f752007-07-13 00:33:32 +00004749 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 since file handle passed in no longer valid */
4751
4752 return rc;
4753}
4754
Steve French50c2f752007-07-13 00:33:32 +00004755/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 an open handle, rather than by pathname - this is awkward due to
4757 potential access conflicts on the open, but it is unavoidable for these
4758 old servers since the only other choice is to go from 100 nanosecond DCE
4759 time and resort to the original setpathinfo level which takes the ancient
4760 DOS time format with 2 second granularity */
4761int
Steve French50c2f752007-07-13 00:33:32 +00004762CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4763 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764{
4765 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 char *data_offset;
4767 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 __u16 params, param_offset, offset, byte_count, count;
4769
4770 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004771 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4772
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 if (rc)
4774 return rc;
4775
4776 /* At this point there is no need to override the current pid
4777 with the pid of the opener, but that could change if we someday
4778 use an existing handle (rather than opening one on the fly) */
4779 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4780 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004781
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 params = 6;
4783 pSMB->MaxSetupCount = 0;
4784 pSMB->Reserved = 0;
4785 pSMB->Flags = 0;
4786 pSMB->Timeout = 0;
4787 pSMB->Reserved2 = 0;
4788 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4789 offset = param_offset + params;
4790
Steve French50c2f752007-07-13 00:33:32 +00004791 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792
Steve French26f57362007-08-30 22:09:15 +00004793 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004795 /* BB find max SMB PDU from sess */
4796 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->SetupCount = 1;
4798 pSMB->Reserved3 = 0;
4799 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4800 byte_count = 3 /* pad */ + params + count;
4801 pSMB->DataCount = cpu_to_le16(count);
4802 pSMB->ParameterCount = cpu_to_le16(params);
4803 pSMB->TotalDataCount = pSMB->DataCount;
4804 pSMB->TotalParameterCount = pSMB->ParameterCount;
4805 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4806 pSMB->DataOffset = cpu_to_le16(offset);
4807 pSMB->Fid = fid;
4808 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4809 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4810 else
4811 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4812 pSMB->Reserved4 = 0;
4813 pSMB->hdr.smb_buf_length += byte_count;
4814 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004815 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004816 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004817 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004818 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819
Steve French50c2f752007-07-13 00:33:32 +00004820 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 since file handle passed in no longer valid */
4822
4823 return rc;
4824}
4825
4826
4827int
4828CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004829 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004830 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831{
4832 TRANSACTION2_SPI_REQ *pSMB = NULL;
4833 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4834 int name_len;
4835 int rc = 0;
4836 int bytes_returned = 0;
4837 char *data_offset;
4838 __u16 params, param_offset, offset, byte_count, count;
4839
4840 cFYI(1, ("In SetTimes"));
4841
4842SetTimesRetry:
4843 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4844 (void **) &pSMBr);
4845 if (rc)
4846 return rc;
4847
4848 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4849 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004850 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004851 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 name_len++; /* trailing null */
4853 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004854 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 name_len = strnlen(fileName, PATH_MAX);
4856 name_len++; /* trailing null */
4857 strncpy(pSMB->FileName, fileName, name_len);
4858 }
4859
4860 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004861 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004863 /* BB find max SMB PDU from sess structure BB */
4864 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 pSMB->MaxSetupCount = 0;
4866 pSMB->Reserved = 0;
4867 pSMB->Flags = 0;
4868 pSMB->Timeout = 0;
4869 pSMB->Reserved2 = 0;
4870 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004871 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 offset = param_offset + params;
4873 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4874 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4875 pSMB->DataOffset = cpu_to_le16(offset);
4876 pSMB->SetupCount = 1;
4877 pSMB->Reserved3 = 0;
4878 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4879 byte_count = 3 /* pad */ + params + count;
4880
4881 pSMB->DataCount = cpu_to_le16(count);
4882 pSMB->ParameterCount = cpu_to_le16(params);
4883 pSMB->TotalDataCount = pSMB->DataCount;
4884 pSMB->TotalParameterCount = pSMB->ParameterCount;
4885 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4886 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4887 else
4888 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4889 pSMB->Reserved4 = 0;
4890 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004891 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 pSMB->ByteCount = cpu_to_le16(byte_count);
4893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004895 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897
4898 cifs_buf_release(pSMB);
4899
4900 if (rc == -EAGAIN)
4901 goto SetTimesRetry;
4902
4903 return rc;
4904}
4905
4906/* Can not be used to set time stamps yet (due to old DOS time format) */
4907/* Can be used to set attributes */
4908#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4909 handling it anyway and NT4 was what we thought it would be needed for
4910 Do not delete it until we prove whether needed for Win9x though */
4911int
4912CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4913 __u16 dos_attrs, const struct nls_table *nls_codepage)
4914{
4915 SETATTR_REQ *pSMB = NULL;
4916 SETATTR_RSP *pSMBr = NULL;
4917 int rc = 0;
4918 int bytes_returned;
4919 int name_len;
4920
4921 cFYI(1, ("In SetAttrLegacy"));
4922
4923SetAttrLgcyRetry:
4924 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4925 (void **) &pSMBr);
4926 if (rc)
4927 return rc;
4928
4929 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4930 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004931 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 PATH_MAX, nls_codepage);
4933 name_len++; /* trailing null */
4934 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004935 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 name_len = strnlen(fileName, PATH_MAX);
4937 name_len++; /* trailing null */
4938 strncpy(pSMB->fileName, fileName, name_len);
4939 }
4940 pSMB->attr = cpu_to_le16(dos_attrs);
4941 pSMB->BufferFormat = 0x04;
4942 pSMB->hdr.smb_buf_length += name_len + 1;
4943 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004946 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948
4949 cifs_buf_release(pSMB);
4950
4951 if (rc == -EAGAIN)
4952 goto SetAttrLgcyRetry;
4953
4954 return rc;
4955}
4956#endif /* temporarily unneeded SetAttr legacy function */
4957
4958int
4959CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004960 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4961 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004962 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963{
4964 TRANSACTION2_SPI_REQ *pSMB = NULL;
4965 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4966 int name_len;
4967 int rc = 0;
4968 int bytes_returned = 0;
4969 FILE_UNIX_BASIC_INFO *data_offset;
4970 __u16 params, param_offset, offset, count, byte_count;
4971
4972 cFYI(1, ("In SetUID/GID/Mode"));
4973setPermsRetry:
4974 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4975 (void **) &pSMBr);
4976 if (rc)
4977 return rc;
4978
4979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4980 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004981 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 name_len++; /* trailing null */
4984 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004985 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 name_len = strnlen(fileName, PATH_MAX);
4987 name_len++; /* trailing null */
4988 strncpy(pSMB->FileName, fileName, name_len);
4989 }
4990
4991 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004992 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004994 /* BB find max SMB PDU from sess structure BB */
4995 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 pSMB->MaxSetupCount = 0;
4997 pSMB->Reserved = 0;
4998 pSMB->Flags = 0;
4999 pSMB->Timeout = 0;
5000 pSMB->Reserved2 = 0;
5001 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005002 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 offset = param_offset + params;
5004 data_offset =
5005 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5006 offset);
5007 memset(data_offset, 0, count);
5008 pSMB->DataOffset = cpu_to_le16(offset);
5009 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5010 pSMB->SetupCount = 1;
5011 pSMB->Reserved3 = 0;
5012 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5013 byte_count = 3 /* pad */ + params + count;
5014 pSMB->ParameterCount = cpu_to_le16(params);
5015 pSMB->DataCount = cpu_to_le16(count);
5016 pSMB->TotalParameterCount = pSMB->ParameterCount;
5017 pSMB->TotalDataCount = pSMB->DataCount;
5018 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5019 pSMB->Reserved4 = 0;
5020 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005021 /* Samba server ignores set of file size to zero due to bugs in some
5022 older clients, but we should be precise - we use SetFileSize to
5023 set file size and do not want to truncate file size to zero
5024 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005025 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005026 data_offset->EndOfFile = NO_CHANGE_64;
5027 data_offset->NumOfBytes = NO_CHANGE_64;
5028 data_offset->LastStatusChange = NO_CHANGE_64;
5029 data_offset->LastAccessTime = NO_CHANGE_64;
5030 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 data_offset->Uid = cpu_to_le64(uid);
5032 data_offset->Gid = cpu_to_le64(gid);
5033 /* better to leave device as zero when it is */
5034 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5035 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5036 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005037
Steve French790fe572007-07-07 19:25:05 +00005038 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005040 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005042 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005044 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005046 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005048 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005050 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5052
5053
5054 pSMB->ByteCount = cpu_to_le16(byte_count);
5055 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5056 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005057 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059
5060 if (pSMB)
5061 cifs_buf_release(pSMB);
5062 if (rc == -EAGAIN)
5063 goto setPermsRetry;
5064 return rc;
5065}
5066
Steve French50c2f752007-07-13 00:33:32 +00005067int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005068 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005069 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005070 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071{
5072 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005073 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5074 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005075 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 int bytes_returned;
5077
Steve French50c2f752007-07-13 00:33:32 +00005078 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005080 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 if (rc)
5082 return rc;
5083
5084 pSMB->TotalParameterCount = 0 ;
5085 pSMB->TotalDataCount = 0;
5086 pSMB->MaxParameterCount = cpu_to_le32(2);
5087 /* BB find exact data count max from sess structure BB */
5088 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005089/* BB VERIFY verify which is correct for above BB */
5090 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5091 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5092
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 pSMB->MaxSetupCount = 4;
5094 pSMB->Reserved = 0;
5095 pSMB->ParameterOffset = 0;
5096 pSMB->DataCount = 0;
5097 pSMB->DataOffset = 0;
5098 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5099 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5100 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005101 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5103 pSMB->Reserved2 = 0;
5104 pSMB->CompletionFilter = cpu_to_le32(filter);
5105 pSMB->Fid = netfid; /* file handle always le */
5106 pSMB->ByteCount = 0;
5107
5108 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005109 (struct smb_hdr *)pSMBr, &bytes_returned,
5110 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 if (rc) {
5112 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005113 } else {
5114 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005115 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005116 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005117 sizeof(struct dir_notify_req),
5118 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005119 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005120 dnotify_req->Pid = pSMB->hdr.Pid;
5121 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5122 dnotify_req->Mid = pSMB->hdr.Mid;
5123 dnotify_req->Tid = pSMB->hdr.Tid;
5124 dnotify_req->Uid = pSMB->hdr.Uid;
5125 dnotify_req->netfid = netfid;
5126 dnotify_req->pfile = pfile;
5127 dnotify_req->filter = filter;
5128 dnotify_req->multishot = multishot;
5129 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005130 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005131 &GlobalDnotifyReqList);
5132 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005133 } else
Steve French47c786e2005-10-11 20:03:18 -07005134 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 }
5136 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005137 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138}
5139#ifdef CONFIG_CIFS_XATTR
5140ssize_t
5141CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5142 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005143 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005144 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145{
5146 /* BB assumes one setup word */
5147 TRANSACTION2_QPI_REQ *pSMB = NULL;
5148 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5149 int rc = 0;
5150 int bytes_returned;
5151 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005152 struct fea *temp_fea;
5153 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 __u16 params, byte_count;
5155
5156 cFYI(1, ("In Query All EAs path %s", searchName));
5157QAllEAsRetry:
5158 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5159 (void **) &pSMBr);
5160 if (rc)
5161 return rc;
5162
5163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5164 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005165 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005166 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 name_len++; /* trailing null */
5168 name_len *= 2;
5169 } else { /* BB improve the check for buffer overruns BB */
5170 name_len = strnlen(searchName, PATH_MAX);
5171 name_len++; /* trailing null */
5172 strncpy(pSMB->FileName, searchName, name_len);
5173 }
5174
Steve French50c2f752007-07-13 00:33:32 +00005175 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 pSMB->TotalDataCount = 0;
5177 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005178 /* BB find exact max SMB PDU from sess structure BB */
5179 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 pSMB->MaxSetupCount = 0;
5181 pSMB->Reserved = 0;
5182 pSMB->Flags = 0;
5183 pSMB->Timeout = 0;
5184 pSMB->Reserved2 = 0;
5185 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005186 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 pSMB->DataCount = 0;
5188 pSMB->DataOffset = 0;
5189 pSMB->SetupCount = 1;
5190 pSMB->Reserved3 = 0;
5191 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5192 byte_count = params + 1 /* pad */ ;
5193 pSMB->TotalParameterCount = cpu_to_le16(params);
5194 pSMB->ParameterCount = pSMB->TotalParameterCount;
5195 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5196 pSMB->Reserved4 = 0;
5197 pSMB->hdr.smb_buf_length += byte_count;
5198 pSMB->ByteCount = cpu_to_le16(byte_count);
5199
5200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5202 if (rc) {
5203 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5204 } else { /* decode response */
5205 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5206
5207 /* BB also check enough total bytes returned */
5208 /* BB we need to improve the validity checking
5209 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005210 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 rc = -EIO; /* bad smb */
5212 /* else if (pFindData){
5213 memcpy((char *) pFindData,
5214 (char *) &pSMBr->hdr.Protocol +
5215 data_offset, kl);
5216 }*/ else {
5217 /* check that length of list is not more than bcc */
5218 /* check that each entry does not go beyond length
5219 of list */
5220 /* check that each element of each entry does not
5221 go beyond end of list */
5222 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005223 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 rc = 0;
5225 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005226 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 ea_response_data = (struct fealist *)
5228 (((char *) &pSMBr->hdr.Protocol) +
5229 data_offset);
5230 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005231 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005232 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005234 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 } else {
5236 /* account for ea list len */
5237 name_len -= 4;
5238 temp_fea = ea_response_data->list;
5239 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005240 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 __u16 value_len;
5242 name_len -= 4;
5243 temp_ptr += 4;
5244 rc += temp_fea->name_len;
5245 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005246 rc = rc + 5 + 1;
5247 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005248 memcpy(EAData, "user.", 5);
5249 EAData += 5;
5250 memcpy(EAData, temp_ptr,
5251 temp_fea->name_len);
5252 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 /* null terminate name */
5254 *EAData = 0;
5255 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005256 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 /* skip copy - calc size only */
5258 } else {
5259 /* stop before overrun buffer */
5260 rc = -ERANGE;
5261 break;
5262 }
5263 name_len -= temp_fea->name_len;
5264 temp_ptr += temp_fea->name_len;
5265 /* account for trailing null */
5266 name_len--;
5267 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005268 value_len =
5269 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 name_len -= value_len;
5271 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005272 /* BB check that temp_ptr is still
5273 within the SMB BB*/
5274
5275 /* no trailing null to account for
5276 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 /* go on to next EA */
5278 temp_fea = (struct fea *)temp_ptr;
5279 }
5280 }
5281 }
5282 }
5283 if (pSMB)
5284 cifs_buf_release(pSMB);
5285 if (rc == -EAGAIN)
5286 goto QAllEAsRetry;
5287
5288 return (ssize_t)rc;
5289}
5290
Steve French50c2f752007-07-13 00:33:32 +00005291ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5292 const unsigned char *searchName, const unsigned char *ea_name,
5293 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005294 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295{
5296 TRANSACTION2_QPI_REQ *pSMB = NULL;
5297 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5298 int rc = 0;
5299 int bytes_returned;
5300 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005301 struct fea *temp_fea;
5302 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 __u16 params, byte_count;
5304
5305 cFYI(1, ("In Query EA path %s", searchName));
5306QEARetry:
5307 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5308 (void **) &pSMBr);
5309 if (rc)
5310 return rc;
5311
5312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5313 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005314 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005315 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 name_len++; /* trailing null */
5317 name_len *= 2;
5318 } else { /* BB improve the check for buffer overruns BB */
5319 name_len = strnlen(searchName, PATH_MAX);
5320 name_len++; /* trailing null */
5321 strncpy(pSMB->FileName, searchName, name_len);
5322 }
5323
Steve French50c2f752007-07-13 00:33:32 +00005324 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 pSMB->TotalDataCount = 0;
5326 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005327 /* BB find exact max SMB PDU from sess structure BB */
5328 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 pSMB->MaxSetupCount = 0;
5330 pSMB->Reserved = 0;
5331 pSMB->Flags = 0;
5332 pSMB->Timeout = 0;
5333 pSMB->Reserved2 = 0;
5334 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005335 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 pSMB->DataCount = 0;
5337 pSMB->DataOffset = 0;
5338 pSMB->SetupCount = 1;
5339 pSMB->Reserved3 = 0;
5340 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5341 byte_count = params + 1 /* pad */ ;
5342 pSMB->TotalParameterCount = cpu_to_le16(params);
5343 pSMB->ParameterCount = pSMB->TotalParameterCount;
5344 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5345 pSMB->Reserved4 = 0;
5346 pSMB->hdr.smb_buf_length += byte_count;
5347 pSMB->ByteCount = cpu_to_le16(byte_count);
5348
5349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5351 if (rc) {
5352 cFYI(1, ("Send error in Query EA = %d", rc));
5353 } else { /* decode response */
5354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5355
5356 /* BB also check enough total bytes returned */
5357 /* BB we need to improve the validity checking
5358 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005359 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 rc = -EIO; /* bad smb */
5361 /* else if (pFindData){
5362 memcpy((char *) pFindData,
5363 (char *) &pSMBr->hdr.Protocol +
5364 data_offset, kl);
5365 }*/ else {
5366 /* check that length of list is not more than bcc */
5367 /* check that each entry does not go beyond length
5368 of list */
5369 /* check that each element of each entry does not
5370 go beyond end of list */
5371 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005372 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 rc = -ENODATA;
5374 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005375 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 ea_response_data = (struct fealist *)
5377 (((char *) &pSMBr->hdr.Protocol) +
5378 data_offset);
5379 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005380 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005381 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005383 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 } else {
5385 /* account for ea list len */
5386 name_len -= 4;
5387 temp_fea = ea_response_data->list;
5388 temp_ptr = (char *)temp_fea;
5389 /* loop through checking if we have a matching
5390 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005391 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 __u16 value_len;
5393 name_len -= 4;
5394 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005395 value_len =
5396 le16_to_cpu(temp_fea->value_len);
5397 /* BB validate that value_len falls within SMB,
5398 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005399 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 temp_fea->name_len) == 0) {
5401 /* found a match */
5402 rc = value_len;
5403 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005404 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 memcpy(ea_value,
5406 temp_fea->name+temp_fea->name_len+1,
5407 rc);
Steve French50c2f752007-07-13 00:33:32 +00005408 /* ea values, unlike ea
5409 names, are not null
5410 terminated */
Steve French790fe572007-07-07 19:25:05 +00005411 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 /* skip copy - calc size only */
5413 } else {
Steve French50c2f752007-07-13 00:33:32 +00005414 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 rc = -ERANGE;
5416 }
5417 break;
5418 }
5419 name_len -= temp_fea->name_len;
5420 temp_ptr += temp_fea->name_len;
5421 /* account for trailing null */
5422 name_len--;
5423 temp_ptr++;
5424 name_len -= value_len;
5425 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005426 /* No trailing null to account for in
5427 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 temp_fea = (struct fea *)temp_ptr;
5429 }
Steve French50c2f752007-07-13 00:33:32 +00005430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 }
5432 }
5433 if (pSMB)
5434 cifs_buf_release(pSMB);
5435 if (rc == -EAGAIN)
5436 goto QEARetry;
5437
5438 return (ssize_t)rc;
5439}
5440
5441int
5442CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005443 const char *ea_name, const void *ea_value,
5444 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5445 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446{
5447 struct smb_com_transaction2_spi_req *pSMB = NULL;
5448 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5449 struct fealist *parm_data;
5450 int name_len;
5451 int rc = 0;
5452 int bytes_returned = 0;
5453 __u16 params, param_offset, byte_count, offset, count;
5454
5455 cFYI(1, ("In SetEA"));
5456SetEARetry:
5457 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5458 (void **) &pSMBr);
5459 if (rc)
5460 return rc;
5461
5462 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5463 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005464 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005465 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 name_len++; /* trailing null */
5467 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005468 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 name_len = strnlen(fileName, PATH_MAX);
5470 name_len++; /* trailing null */
5471 strncpy(pSMB->FileName, fileName, name_len);
5472 }
5473
5474 params = 6 + name_len;
5475
5476 /* done calculating parms using name_len of file name,
5477 now use name_len to calculate length of ea name
5478 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005479 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 name_len = 0;
5481 else
Steve French50c2f752007-07-13 00:33:32 +00005482 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005484 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005486 /* BB find max SMB PDU from sess */
5487 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 pSMB->MaxSetupCount = 0;
5489 pSMB->Reserved = 0;
5490 pSMB->Flags = 0;
5491 pSMB->Timeout = 0;
5492 pSMB->Reserved2 = 0;
5493 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005494 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 offset = param_offset + params;
5496 pSMB->InformationLevel =
5497 cpu_to_le16(SMB_SET_FILE_EA);
5498
5499 parm_data =
5500 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5501 offset);
5502 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5503 pSMB->DataOffset = cpu_to_le16(offset);
5504 pSMB->SetupCount = 1;
5505 pSMB->Reserved3 = 0;
5506 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5507 byte_count = 3 /* pad */ + params + count;
5508 pSMB->DataCount = cpu_to_le16(count);
5509 parm_data->list_len = cpu_to_le32(count);
5510 parm_data->list[0].EA_flags = 0;
5511 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005512 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005514 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005515 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 parm_data->list[0].name[name_len] = 0;
5517 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5518 /* caller ensures that ea_value_len is less than 64K but
5519 we need to ensure that it fits within the smb */
5520
Steve French50c2f752007-07-13 00:33:32 +00005521 /*BB add length check to see if it would fit in
5522 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005523 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5524 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005525 memcpy(parm_data->list[0].name+name_len+1,
5526 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527
5528 pSMB->TotalDataCount = pSMB->DataCount;
5529 pSMB->ParameterCount = cpu_to_le16(params);
5530 pSMB->TotalParameterCount = pSMB->ParameterCount;
5531 pSMB->Reserved4 = 0;
5532 pSMB->hdr.smb_buf_length += byte_count;
5533 pSMB->ByteCount = cpu_to_le16(byte_count);
5534 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5535 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005536 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538
5539 cifs_buf_release(pSMB);
5540
5541 if (rc == -EAGAIN)
5542 goto SetEARetry;
5543
5544 return rc;
5545}
5546
5547#endif