blob: 4728fa982a4ed965237427b7386b838266ec497b [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)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 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 French790fe572007-07-07 19:25:05 +0000144 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000146 cFYI(1, ("gave up waiting on "
147 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700149 } /* else "hard" mount - keep retrying
150 until process is killed or server
151 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 } else /* TCP session is reestablished now */
153 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 }
Steve French50c2f752007-07-13 00:33:32 +0000155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 nls_codepage = load_nls_default();
157 /* need to prevent multiple threads trying to
158 simultaneously reconnect the same SMB session */
159 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000160 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000161 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700162 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000163 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000165 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000166 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700168 /* BB FIXME add code to check if wsize needs
169 update due to negotiated smb buffer size
170 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000171 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000173 /* tell server Unix caps we support */
174 if (tcon->ses->capabilities & CAP_UNIX)
175 reset_cifs_unix_caps(
176 0 /* no xid */,
177 tcon,
178 NULL /* we do not know sb */,
179 NULL /* no vol info */);
180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000183 /* Removed call to reopen open files here.
184 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700185 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Steve French50c2f752007-07-13 00:33:32 +0000187 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700188 know whether we can continue or not without
189 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000190 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 case SMB_COM_READ_ANDX:
192 case SMB_COM_WRITE_ANDX:
193 case SMB_COM_CLOSE:
194 case SMB_COM_FIND_CLOSE2:
195 case SMB_COM_LOCKING_ANDX: {
196 unload_nls(nls_codepage);
197 return -EAGAIN;
198 }
199 }
200 } else {
201 up(&tcon->ses->sesSem);
202 }
203 unload_nls(nls_codepage);
204
205 } else {
206 return -EIO;
207 }
208 }
Steve French790fe572007-07-07 19:25:05 +0000209 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 return rc;
211
212 *request_buf = cifs_small_buf_get();
213 if (*request_buf == NULL) {
214 /* BB should we add a retry in here if not a writepage? */
215 return -ENOMEM;
216 }
217
Steve French63135e02007-07-17 17:34:02 +0000218 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000219 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Steve French790fe572007-07-07 19:25:05 +0000221 if (tcon != NULL)
222 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000225}
226
Steve French12b3b8f2006-02-09 21:12:47 +0000227int
Steve French50c2f752007-07-13 00:33:32 +0000228small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000229 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000230{
231 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000232 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000233
Steve French5815449d2006-02-14 01:36:20 +0000234 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000235 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000236 return rc;
237
Steve French04fdabe2006-02-10 05:52:50 +0000238 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000239 buffer->Mid = GetNextMid(ses->server);
240 if (ses->capabilities & CAP_UNICODE)
241 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000242 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000243 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
244
245 /* uid, tid can stay at zero as set in header assemble */
246
Steve French50c2f752007-07-13 00:33:32 +0000247 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000248 this function is used after 1st of session setup requests */
249
250 return rc;
251}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253/* If the return code is zero, this function must fill in request_buf pointer */
254static int
255smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
256 void **request_buf /* returned */ ,
257 void **response_buf /* returned */ )
258{
259 int rc = 0;
260
261 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
262 check for tcp and smb session status done differently
263 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000264 if (tcon) {
265 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800266 /* only tree disconnect, open, and write,
267 (and ulogoff which does not have tcon)
268 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000269 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800270 (smb_command != SMB_COM_OPEN_ANDX) &&
271 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000272 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800273 smb_command));
274 return -ENODEV;
275 }
276 }
277
Steve French790fe572007-07-07 19:25:05 +0000278 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000279 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700281 /* Give Demultiplex thread up to 10 seconds to
282 reconnect, should be greater than cifs socket
283 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000284 while (tcon->ses->server->tcpStatus ==
285 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000287 (tcon->ses->server->tcpStatus ==
288 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000289 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700290 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000292 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000294 cFYI(1, ("gave up waiting on "
295 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700297 } /* else "hard" mount - keep retrying
298 until process is killed or server
299 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 } else /* TCP session is reestablished now */
301 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 nls_codepage = load_nls_default();
304 /* need to prevent multiple threads trying to
305 simultaneously reconnect the same SMB session */
306 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000307 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000308 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700309 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000310 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700312 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
313 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700315 /* BB FIXME add code to check if wsize needs
316 update due to negotiated smb buffer size
317 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000318 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000320 /* tell server Unix caps we support */
321 if (tcon->ses->capabilities & CAP_UNIX)
322 reset_cifs_unix_caps(
323 0 /* no xid */,
324 tcon,
325 NULL /* do not know sb */,
326 NULL /* no vol info */);
327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000330 /* Removed call to reopen open files here.
331 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700332 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Steve French50c2f752007-07-13 00:33:32 +0000334 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700335 know whether we can continue or not without
336 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000337 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 case SMB_COM_READ_ANDX:
339 case SMB_COM_WRITE_ANDX:
340 case SMB_COM_CLOSE:
341 case SMB_COM_FIND_CLOSE2:
342 case SMB_COM_LOCKING_ANDX: {
343 unload_nls(nls_codepage);
344 return -EAGAIN;
345 }
346 }
347 } else {
348 up(&tcon->ses->sesSem);
349 }
350 unload_nls(nls_codepage);
351
352 } else {
353 return -EIO;
354 }
355 }
Steve French790fe572007-07-07 19:25:05 +0000356 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return rc;
358
359 *request_buf = cifs_buf_get();
360 if (*request_buf == NULL) {
361 /* BB should we add a retry in here if not a writepage? */
362 return -ENOMEM;
363 }
364 /* Although the original thought was we needed the response buf for */
365 /* potential retries of smb operations it turns out we can determine */
366 /* from the mid flags when the request buffer can be resent without */
367 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000368 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000369 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000372 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
Steve French790fe572007-07-07 19:25:05 +0000374 if (tcon != NULL)
375 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return rc;
378}
379
Steve French50c2f752007-07-13 00:33:32 +0000380static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
382 int rc = -EINVAL;
383 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000384 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
386 /* check for plausible wct, bcc and t2 data and parm sizes */
387 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000388 if (pSMB->hdr.WordCount >= 10) {
389 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
391 /* check that bcc is at least as big as parms + data */
392 /* check that bcc is less than negotiated smb buffer */
393 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000394 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000395 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000396 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000398 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700399 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000401 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000402 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
404 return 0;
405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 }
407 }
408 }
Steve French50c2f752007-07-13 00:33:32 +0000409 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 sizeof(struct smb_t2_rsp) + 16);
411 return rc;
412}
413int
414CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
415{
416 NEGOTIATE_REQ *pSMB;
417 NEGOTIATE_RSP *pSMBr;
418 int rc = 0;
419 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000420 int i;
Steve French50c2f752007-07-13 00:33:32 +0000421 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000423 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100424 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Steve French790fe572007-07-07 19:25:05 +0000426 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 server = ses->server;
428 else {
429 rc = -EIO;
430 return rc;
431 }
432 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
433 (void **) &pSMB, (void **) &pSMBr);
434 if (rc)
435 return rc;
Steve French750d1152006-06-27 06:28:30 +0000436
437 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000438 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000439 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000440 else /* if override flags set only sign/seal OR them with global auth */
441 secFlags = extended_security | ses->overrideSecFlg;
442
Steve French762e5ab2007-06-28 18:41:42 +0000443 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000444
Steve French1982c342005-08-17 12:38:22 -0700445 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000446 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000447
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000448 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000449 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000450 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
451 cFYI(1, ("Kerberos only mechanism, enable extended security"));
452 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
453 }
Steve French50c2f752007-07-13 00:33:32 +0000454
Steve French39798772006-05-31 22:40:51 +0000455 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000456 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000457 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
458 count += strlen(protocols[i].name) + 1;
459 /* null at end of source and target buffers anyway */
460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 pSMB->hdr.smb_buf_length += count;
462 pSMB->ByteCount = cpu_to_le16(count);
463
464 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000466 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000467 goto neg_err_exit;
468
Al Viro733f99a2006-10-14 16:48:26 +0100469 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000470 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000471 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000472 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000473 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000474 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000475 could not negotiate a common dialect */
476 rc = -EOPNOTSUPP;
477 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000478#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000479 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100480 && ((dialect == LANMAN_PROT)
481 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000482 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000483 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000484
Steve French790fe572007-07-07 19:25:05 +0000485 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000486 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000487 server->secType = LANMAN;
488 else {
489 cERROR(1, ("mount failed weak security disabled"
490 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000491 rc = -EOPNOTSUPP;
492 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000493 }
Steve French254e55e2006-06-04 05:53:15 +0000494 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
495 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
496 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000497 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000498 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
499 /* even though we do not use raw we might as well set this
500 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000501 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000502 server->maxRw = 0xFF00;
503 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
504 } else {
505 server->maxRw = 0;/* we do not need to use raw anyway */
506 server->capabilities = CAP_MPX_MODE;
507 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000508 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000509 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000510 /* OS/2 often does not set timezone therefore
511 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000512 * Could deviate slightly from the right zone.
513 * Smallest defined timezone difference is 15 minutes
514 * (i.e. Nepal). Rounding up/down is done to match
515 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000516 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000517 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000518 struct timespec ts, utc;
519 utc = CURRENT_TIME;
520 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
521 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000522 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
523 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000524 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000525 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000526 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000527 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000528 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000529 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000530 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000531 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000532 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000533 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000534 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000535 server->timeAdj = (int)tmp;
536 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000537 }
Steve French790fe572007-07-07 19:25:05 +0000538 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000539
Steve French39798772006-05-31 22:40:51 +0000540
Steve French254e55e2006-06-04 05:53:15 +0000541 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000542 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000543
Steve French50c2f752007-07-13 00:33:32 +0000544 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000545 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000546 memcpy(server->cryptKey, rsp->EncryptionKey,
547 CIFS_CRYPTO_KEY_SIZE);
548 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
549 rc = -EIO; /* need cryptkey unless plain text */
550 goto neg_err_exit;
551 }
Steve French39798772006-05-31 22:40:51 +0000552
Steve French790fe572007-07-07 19:25:05 +0000553 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000554 /* we will not end up setting signing flags - as no signing
555 was in LANMAN and server did not return the flags on */
556 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000557#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000558 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000559 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000560 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000561 rc = -EOPNOTSUPP;
562#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000563 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000564 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000565 /* unknown wct */
566 rc = -EOPNOTSUPP;
567 goto neg_err_exit;
568 }
569 /* else wct == 17 NTLM */
570 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000571 if ((server->secMode & SECMODE_USER) == 0)
572 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000573
Steve French790fe572007-07-07 19:25:05 +0000574 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000575#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000576 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000577#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000578 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000579 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000580
Steve French790fe572007-07-07 19:25:05 +0000581 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000582 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000583 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000584 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000585 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000586 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000587 else if (secFlags & CIFSSEC_MAY_KRB5)
588 server->secType = Kerberos;
589 else if (secFlags & CIFSSEC_MAY_LANMAN)
590 server->secType = LANMAN;
591/* #ifdef CONFIG_CIFS_EXPERIMENTAL
592 else if (secFlags & CIFSSEC_MAY_PLNTXT)
593 server->secType = ??
594#endif */
595 else {
596 rc = -EOPNOTSUPP;
597 cERROR(1, ("Invalid security type"));
598 goto neg_err_exit;
599 }
600 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000601
Steve French254e55e2006-06-04 05:53:15 +0000602 /* one byte, so no need to convert this or EncryptionKeyLen from
603 little endian */
604 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
605 /* probably no need to store and check maxvcs */
606 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000608 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000609 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000610 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
611 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000612 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
613 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000614 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
615 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
616 CIFS_CRYPTO_KEY_SIZE);
617 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
618 && (pSMBr->EncryptionKeyLength == 0)) {
619 /* decode security blob */
620 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
621 rc = -EIO; /* no crypt key only if plain text pwd */
622 goto neg_err_exit;
623 }
624
625 /* BB might be helpful to save off the domain of server here */
626
Steve French50c2f752007-07-13 00:33:32 +0000627 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000628 (server->capabilities & CAP_EXTENDED_SECURITY)) {
629 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000630 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000632 goto neg_err_exit;
633 }
634
635 if (server->socketUseCount.counter > 1) {
636 if (memcmp(server->server_GUID,
637 pSMBr->u.extended_response.
638 GUID, 16) != 0) {
639 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000640 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000641 pSMBr->u.extended_response.GUID,
642 16);
643 }
644 } else
645 memcpy(server->server_GUID,
646 pSMBr->u.extended_response.GUID, 16);
647
648 if (count == 16) {
649 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000650 } else {
651 rc = decode_negTokenInit(pSMBr->u.extended_response.
652 SecurityBlob,
653 count - 16,
654 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000655 if (rc == 1) {
Jeff Laytone5459372007-11-03 05:11:06 +0000656 rc = 0;
Steve French254e55e2006-06-04 05:53:15 +0000657 } else {
658 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
Steve French254e55e2006-06-04 05:53:15 +0000661 } else
662 server->capabilities &= ~CAP_EXTENDED_SECURITY;
663
Steve French6344a422006-06-12 04:18:35 +0000664#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000665signing_check:
Steve French6344a422006-06-12 04:18:35 +0000666#endif
Steve French762e5ab2007-06-28 18:41:42 +0000667 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
668 /* MUST_SIGN already includes the MAY_SIGN FLAG
669 so if this is zero it means that signing is disabled */
670 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000671 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000672 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000673 "packet signing to be enabled in "
674 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000675 rc = -EOPNOTSUPP;
676 }
Steve French50c2f752007-07-13 00:33:32 +0000677 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000678 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000679 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
680 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000681 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000682 if ((server->secMode &
683 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
684 cERROR(1,
685 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000686 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000687 } else
688 server->secMode |= SECMODE_SIGN_REQUIRED;
689 } else {
690 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000691 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000692 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000693 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Steve French50c2f752007-07-13 00:33:32 +0000695
696neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700697 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000698
Steve French790fe572007-07-07 19:25:05 +0000699 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return rc;
701}
702
703int
704CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
705{
706 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 cFYI(1, ("In tree disconnect"));
710 /*
711 * If last user of the connection and
712 * connection alive - disconnect it
713 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000714 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 * to be freed and kernel thread woken up).
716 */
717 if (tcon)
718 down(&tcon->tconSem);
719 else
720 return -EIO;
721
722 atomic_dec(&tcon->useCount);
723 if (atomic_read(&tcon->useCount) > 0) {
724 up(&tcon->tconSem);
725 return -EBUSY;
726 }
727
Steve French50c2f752007-07-13 00:33:32 +0000728 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000730 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000732 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734
Steve French790fe572007-07-07 19:25:05 +0000735 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 up(&tcon->tconSem);
737 return -EIO;
738 }
Steve French50c2f752007-07-13 00:33:32 +0000739 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700740 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (rc) {
742 up(&tcon->tconSem);
743 return rc;
Steve Frenchcd634992005-04-28 22:41:10 -0700744 }
Steve French133672e2007-11-13 22:41:37 +0000745
746 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700748 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 up(&tcon->tconSem);
751
Steve French50c2f752007-07-13 00:33:32 +0000752 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 closed on server already e.g. due to tcp session crashing */
754 if (rc == -EAGAIN)
755 rc = 0;
756
757 return rc;
758}
759
760int
761CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
762{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 LOGOFF_ANDX_REQ *pSMB;
764 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 cFYI(1, ("In SMBLogoff for session disconnect"));
767 if (ses)
768 down(&ses->sesSem);
769 else
770 return -EIO;
771
772 atomic_dec(&ses->inUse);
773 if (atomic_read(&ses->inUse) > 0) {
774 up(&ses->sesSem);
775 return -EBUSY;
776 }
777 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
778 if (rc) {
779 up(&ses->sesSem);
780 return rc;
781 }
782
Steve French790fe572007-07-07 19:25:05 +0000783 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700784 pSMB->hdr.Mid = GetNextMid(ses->server);
785
Steve French790fe572007-07-07 19:25:05 +0000786 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
788 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
789 }
790
791 pSMB->hdr.Uid = ses->Suid;
792
793 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000794 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (ses->server) {
796 atomic_dec(&ses->server->socketUseCount);
797 if (atomic_read(&ses->server->socketUseCount) == 0) {
798 spin_lock(&GlobalMid_Lock);
799 ses->server->tcpStatus = CifsExiting;
800 spin_unlock(&GlobalMid_Lock);
801 rc = -ESHUTDOWN;
802 }
803 }
Steve Frencha59c6582005-08-17 12:12:19 -0700804 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
806 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000807 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 error */
809 if (rc == -EAGAIN)
810 rc = 0;
811 return rc;
812}
813
814int
Steve French2d785a52007-07-15 01:48:57 +0000815CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
816 __u16 type, const struct nls_table *nls_codepage, int remap)
817{
818 TRANSACTION2_SPI_REQ *pSMB = NULL;
819 TRANSACTION2_SPI_RSP *pSMBr = NULL;
820 struct unlink_psx_rq *pRqD;
821 int name_len;
822 int rc = 0;
823 int bytes_returned = 0;
824 __u16 params, param_offset, offset, byte_count;
825
826 cFYI(1, ("In POSIX delete"));
827PsxDelete:
828 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
829 (void **) &pSMBr);
830 if (rc)
831 return rc;
832
833 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
834 name_len =
835 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
836 PATH_MAX, nls_codepage, remap);
837 name_len++; /* trailing null */
838 name_len *= 2;
839 } else { /* BB add path length overrun check */
840 name_len = strnlen(fileName, PATH_MAX);
841 name_len++; /* trailing null */
842 strncpy(pSMB->FileName, fileName, name_len);
843 }
844
845 params = 6 + name_len;
846 pSMB->MaxParameterCount = cpu_to_le16(2);
847 pSMB->MaxDataCount = 0; /* BB double check this with jra */
848 pSMB->MaxSetupCount = 0;
849 pSMB->Reserved = 0;
850 pSMB->Flags = 0;
851 pSMB->Timeout = 0;
852 pSMB->Reserved2 = 0;
853 param_offset = offsetof(struct smb_com_transaction2_spi_req,
854 InformationLevel) - 4;
855 offset = param_offset + params;
856
857 /* Setup pointer to Request Data (inode type) */
858 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
859 pRqD->type = cpu_to_le16(type);
860 pSMB->ParameterOffset = cpu_to_le16(param_offset);
861 pSMB->DataOffset = cpu_to_le16(offset);
862 pSMB->SetupCount = 1;
863 pSMB->Reserved3 = 0;
864 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
865 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
866
867 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
868 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
869 pSMB->ParameterCount = cpu_to_le16(params);
870 pSMB->TotalParameterCount = pSMB->ParameterCount;
871 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
872 pSMB->Reserved4 = 0;
873 pSMB->hdr.smb_buf_length += byte_count;
874 pSMB->ByteCount = cpu_to_le16(byte_count);
875 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
876 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000877 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000878 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000879 cifs_buf_release(pSMB);
880
881 cifs_stats_inc(&tcon->num_deletes);
882
883 if (rc == -EAGAIN)
884 goto PsxDelete;
885
886 return rc;
887}
888
889int
Steve French737b7582005-04-28 22:41:06 -0700890CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
891 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892{
893 DELETE_FILE_REQ *pSMB = NULL;
894 DELETE_FILE_RSP *pSMBr = NULL;
895 int rc = 0;
896 int bytes_returned;
897 int name_len;
898
899DelFileRetry:
900 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
901 (void **) &pSMBr);
902 if (rc)
903 return rc;
904
905 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
906 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000907 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700908 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 name_len++; /* trailing null */
910 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700911 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 name_len = strnlen(fileName, PATH_MAX);
913 name_len++; /* trailing null */
914 strncpy(pSMB->fileName, fileName, name_len);
915 }
916 pSMB->SearchAttributes =
917 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
918 pSMB->BufferFormat = 0x04;
919 pSMB->hdr.smb_buf_length += name_len + 1;
920 pSMB->ByteCount = cpu_to_le16(name_len + 1);
921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700923 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000924 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927 cifs_buf_release(pSMB);
928 if (rc == -EAGAIN)
929 goto DelFileRetry;
930
931 return rc;
932}
933
934int
Steve French50c2f752007-07-13 00:33:32 +0000935CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700936 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 DELETE_DIRECTORY_REQ *pSMB = NULL;
939 DELETE_DIRECTORY_RSP *pSMBr = NULL;
940 int rc = 0;
941 int bytes_returned;
942 int name_len;
943
944 cFYI(1, ("In CIFSSMBRmDir"));
945RmDirRetry:
946 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
947 (void **) &pSMBr);
948 if (rc)
949 return rc;
950
951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700952 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
953 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 name_len++; /* trailing null */
955 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700956 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 name_len = strnlen(dirName, PATH_MAX);
958 name_len++; /* trailing null */
959 strncpy(pSMB->DirName, dirName, name_len);
960 }
961
962 pSMB->BufferFormat = 0x04;
963 pSMB->hdr.smb_buf_length += name_len + 1;
964 pSMB->ByteCount = cpu_to_le16(name_len + 1);
965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700967 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000968 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
971 cifs_buf_release(pSMB);
972 if (rc == -EAGAIN)
973 goto RmDirRetry;
974 return rc;
975}
976
977int
978CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700979 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980{
981 int rc = 0;
982 CREATE_DIRECTORY_REQ *pSMB = NULL;
983 CREATE_DIRECTORY_RSP *pSMBr = NULL;
984 int bytes_returned;
985 int name_len;
986
987 cFYI(1, ("In CIFSSMBMkDir"));
988MkDirRetry:
989 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
990 (void **) &pSMBr);
991 if (rc)
992 return rc;
993
994 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000995 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700996 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 name_len++; /* trailing null */
998 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700999 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 name_len = strnlen(name, PATH_MAX);
1001 name_len++; /* trailing null */
1002 strncpy(pSMB->DirName, name, name_len);
1003 }
1004
1005 pSMB->BufferFormat = 0x04;
1006 pSMB->hdr.smb_buf_length += name_len + 1;
1007 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001010 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001011 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07001013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 cifs_buf_release(pSMB);
1015 if (rc == -EAGAIN)
1016 goto MkDirRetry;
1017 return rc;
1018}
1019
Steve French2dd29d32007-04-23 22:07:35 +00001020int
1021CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001022 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001023 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001024 const struct nls_table *nls_codepage, int remap)
1025{
1026 TRANSACTION2_SPI_REQ *pSMB = NULL;
1027 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1028 int name_len;
1029 int rc = 0;
1030 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001031 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001032 OPEN_PSX_REQ *pdata;
1033 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001034
1035 cFYI(1, ("In POSIX Create"));
1036PsxCreat:
1037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1038 (void **) &pSMBr);
1039 if (rc)
1040 return rc;
1041
1042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1043 name_len =
1044 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1045 PATH_MAX, nls_codepage, remap);
1046 name_len++; /* trailing null */
1047 name_len *= 2;
1048 } else { /* BB improve the check for buffer overruns BB */
1049 name_len = strnlen(name, PATH_MAX);
1050 name_len++; /* trailing null */
1051 strncpy(pSMB->FileName, name, name_len);
1052 }
1053
1054 params = 6 + name_len;
1055 count = sizeof(OPEN_PSX_REQ);
1056 pSMB->MaxParameterCount = cpu_to_le16(2);
1057 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1058 pSMB->MaxSetupCount = 0;
1059 pSMB->Reserved = 0;
1060 pSMB->Flags = 0;
1061 pSMB->Timeout = 0;
1062 pSMB->Reserved2 = 0;
1063 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001064 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001065 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001066 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001067 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001068 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001069 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001070 pdata->OpenFlags = cpu_to_le32(*pOplock);
1071 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1072 pSMB->DataOffset = cpu_to_le16(offset);
1073 pSMB->SetupCount = 1;
1074 pSMB->Reserved3 = 0;
1075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1076 byte_count = 3 /* pad */ + params + count;
1077
1078 pSMB->DataCount = cpu_to_le16(count);
1079 pSMB->ParameterCount = cpu_to_le16(params);
1080 pSMB->TotalDataCount = pSMB->DataCount;
1081 pSMB->TotalParameterCount = pSMB->ParameterCount;
1082 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1083 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001084 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001085 pSMB->ByteCount = cpu_to_le16(byte_count);
1086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1088 if (rc) {
1089 cFYI(1, ("Posix create returned %d", rc));
1090 goto psx_create_err;
1091 }
1092
Steve French790fe572007-07-07 19:25:05 +00001093 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1095
1096 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1097 rc = -EIO; /* bad smb */
1098 goto psx_create_err;
1099 }
1100
1101 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001102 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001103 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001104
Steve French2dd29d32007-04-23 22:07:35 +00001105 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001106 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001107 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1108 /* Let caller know file was created so we can set the mode. */
1109 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001110 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001111 *pOplock |= CIFS_CREATE_ACTION;
1112 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001113 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1114 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001115 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001116 } else {
Steve French790fe572007-07-07 19:25:05 +00001117 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001118 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001119 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001120 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001121 goto psx_create_err;
1122 }
Steve French50c2f752007-07-13 00:33:32 +00001123 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001124 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001125 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001126 }
Steve French2dd29d32007-04-23 22:07:35 +00001127
1128psx_create_err:
1129 cifs_buf_release(pSMB);
1130
1131 cifs_stats_inc(&tcon->num_mkdirs);
1132
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1135
Steve French50c2f752007-07-13 00:33:32 +00001136 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001137}
1138
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139static __u16 convert_disposition(int disposition)
1140{
1141 __u16 ofun = 0;
1142
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
Steve French790fe572007-07-07 19:25:05 +00001163 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 ofun = SMBOPEN_OAPPEND; /* regular open */
1165 }
1166 return ofun;
1167}
1168
1169int
1170SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1171 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001172 const int access_flags, const int create_options, __u16 *netfid,
1173 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 const struct nls_table *nls_codepage, int remap)
1175{
1176 int rc = -EACCES;
1177 OPENX_REQ *pSMB = NULL;
1178 OPENX_RSP *pSMBr = NULL;
1179 int bytes_returned;
1180 int name_len;
1181 __u16 count;
1182
1183OldOpenRetry:
1184 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1185 (void **) &pSMBr);
1186 if (rc)
1187 return rc;
1188
1189 pSMB->AndXCommand = 0xFF; /* none */
1190
1191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1192 count = 1; /* account for one byte pad to word boundary */
1193 name_len =
1194 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1195 fileName, PATH_MAX, nls_codepage, remap);
1196 name_len++; /* trailing null */
1197 name_len *= 2;
1198 } else { /* BB improve check for buffer overruns BB */
1199 count = 0; /* no pad */
1200 name_len = strnlen(fileName, PATH_MAX);
1201 name_len++; /* trailing null */
1202 strncpy(pSMB->fileName, fileName, name_len);
1203 }
1204 if (*pOplock & REQ_OPLOCK)
1205 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001206 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001208
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1210 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1211 /* 0 = read
1212 1 = write
1213 2 = rw
1214 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001215 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 pSMB->Mode = cpu_to_le16(2);
1217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1221
Steve French790fe572007-07-07 19:25:05 +00001222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001224 else /* BB FIXME BB */
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226
1227 /* if ((omode & S_IWUGO) == 0)
1228 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1229 /* Above line causes problems due to vfs splitting create into two
1230 pieces - need to set mode after file created not while it is
1231 being created */
1232
1233 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001234/* pSMB->CreateOptions = cpu_to_le32(create_options &
1235 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001237
1238 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001239 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 count += name_len;
1241 pSMB->hdr.smb_buf_length += count;
1242
1243 pSMB->ByteCount = cpu_to_le16(count);
1244 /* long_op set to 1 to allow for oplock break timeouts */
1245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001246 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 cifs_stats_inc(&tcon->num_opens);
1248 if (rc) {
1249 cFYI(1, ("Error in Open = %d", rc));
1250 } else {
1251 /* BB verify if wct == 15 */
1252
1253/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1254
1255 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1256 /* Let caller know file was created so we can set the mode. */
1257 /* Do we care about the CreateAction in any other cases? */
1258 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001259/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 *pOplock |= CIFS_CREATE_ACTION; */
1261 /* BB FIXME END */
1262
Steve French790fe572007-07-07 19:25:05 +00001263 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1265 pfile_info->LastAccessTime = 0; /* BB fixme */
1266 pfile_info->LastWriteTime = 0; /* BB fixme */
1267 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001269 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001271 pfile_info->AllocationSize =
1272 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1273 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 pfile_info->NumberOfLinks = cpu_to_le32(1);
1275 }
1276 }
1277
1278 cifs_buf_release(pSMB);
1279 if (rc == -EAGAIN)
1280 goto OldOpenRetry;
1281 return rc;
1282}
1283
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284int
1285CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1286 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001287 const int access_flags, const int create_options, __u16 *netfid,
1288 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001289 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290{
1291 int rc = -EACCES;
1292 OPEN_REQ *pSMB = NULL;
1293 OPEN_RSP *pSMBr = NULL;
1294 int bytes_returned;
1295 int name_len;
1296 __u16 count;
1297
1298openRetry:
1299 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1300 (void **) &pSMBr);
1301 if (rc)
1302 return rc;
1303
1304 pSMB->AndXCommand = 0xFF; /* none */
1305
1306 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1307 count = 1; /* account for one byte pad to word boundary */
1308 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001309 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001310 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 name_len++; /* trailing null */
1312 name_len *= 2;
1313 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001314 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 count = 0; /* no pad */
1316 name_len = strnlen(fileName, PATH_MAX);
1317 name_len++; /* trailing null */
1318 pSMB->NameLength = cpu_to_le16(name_len);
1319 strncpy(pSMB->fileName, fileName, name_len);
1320 }
1321 if (*pOplock & REQ_OPLOCK)
1322 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001323 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1326 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001327 /* set file as system file if special file such
1328 as fifo and server expecting SFU style and
1329 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001330 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001331 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1332 else
1333 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 /* XP does not handle ATTR_POSIX_SEMANTICS */
1335 /* but it helps speed up case sensitive checks for other
1336 servers such as Samba */
1337 if (tcon->ses->capabilities & CAP_UNIX)
1338 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1339
1340 /* if ((omode & S_IWUGO) == 0)
1341 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1342 /* Above line causes problems due to vfs splitting create into two
1343 pieces - need to set mode after file created not while it is
1344 being created */
1345 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1346 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001347 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001348 /* BB Expirement with various impersonation levels and verify */
1349 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->SecurityFlags =
1351 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1352
1353 count += name_len;
1354 pSMB->hdr.smb_buf_length += count;
1355
1356 pSMB->ByteCount = cpu_to_le16(count);
1357 /* long_op set to 1 to allow for oplock break timeouts */
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001359 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001360 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (rc) {
1362 cFYI(1, ("Error in Open = %d", rc));
1363 } else {
Steve French09d1db52005-04-28 22:41:08 -07001364 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1366 /* Let caller know file was created so we can set the mode. */
1367 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001368 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001369 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001370 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001371 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 36 /* CreationTime to Attributes */);
1373 /* the file_info buf is endian converted by caller */
1374 pfile_info->AllocationSize = pSMBr->AllocationSize;
1375 pfile_info->EndOfFile = pSMBr->EndOfFile;
1376 pfile_info->NumberOfLinks = cpu_to_le32(1);
1377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 cifs_buf_release(pSMB);
1381 if (rc == -EAGAIN)
1382 goto openRetry;
1383 return rc;
1384}
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386int
Steve French50c2f752007-07-13 00:33:32 +00001387CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1388 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1389 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390{
1391 int rc = -EACCES;
1392 READ_REQ *pSMB = NULL;
1393 READ_RSP *pSMBr = NULL;
1394 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001395 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001396 int resp_buf_type = 0;
1397 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Steve French790fe572007-07-07 19:25:05 +00001399 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1400 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001401 wct = 12;
1402 else
1403 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
1405 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001406 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if (rc)
1408 return rc;
1409
1410 /* tcon and ses pointer are checked in smb_init */
1411 if (tcon->ses->server == NULL)
1412 return -ECONNABORTED;
1413
Steve Frenchec637e32005-12-12 20:53:18 -08001414 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 pSMB->Fid = netfid;
1416 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001417 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001418 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001419 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001420 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 pSMB->Remaining = 0;
1423 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1424 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001425 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001426 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1427 else {
1428 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001429 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001430 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001431 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001432 }
Steve Frenchec637e32005-12-12 20:53:18 -08001433
1434 iov[0].iov_base = (char *)pSMB;
1435 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001436 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001437 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001438 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001439 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 if (rc) {
1441 cERROR(1, ("Send error in read = %d", rc));
1442 } else {
1443 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1444 data_length = data_length << 16;
1445 data_length += le16_to_cpu(pSMBr->DataLength);
1446 *nbytes = data_length;
1447
1448 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001449 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001451 cFYI(1, ("bad length %d for count %d",
1452 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 rc = -EIO;
1454 *nbytes = 0;
1455 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001456 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001457 le16_to_cpu(pSMBr->DataOffset);
1458/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001459 cERROR(1,("Faulting on read rc = %d",rc));
1460 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001461 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001462 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001463 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 }
1465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
Steve French4b8f9302006-02-26 16:41:18 +00001467/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001468 if (*buf) {
1469 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001470 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001471 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001472 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001473 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001474 /* return buffer to caller to free */
1475 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001476 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001477 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001478 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001479 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001480 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001481
1482 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 since file handle passed in no longer valid */
1484 return rc;
1485}
1486
Steve Frenchec637e32005-12-12 20:53:18 -08001487
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488int
1489CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1490 const int netfid, const unsigned int count,
1491 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001492 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 int rc = -EACCES;
1495 WRITE_REQ *pSMB = NULL;
1496 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001497 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 __u32 bytes_sent;
1499 __u16 byte_count;
1500
1501 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001502 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001503 return -ECONNABORTED;
1504
Steve French790fe572007-07-07 19:25:05 +00001505 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001506 wct = 14;
1507 else
1508 wct = 12;
1509
1510 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 (void **) &pSMBr);
1512 if (rc)
1513 return rc;
1514 /* tcon and ses pointer are checked in smb_init */
1515 if (tcon->ses->server == NULL)
1516 return -ECONNABORTED;
1517
1518 pSMB->AndXCommand = 0xFF; /* none */
1519 pSMB->Fid = netfid;
1520 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001521 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001522 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001523 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001524 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 pSMB->Reserved = 0xFFFFFFFF;
1527 pSMB->WriteMode = 0;
1528 pSMB->Remaining = 0;
1529
Steve French50c2f752007-07-13 00:33:32 +00001530 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 can send more if LARGE_WRITE_X capability returned by the server and if
1532 our buffer is big enough or if we convert to iovecs on socket writes
1533 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001534 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1536 } else {
1537 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1538 & ~0xFF;
1539 }
1540
1541 if (bytes_sent > count)
1542 bytes_sent = count;
1543 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001544 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001545 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001546 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001547 else if (ubuf) {
1548 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 cifs_buf_release(pSMB);
1550 return -EFAULT;
1551 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001552 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 /* No buffer */
1554 cifs_buf_release(pSMB);
1555 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001557 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001558 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001559 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001560 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001561
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1563 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001565
Steve French790fe572007-07-07 19:25:05 +00001566 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001567 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001568 else { /* old style write has byte count 4 bytes earlier
1569 so 4 bytes pad */
1570 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001571 (struct smb_com_writex_req *)pSMB;
1572 pSMBW->ByteCount = cpu_to_le16(byte_count);
1573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1576 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001577 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 if (rc) {
1579 cFYI(1, ("Send error in write = %d", rc));
1580 *nbytes = 0;
1581 } else {
1582 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1583 *nbytes = (*nbytes) << 16;
1584 *nbytes += le16_to_cpu(pSMBr->Count);
1585 }
1586
1587 cifs_buf_release(pSMB);
1588
Steve French50c2f752007-07-13 00:33:32 +00001589 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 since file handle passed in no longer valid */
1591
1592 return rc;
1593}
1594
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001595int
1596CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001598 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1599 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600{
1601 int rc = -EACCES;
1602 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001603 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001604 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001605 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
Steve French790fe572007-07-07 19:25:05 +00001607 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001608
Steve French790fe572007-07-07 19:25:05 +00001609 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001610 wct = 14;
1611 else
1612 wct = 12;
1613 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 if (rc)
1615 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 /* tcon and ses pointer are checked in smb_init */
1617 if (tcon->ses->server == NULL)
1618 return -ECONNABORTED;
1619
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001620 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 pSMB->Fid = netfid;
1622 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001623 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001624 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001625 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001626 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 pSMB->Reserved = 0xFFFFFFFF;
1628 pSMB->WriteMode = 0;
1629 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001632 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Steve French3e844692005-10-03 13:37:24 -07001634 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1635 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001636 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001637 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001638 pSMB->hdr.smb_buf_length += count+1;
1639 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001640 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1641 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001642 pSMB->ByteCount = cpu_to_le16(count + 1);
1643 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001644 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001645 (struct smb_com_writex_req *)pSMB;
1646 pSMBW->ByteCount = cpu_to_le16(count + 5);
1647 }
Steve French3e844692005-10-03 13:37:24 -07001648 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001649 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001650 iov[0].iov_len = smb_hdr_len + 4;
1651 else /* wct == 12 pad bigger by four bytes */
1652 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001653
Steve French3e844692005-10-03 13:37:24 -07001654
Steve Frenchec637e32005-12-12 20:53:18 -08001655 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001656 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001657 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001659 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001661 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001662 /* presumably this can not happen, but best to be safe */
1663 rc = -EIO;
1664 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001665 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001666 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001667 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1668 *nbytes = (*nbytes) << 16;
1669 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
Steve French4b8f9302006-02-26 16:41:18 +00001672/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001673 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001674 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001675 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001676 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
Steve French50c2f752007-07-13 00:33:32 +00001678 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 since file handle passed in no longer valid */
1680
1681 return rc;
1682}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001683
1684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685int
1686CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1687 const __u16 smb_file_id, const __u64 len,
1688 const __u64 offset, const __u32 numUnlock,
1689 const __u32 numLock, const __u8 lockType, const int waitFlag)
1690{
1691 int rc = 0;
1692 LOCK_REQ *pSMB = NULL;
1693 LOCK_RSP *pSMBr = NULL;
1694 int bytes_returned;
1695 int timeout = 0;
1696 __u16 count;
1697
Steve French133672e2007-11-13 22:41:37 +00001698 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001699 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1700
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (rc)
1702 return rc;
1703
Steve French46810cb2005-04-28 22:41:09 -07001704 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1705
Steve French790fe572007-07-07 19:25:05 +00001706 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001707 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 pSMB->Timeout = 0;
1709 } else if (waitFlag == TRUE) {
Steve French133672e2007-11-13 22:41:37 +00001710 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1712 } else {
1713 pSMB->Timeout = 0;
1714 }
1715
1716 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1717 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1718 pSMB->LockType = lockType;
1719 pSMB->AndXCommand = 0xFF; /* none */
1720 pSMB->Fid = smb_file_id; /* netfid stays le */
1721
Steve French790fe572007-07-07 19:25:05 +00001722 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1724 /* BB where to store pid high? */
1725 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1726 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1727 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1728 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1729 count = sizeof(LOCKING_ANDX_RANGE);
1730 } else {
1731 /* oplock break */
1732 count = 0;
1733 }
1734 pSMB->hdr.smb_buf_length += count;
1735 pSMB->ByteCount = cpu_to_le16(count);
1736
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001737 if (waitFlag) {
1738 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1739 (struct smb_hdr *) pSMBr, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001740 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001741 } else {
Steve French133672e2007-11-13 22:41:37 +00001742 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1743 timeout);
1744 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001745 }
Steve Frencha4544342005-08-24 13:59:35 -07001746 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001747 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
Steve French50c2f752007-07-13 00:33:32 +00001750 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 since file handle passed in no longer valid */
1752 return rc;
1753}
1754
1755int
Steve French08547b02006-02-28 22:39:25 +00001756CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1757 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001758 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001759 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001760{
1761 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1762 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001763 struct cifs_posix_lock *parm_data;
1764 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001765 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001766 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001767 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001768 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001769 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001770
1771 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001772
Steve French790fe572007-07-07 19:25:05 +00001773 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001774 return EINVAL;
1775
Steve French08547b02006-02-28 22:39:25 +00001776 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1777
1778 if (rc)
1779 return rc;
1780
1781 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1782
Steve French50c2f752007-07-13 00:33:32 +00001783 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001784 pSMB->MaxSetupCount = 0;
1785 pSMB->Reserved = 0;
1786 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001787 pSMB->Reserved2 = 0;
1788 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1789 offset = param_offset + params;
1790
Steve French08547b02006-02-28 22:39:25 +00001791 count = sizeof(struct cifs_posix_lock);
1792 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001793 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001794 pSMB->SetupCount = 1;
1795 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001796 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001797 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1798 else
1799 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1800 byte_count = 3 /* pad */ + params + count;
1801 pSMB->DataCount = cpu_to_le16(count);
1802 pSMB->ParameterCount = cpu_to_le16(params);
1803 pSMB->TotalDataCount = pSMB->DataCount;
1804 pSMB->TotalParameterCount = pSMB->ParameterCount;
1805 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001806 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001807 (((char *) &pSMB->hdr.Protocol) + offset);
1808
1809 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001810 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001811 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001812 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001813 pSMB->Timeout = cpu_to_le32(-1);
1814 } else
1815 pSMB->Timeout = 0;
1816
Steve French08547b02006-02-28 22:39:25 +00001817 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001818 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001819 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001820
1821 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001822 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001823 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1824 pSMB->Reserved4 = 0;
1825 pSMB->hdr.smb_buf_length += byte_count;
1826 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001827 if (waitFlag) {
1828 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1829 (struct smb_hdr *) pSMBr, &bytes_returned);
1830 } else {
Steve French133672e2007-11-13 22:41:37 +00001831 iov[0].iov_base = (char *)pSMB;
1832 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1833 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1834 &resp_buf_type, timeout);
1835 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1836 not try to free it twice below on exit */
1837 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001838 }
1839
Steve French08547b02006-02-28 22:39:25 +00001840 if (rc) {
1841 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001842 } else if (get_flag) {
1843 /* lock structure can be returned on get */
1844 __u16 data_offset;
1845 __u16 data_count;
1846 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001847
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001848 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1849 rc = -EIO; /* bad smb */
1850 goto plk_err_exit;
1851 }
Steve French790fe572007-07-07 19:25:05 +00001852 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001853 rc = -EINVAL;
1854 goto plk_err_exit;
1855 }
1856 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1857 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001858 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001859 rc = -EIO;
1860 goto plk_err_exit;
1861 }
1862 parm_data = (struct cifs_posix_lock *)
1863 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001864 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001865 pLockData->fl_type = F_UNLCK;
1866 }
Steve French50c2f752007-07-13 00:33:32 +00001867
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001868plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001869 if (pSMB)
1870 cifs_small_buf_release(pSMB);
1871
Steve French133672e2007-11-13 22:41:37 +00001872 if (resp_buf_type == CIFS_SMALL_BUFFER)
1873 cifs_small_buf_release(iov[0].iov_base);
1874 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1875 cifs_buf_release(iov[0].iov_base);
1876
Steve French08547b02006-02-28 22:39:25 +00001877 /* Note: On -EAGAIN error only caller can retry on handle based calls
1878 since file handle passed in no longer valid */
1879
1880 return rc;
1881}
1882
1883
1884int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1886{
1887 int rc = 0;
1888 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 cFYI(1, ("In CIFSSMBClose"));
1890
1891/* do not retry on dead session on close */
1892 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001893 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 return 0;
1895 if (rc)
1896 return rc;
1897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001899 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001901 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001902 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001904 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 /* EINTR is expected when user ctl-c to kill app */
1906 cERROR(1, ("Send error in Close = %d", rc));
1907 }
1908 }
1909
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001911 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 rc = 0;
1913
1914 return rc;
1915}
1916
1917int
1918CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1919 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001920 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921{
1922 int rc = 0;
1923 RENAME_REQ *pSMB = NULL;
1924 RENAME_RSP *pSMBr = NULL;
1925 int bytes_returned;
1926 int name_len, name_len2;
1927 __u16 count;
1928
1929 cFYI(1, ("In CIFSSMBRename"));
1930renameRetry:
1931 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1932 (void **) &pSMBr);
1933 if (rc)
1934 return rc;
1935
1936 pSMB->BufferFormat = 0x04;
1937 pSMB->SearchAttributes =
1938 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1939 ATTR_DIRECTORY);
1940
1941 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1942 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001943 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001944 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 name_len++; /* trailing null */
1946 name_len *= 2;
1947 pSMB->OldFileName[name_len] = 0x04; /* pad */
1948 /* protocol requires ASCII signature byte on Unicode string */
1949 pSMB->OldFileName[name_len + 1] = 0x00;
1950 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001951 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001952 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1954 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001955 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 name_len = strnlen(fromName, PATH_MAX);
1957 name_len++; /* trailing null */
1958 strncpy(pSMB->OldFileName, fromName, name_len);
1959 name_len2 = strnlen(toName, PATH_MAX);
1960 name_len2++; /* trailing null */
1961 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1962 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1963 name_len2++; /* trailing null */
1964 name_len2++; /* signature byte */
1965 }
1966
1967 count = 1 /* 1st signature byte */ + name_len + name_len2;
1968 pSMB->hdr.smb_buf_length += count;
1969 pSMB->ByteCount = cpu_to_le16(count);
1970
1971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001973 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001974 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 cifs_buf_release(pSMB);
1978
1979 if (rc == -EAGAIN)
1980 goto renameRetry;
1981
1982 return rc;
1983}
1984
Steve French50c2f752007-07-13 00:33:32 +00001985int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1986 int netfid, char *target_name,
1987 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988{
1989 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1990 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001991 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 char *data_offset;
1993 char dummy_string[30];
1994 int rc = 0;
1995 int bytes_returned = 0;
1996 int len_of_str;
1997 __u16 params, param_offset, offset, count, byte_count;
1998
1999 cFYI(1, ("Rename to File by handle"));
2000 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2001 (void **) &pSMBr);
2002 if (rc)
2003 return rc;
2004
2005 params = 6;
2006 pSMB->MaxSetupCount = 0;
2007 pSMB->Reserved = 0;
2008 pSMB->Flags = 0;
2009 pSMB->Timeout = 0;
2010 pSMB->Reserved2 = 0;
2011 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2012 offset = param_offset + params;
2013
2014 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2015 rename_info = (struct set_file_rename *) data_offset;
2016 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002017 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 pSMB->SetupCount = 1;
2019 pSMB->Reserved3 = 0;
2020 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2021 byte_count = 3 /* pad */ + params;
2022 pSMB->ParameterCount = cpu_to_le16(params);
2023 pSMB->TotalParameterCount = pSMB->ParameterCount;
2024 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2025 pSMB->DataOffset = cpu_to_le16(offset);
2026 /* construct random name ".cifs_tmp<inodenum><mid>" */
2027 rename_info->overwrite = cpu_to_le32(1);
2028 rename_info->root_fid = 0;
2029 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002030 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002031 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2032 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002033 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002035 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002036 target_name, PATH_MAX, nls_codepage,
2037 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
2039 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2040 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2041 byte_count += count;
2042 pSMB->DataCount = cpu_to_le16(count);
2043 pSMB->TotalDataCount = pSMB->DataCount;
2044 pSMB->Fid = netfid;
2045 pSMB->InformationLevel =
2046 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2047 pSMB->Reserved4 = 0;
2048 pSMB->hdr.smb_buf_length += byte_count;
2049 pSMB->ByteCount = cpu_to_le16(byte_count);
2050 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002052 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002053 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002054 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002055
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 cifs_buf_release(pSMB);
2057
2058 /* Note: On -EAGAIN error only caller can retry on handle based calls
2059 since file handle passed in no longer valid */
2060
2061 return rc;
2062}
2063
2064int
Steve French50c2f752007-07-13 00:33:32 +00002065CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2066 const __u16 target_tid, const char *toName, const int flags,
2067 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068{
2069 int rc = 0;
2070 COPY_REQ *pSMB = NULL;
2071 COPY_RSP *pSMBr = NULL;
2072 int bytes_returned;
2073 int name_len, name_len2;
2074 __u16 count;
2075
2076 cFYI(1, ("In CIFSSMBCopy"));
2077copyRetry:
2078 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2079 (void **) &pSMBr);
2080 if (rc)
2081 return rc;
2082
2083 pSMB->BufferFormat = 0x04;
2084 pSMB->Tid2 = target_tid;
2085
2086 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2087
2088 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002089 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002090 fromName, PATH_MAX, nls_codepage,
2091 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 name_len++; /* trailing null */
2093 name_len *= 2;
2094 pSMB->OldFileName[name_len] = 0x04; /* pad */
2095 /* protocol requires ASCII signature byte on Unicode string */
2096 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002097 name_len2 =
2098 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002099 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2101 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002102 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 name_len = strnlen(fromName, PATH_MAX);
2104 name_len++; /* trailing null */
2105 strncpy(pSMB->OldFileName, fromName, name_len);
2106 name_len2 = strnlen(toName, PATH_MAX);
2107 name_len2++; /* trailing null */
2108 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2109 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2110 name_len2++; /* trailing null */
2111 name_len2++; /* signature byte */
2112 }
2113
2114 count = 1 /* 1st signature byte */ + name_len + name_len2;
2115 pSMB->hdr.smb_buf_length += count;
2116 pSMB->ByteCount = cpu_to_le16(count);
2117
2118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2120 if (rc) {
2121 cFYI(1, ("Send error in copy = %d with %d files copied",
2122 rc, le16_to_cpu(pSMBr->CopyCount)));
2123 }
2124 if (pSMB)
2125 cifs_buf_release(pSMB);
2126
2127 if (rc == -EAGAIN)
2128 goto copyRetry;
2129
2130 return rc;
2131}
2132
2133int
2134CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2135 const char *fromName, const char *toName,
2136 const struct nls_table *nls_codepage)
2137{
2138 TRANSACTION2_SPI_REQ *pSMB = NULL;
2139 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2140 char *data_offset;
2141 int name_len;
2142 int name_len_target;
2143 int rc = 0;
2144 int bytes_returned = 0;
2145 __u16 params, param_offset, offset, byte_count;
2146
2147 cFYI(1, ("In Symlink Unix style"));
2148createSymLinkRetry:
2149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2150 (void **) &pSMBr);
2151 if (rc)
2152 return rc;
2153
2154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2155 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002156 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 /* find define for this maxpathcomponent */
2158 , nls_codepage);
2159 name_len++; /* trailing null */
2160 name_len *= 2;
2161
Steve French50c2f752007-07-13 00:33:32 +00002162 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 name_len = strnlen(fromName, PATH_MAX);
2164 name_len++; /* trailing null */
2165 strncpy(pSMB->FileName, fromName, name_len);
2166 }
2167 params = 6 + name_len;
2168 pSMB->MaxSetupCount = 0;
2169 pSMB->Reserved = 0;
2170 pSMB->Flags = 0;
2171 pSMB->Timeout = 0;
2172 pSMB->Reserved2 = 0;
2173 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002174 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 offset = param_offset + params;
2176
2177 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2178 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2179 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002180 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 /* find define for this maxpathcomponent */
2182 , nls_codepage);
2183 name_len_target++; /* trailing null */
2184 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002185 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 name_len_target = strnlen(toName, PATH_MAX);
2187 name_len_target++; /* trailing null */
2188 strncpy(data_offset, toName, name_len_target);
2189 }
2190
2191 pSMB->MaxParameterCount = cpu_to_le16(2);
2192 /* BB find exact max on data count below from sess */
2193 pSMB->MaxDataCount = cpu_to_le16(1000);
2194 pSMB->SetupCount = 1;
2195 pSMB->Reserved3 = 0;
2196 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2197 byte_count = 3 /* pad */ + params + name_len_target;
2198 pSMB->DataCount = cpu_to_le16(name_len_target);
2199 pSMB->ParameterCount = cpu_to_le16(params);
2200 pSMB->TotalDataCount = pSMB->DataCount;
2201 pSMB->TotalParameterCount = pSMB->ParameterCount;
2202 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2203 pSMB->DataOffset = cpu_to_le16(offset);
2204 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2205 pSMB->Reserved4 = 0;
2206 pSMB->hdr.smb_buf_length += byte_count;
2207 pSMB->ByteCount = cpu_to_le16(byte_count);
2208 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2209 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002210 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002211 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002212 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
2214 if (pSMB)
2215 cifs_buf_release(pSMB);
2216
2217 if (rc == -EAGAIN)
2218 goto createSymLinkRetry;
2219
2220 return rc;
2221}
2222
2223int
2224CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2225 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002226 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227{
2228 TRANSACTION2_SPI_REQ *pSMB = NULL;
2229 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2230 char *data_offset;
2231 int name_len;
2232 int name_len_target;
2233 int rc = 0;
2234 int bytes_returned = 0;
2235 __u16 params, param_offset, offset, byte_count;
2236
2237 cFYI(1, ("In Create Hard link Unix style"));
2238createHardLinkRetry:
2239 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2240 (void **) &pSMBr);
2241 if (rc)
2242 return rc;
2243
2244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002245 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002246 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 name_len++; /* trailing null */
2248 name_len *= 2;
2249
Steve French50c2f752007-07-13 00:33:32 +00002250 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 name_len = strnlen(toName, PATH_MAX);
2252 name_len++; /* trailing null */
2253 strncpy(pSMB->FileName, toName, name_len);
2254 }
2255 params = 6 + name_len;
2256 pSMB->MaxSetupCount = 0;
2257 pSMB->Reserved = 0;
2258 pSMB->Flags = 0;
2259 pSMB->Timeout = 0;
2260 pSMB->Reserved2 = 0;
2261 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002262 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 offset = param_offset + params;
2264
2265 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2266 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2267 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002268 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002269 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 name_len_target++; /* trailing null */
2271 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002272 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 name_len_target = strnlen(fromName, PATH_MAX);
2274 name_len_target++; /* trailing null */
2275 strncpy(data_offset, fromName, name_len_target);
2276 }
2277
2278 pSMB->MaxParameterCount = cpu_to_le16(2);
2279 /* BB find exact max on data count below from sess*/
2280 pSMB->MaxDataCount = cpu_to_le16(1000);
2281 pSMB->SetupCount = 1;
2282 pSMB->Reserved3 = 0;
2283 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2284 byte_count = 3 /* pad */ + params + name_len_target;
2285 pSMB->ParameterCount = cpu_to_le16(params);
2286 pSMB->TotalParameterCount = pSMB->ParameterCount;
2287 pSMB->DataCount = cpu_to_le16(name_len_target);
2288 pSMB->TotalDataCount = pSMB->DataCount;
2289 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2290 pSMB->DataOffset = cpu_to_le16(offset);
2291 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2292 pSMB->Reserved4 = 0;
2293 pSMB->hdr.smb_buf_length += byte_count;
2294 pSMB->ByteCount = cpu_to_le16(byte_count);
2295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002297 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002298 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300
2301 cifs_buf_release(pSMB);
2302 if (rc == -EAGAIN)
2303 goto createHardLinkRetry;
2304
2305 return rc;
2306}
2307
2308int
2309CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2310 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002311 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312{
2313 int rc = 0;
2314 NT_RENAME_REQ *pSMB = NULL;
2315 RENAME_RSP *pSMBr = NULL;
2316 int bytes_returned;
2317 int name_len, name_len2;
2318 __u16 count;
2319
2320 cFYI(1, ("In CIFSCreateHardLink"));
2321winCreateHardLinkRetry:
2322
2323 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2324 (void **) &pSMBr);
2325 if (rc)
2326 return rc;
2327
2328 pSMB->SearchAttributes =
2329 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2330 ATTR_DIRECTORY);
2331 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2332 pSMB->ClusterCount = 0;
2333
2334 pSMB->BufferFormat = 0x04;
2335
2336 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2337 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002338 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002339 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 name_len++; /* trailing null */
2341 name_len *= 2;
2342 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002343 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002345 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002346 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2348 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002349 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 name_len = strnlen(fromName, PATH_MAX);
2351 name_len++; /* trailing null */
2352 strncpy(pSMB->OldFileName, fromName, name_len);
2353 name_len2 = strnlen(toName, PATH_MAX);
2354 name_len2++; /* trailing null */
2355 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2356 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2357 name_len2++; /* trailing null */
2358 name_len2++; /* signature byte */
2359 }
2360
2361 count = 1 /* string type byte */ + name_len + name_len2;
2362 pSMB->hdr.smb_buf_length += count;
2363 pSMB->ByteCount = cpu_to_le16(count);
2364
2365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2366 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002367 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002368 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002370
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 cifs_buf_release(pSMB);
2372 if (rc == -EAGAIN)
2373 goto winCreateHardLinkRetry;
2374
2375 return rc;
2376}
2377
2378int
2379CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2380 const unsigned char *searchName,
2381 char *symlinkinfo, const int buflen,
2382 const struct nls_table *nls_codepage)
2383{
2384/* SMB_QUERY_FILE_UNIX_LINK */
2385 TRANSACTION2_QPI_REQ *pSMB = NULL;
2386 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2387 int rc = 0;
2388 int bytes_returned;
2389 int name_len;
2390 __u16 params, byte_count;
2391
2392 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2393
2394querySymLinkRetry:
2395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2396 (void **) &pSMBr);
2397 if (rc)
2398 return rc;
2399
2400 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2401 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002402 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2403 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 name_len++; /* trailing null */
2405 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002406 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 name_len = strnlen(searchName, PATH_MAX);
2408 name_len++; /* trailing null */
2409 strncpy(pSMB->FileName, searchName, name_len);
2410 }
2411
2412 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2413 pSMB->TotalDataCount = 0;
2414 pSMB->MaxParameterCount = cpu_to_le16(2);
2415 /* BB find exact max data count below from sess structure BB */
2416 pSMB->MaxDataCount = cpu_to_le16(4000);
2417 pSMB->MaxSetupCount = 0;
2418 pSMB->Reserved = 0;
2419 pSMB->Flags = 0;
2420 pSMB->Timeout = 0;
2421 pSMB->Reserved2 = 0;
2422 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002423 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 pSMB->DataCount = 0;
2425 pSMB->DataOffset = 0;
2426 pSMB->SetupCount = 1;
2427 pSMB->Reserved3 = 0;
2428 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2429 byte_count = params + 1 /* pad */ ;
2430 pSMB->TotalParameterCount = cpu_to_le16(params);
2431 pSMB->ParameterCount = pSMB->TotalParameterCount;
2432 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2433 pSMB->Reserved4 = 0;
2434 pSMB->hdr.smb_buf_length += byte_count;
2435 pSMB->ByteCount = cpu_to_le16(byte_count);
2436
2437 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2438 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2439 if (rc) {
2440 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2441 } else {
2442 /* decode response */
2443
2444 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2445 if (rc || (pSMBr->ByteCount < 2))
2446 /* BB also check enough total bytes returned */
2447 rc = -EIO; /* bad smb */
2448 else {
2449 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2450 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2451
2452 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2453 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002454 &pSMBr->hdr.Protocol + data_offset),
2455 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002456 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002458 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2459 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 name_len, nls_codepage);
2461 } else {
2462 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002463 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 data_offset,
2465 min_t(const int, buflen, count));
2466 }
2467 symlinkinfo[buflen] = 0;
2468 /* just in case so calling code does not go off the end of buffer */
2469 }
2470 }
2471 cifs_buf_release(pSMB);
2472 if (rc == -EAGAIN)
2473 goto querySymLinkRetry;
2474 return rc;
2475}
2476
Parag Warudkarc9489772007-10-23 18:09:48 +00002477#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002478/* Initialize NT TRANSACT SMB into small smb request buffer.
2479 This assumes that all NT TRANSACTS that we init here have
2480 total parm and data under about 400 bytes (to fit in small cifs
2481 buffer size), which is the case so far, it easily fits. NB:
2482 Setup words themselves and ByteCount
2483 MaxSetupCount (size of returned setup area) and
2484 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002485static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002486smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002487 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002488 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002489{
2490 int rc;
2491 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002492 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002493
2494 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2495 (void **)&pSMB);
2496 if (rc)
2497 return rc;
2498 *ret_buf = (void *)pSMB;
2499 pSMB->Reserved = 0;
2500 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2501 pSMB->TotalDataCount = 0;
2502 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2503 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2504 pSMB->ParameterCount = pSMB->TotalParameterCount;
2505 pSMB->DataCount = pSMB->TotalDataCount;
2506 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2507 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2508 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2509 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2510 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2511 pSMB->SubCommand = cpu_to_le16(sub_command);
2512 return 0;
2513}
2514
2515static int
Steve French50c2f752007-07-13 00:33:32 +00002516validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002517 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002518{
Steve French50c2f752007-07-13 00:33:32 +00002519 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002520 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002521 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002522
Steve French630f3f02007-10-25 21:17:17 +00002523 *pdatalen = 0;
2524 *pparmlen = 0;
2525
Steve French790fe572007-07-07 19:25:05 +00002526 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002527 return -EINVAL;
2528
2529 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2530
2531 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002532 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002533 (char *)&pSMBr->ByteCount;
2534
Steve French0a4b92c2006-01-12 15:44:21 -08002535 data_offset = le32_to_cpu(pSMBr->DataOffset);
2536 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002537 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002538 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2539
2540 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2541 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2542
2543 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002544 if (*ppparm > end_of_smb) {
2545 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002546 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002547 } else if (parm_count + *ppparm > end_of_smb) {
2548 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002549 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002550 } else if (*ppdata > end_of_smb) {
2551 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002552 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002553 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002554 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002555 *ppdata, data_count, (data_count + *ppdata),
2556 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002557 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002558 } else if (parm_count + data_count > pSMBr->ByteCount) {
2559 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002560 return -EINVAL;
2561 }
Steve French630f3f02007-10-25 21:17:17 +00002562 *pdatalen = data_count;
2563 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002564 return 0;
2565}
Parag Warudkarc9489772007-10-23 18:09:48 +00002566#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002567
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568int
2569CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2570 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002571 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 const struct nls_table *nls_codepage)
2573{
2574 int rc = 0;
2575 int bytes_returned;
2576 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002577 struct smb_com_transaction_ioctl_req *pSMB;
2578 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
2580 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2581 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2582 (void **) &pSMBr);
2583 if (rc)
2584 return rc;
2585
2586 pSMB->TotalParameterCount = 0 ;
2587 pSMB->TotalDataCount = 0;
2588 pSMB->MaxParameterCount = cpu_to_le32(2);
2589 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002590 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2591 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 pSMB->MaxSetupCount = 4;
2593 pSMB->Reserved = 0;
2594 pSMB->ParameterOffset = 0;
2595 pSMB->DataCount = 0;
2596 pSMB->DataOffset = 0;
2597 pSMB->SetupCount = 4;
2598 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2599 pSMB->ParameterCount = pSMB->TotalParameterCount;
2600 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2601 pSMB->IsFsctl = 1; /* FSCTL */
2602 pSMB->IsRootFlag = 0;
2603 pSMB->Fid = fid; /* file handle always le */
2604 pSMB->ByteCount = 0;
2605
2606 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2607 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2608 if (rc) {
2609 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2610 } else { /* decode response */
2611 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2612 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2613 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2614 /* BB also check enough total bytes returned */
2615 rc = -EIO; /* bad smb */
2616 else {
Steve French790fe572007-07-07 19:25:05 +00002617 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002618 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002619 pSMBr->ByteCount +
2620 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
Steve French50c2f752007-07-13 00:33:32 +00002622 struct reparse_data *reparse_buf =
2623 (struct reparse_data *)
2624 ((char *)&pSMBr->hdr.Protocol
2625 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002626 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 rc = -EIO;
2628 goto qreparse_out;
2629 }
Steve French790fe572007-07-07 19:25:05 +00002630 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 reparse_buf->TargetNameOffset +
2632 reparse_buf->TargetNameLen) >
2633 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002634 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 rc = -EIO;
2636 goto qreparse_out;
2637 }
Steve French50c2f752007-07-13 00:33:32 +00002638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2640 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002641 (reparse_buf->LinkNamesBuf +
2642 reparse_buf->TargetNameOffset),
2643 min(buflen/2,
2644 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002646 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 reparse_buf->TargetNameOffset),
2648 name_len, nls_codepage);
2649 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002650 strncpy(symlinkinfo,
2651 reparse_buf->LinkNamesBuf +
2652 reparse_buf->TargetNameOffset,
2653 min_t(const int, buflen,
2654 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 }
2656 } else {
2657 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002658 cFYI(1, ("Invalid return data count on "
2659 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 }
2661 symlinkinfo[buflen] = 0; /* just in case so the caller
2662 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002663 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665 }
2666qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002667 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
2669 /* Note: On -EAGAIN error only caller can retry on handle based calls
2670 since file handle passed in no longer valid */
2671
2672 return rc;
2673}
2674
2675#ifdef CONFIG_CIFS_POSIX
2676
2677/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002678static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2679 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680{
2681 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002682 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2683 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2684 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2686
2687 return;
2688}
2689
2690/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002691static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2692 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693{
2694 int size = 0;
2695 int i;
2696 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002697 struct cifs_posix_ace *pACE;
2698 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2699 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
2701 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2702 return -EOPNOTSUPP;
2703
Steve French790fe572007-07-07 19:25:05 +00002704 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 count = le16_to_cpu(cifs_acl->access_entry_count);
2706 pACE = &cifs_acl->ace_array[0];
2707 size = sizeof(struct cifs_posix_acl);
2708 size += sizeof(struct cifs_posix_ace) * count;
2709 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002710 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002711 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2712 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 return -EINVAL;
2714 }
Steve French790fe572007-07-07 19:25:05 +00002715 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 count = le16_to_cpu(cifs_acl->access_entry_count);
2717 size = sizeof(struct cifs_posix_acl);
2718 size += sizeof(struct cifs_posix_ace) * count;
2719/* skip past access ACEs to get to default ACEs */
2720 pACE = &cifs_acl->ace_array[count];
2721 count = le16_to_cpu(cifs_acl->default_entry_count);
2722 size += sizeof(struct cifs_posix_ace) * count;
2723 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002724 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 return -EINVAL;
2726 } else {
2727 /* illegal type */
2728 return -EINVAL;
2729 }
2730
2731 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002732 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002733 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002734 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 return -ERANGE;
2736 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002737 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002738 for (i = 0; i < count ; i++) {
2739 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2740 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 }
2742 }
2743 return size;
2744}
2745
Steve French50c2f752007-07-13 00:33:32 +00002746static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2747 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748{
2749 __u16 rc = 0; /* 0 = ACL converted ok */
2750
Steve Frenchff7feac2005-11-15 16:45:16 -08002751 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2752 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002754 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 /* Probably no need to le convert -1 on any arch but can not hurt */
2756 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002757 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002758 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002759 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 return rc;
2761}
2762
2763/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002764static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2765 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766{
2767 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002768 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2769 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 int count;
2771 int i;
2772
Steve French790fe572007-07-07 19:25:05 +00002773 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return 0;
2775
2776 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002777 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002778 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002779 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002780 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002781 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002782 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 return 0;
2784 }
2785 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002786 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002787 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002788 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002789 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 else {
Steve French50c2f752007-07-13 00:33:32 +00002791 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 return 0;
2793 }
Steve French50c2f752007-07-13 00:33:32 +00002794 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2796 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002797 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 /* ACE not converted */
2799 break;
2800 }
2801 }
Steve French790fe572007-07-07 19:25:05 +00002802 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2804 rc += sizeof(struct cifs_posix_acl);
2805 /* BB add check to make sure ACL does not overflow SMB */
2806 }
2807 return rc;
2808}
2809
2810int
2811CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002812 const unsigned char *searchName,
2813 char *acl_inf, const int buflen, const int acl_type,
2814 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815{
2816/* SMB_QUERY_POSIX_ACL */
2817 TRANSACTION2_QPI_REQ *pSMB = NULL;
2818 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2819 int rc = 0;
2820 int bytes_returned;
2821 int name_len;
2822 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002823
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2825
2826queryAclRetry:
2827 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2828 (void **) &pSMBr);
2829 if (rc)
2830 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002831
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2833 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002834 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002835 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 name_len++; /* trailing null */
2837 name_len *= 2;
2838 pSMB->FileName[name_len] = 0;
2839 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002840 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 name_len = strnlen(searchName, PATH_MAX);
2842 name_len++; /* trailing null */
2843 strncpy(pSMB->FileName, searchName, name_len);
2844 }
2845
2846 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2847 pSMB->TotalDataCount = 0;
2848 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002849 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 pSMB->MaxDataCount = cpu_to_le16(4000);
2851 pSMB->MaxSetupCount = 0;
2852 pSMB->Reserved = 0;
2853 pSMB->Flags = 0;
2854 pSMB->Timeout = 0;
2855 pSMB->Reserved2 = 0;
2856 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002857 offsetof(struct smb_com_transaction2_qpi_req,
2858 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 pSMB->DataCount = 0;
2860 pSMB->DataOffset = 0;
2861 pSMB->SetupCount = 1;
2862 pSMB->Reserved3 = 0;
2863 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2864 byte_count = params + 1 /* pad */ ;
2865 pSMB->TotalParameterCount = cpu_to_le16(params);
2866 pSMB->ParameterCount = pSMB->TotalParameterCount;
2867 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2868 pSMB->Reserved4 = 0;
2869 pSMB->hdr.smb_buf_length += byte_count;
2870 pSMB->ByteCount = cpu_to_le16(byte_count);
2871
2872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002874 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 if (rc) {
2876 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2877 } else {
2878 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002879
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2881 if (rc || (pSMBr->ByteCount < 2))
2882 /* BB also check enough total bytes returned */
2883 rc = -EIO; /* bad smb */
2884 else {
2885 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2886 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2887 rc = cifs_copy_posix_acl(acl_inf,
2888 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002889 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 }
2891 }
2892 cifs_buf_release(pSMB);
2893 if (rc == -EAGAIN)
2894 goto queryAclRetry;
2895 return rc;
2896}
2897
2898int
2899CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002900 const unsigned char *fileName,
2901 const char *local_acl, const int buflen,
2902 const int acl_type,
2903 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904{
2905 struct smb_com_transaction2_spi_req *pSMB = NULL;
2906 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2907 char *parm_data;
2908 int name_len;
2909 int rc = 0;
2910 int bytes_returned = 0;
2911 __u16 params, byte_count, data_count, param_offset, offset;
2912
2913 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2914setAclRetry:
2915 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002916 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 if (rc)
2918 return rc;
2919 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2920 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002921 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002922 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 name_len++; /* trailing null */
2924 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002925 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 name_len = strnlen(fileName, PATH_MAX);
2927 name_len++; /* trailing null */
2928 strncpy(pSMB->FileName, fileName, name_len);
2929 }
2930 params = 6 + name_len;
2931 pSMB->MaxParameterCount = cpu_to_le16(2);
2932 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2933 pSMB->MaxSetupCount = 0;
2934 pSMB->Reserved = 0;
2935 pSMB->Flags = 0;
2936 pSMB->Timeout = 0;
2937 pSMB->Reserved2 = 0;
2938 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002939 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 offset = param_offset + params;
2941 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2942 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2943
2944 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002945 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
Steve French790fe572007-07-07 19:25:05 +00002947 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 rc = -EOPNOTSUPP;
2949 goto setACLerrorExit;
2950 }
2951 pSMB->DataOffset = cpu_to_le16(offset);
2952 pSMB->SetupCount = 1;
2953 pSMB->Reserved3 = 0;
2954 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2955 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2956 byte_count = 3 /* pad */ + params + data_count;
2957 pSMB->DataCount = cpu_to_le16(data_count);
2958 pSMB->TotalDataCount = pSMB->DataCount;
2959 pSMB->ParameterCount = cpu_to_le16(params);
2960 pSMB->TotalParameterCount = pSMB->ParameterCount;
2961 pSMB->Reserved4 = 0;
2962 pSMB->hdr.smb_buf_length += byte_count;
2963 pSMB->ByteCount = cpu_to_le16(byte_count);
2964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002966 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
2969setACLerrorExit:
2970 cifs_buf_release(pSMB);
2971 if (rc == -EAGAIN)
2972 goto setAclRetry;
2973 return rc;
2974}
2975
Steve Frenchf654bac2005-04-28 22:41:04 -07002976/* BB fix tabs in this function FIXME BB */
2977int
2978CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002979 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002980{
Steve French50c2f752007-07-13 00:33:32 +00002981 int rc = 0;
2982 struct smb_t2_qfi_req *pSMB = NULL;
2983 struct smb_t2_qfi_rsp *pSMBr = NULL;
2984 int bytes_returned;
2985 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002986
Steve French790fe572007-07-07 19:25:05 +00002987 cFYI(1, ("In GetExtAttr"));
2988 if (tcon == NULL)
2989 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002990
2991GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002992 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2993 (void **) &pSMBr);
2994 if (rc)
2995 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002996
Steve Frenchad7a2922008-02-07 23:25:02 +00002997 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002998 pSMB->t2.TotalDataCount = 0;
2999 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3000 /* BB find exact max data count below from sess structure BB */
3001 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3002 pSMB->t2.MaxSetupCount = 0;
3003 pSMB->t2.Reserved = 0;
3004 pSMB->t2.Flags = 0;
3005 pSMB->t2.Timeout = 0;
3006 pSMB->t2.Reserved2 = 0;
3007 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3008 Fid) - 4);
3009 pSMB->t2.DataCount = 0;
3010 pSMB->t2.DataOffset = 0;
3011 pSMB->t2.SetupCount = 1;
3012 pSMB->t2.Reserved3 = 0;
3013 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3014 byte_count = params + 1 /* pad */ ;
3015 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3016 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3017 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3018 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003019 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003020 pSMB->hdr.smb_buf_length += byte_count;
3021 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003022
Steve French790fe572007-07-07 19:25:05 +00003023 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3024 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3025 if (rc) {
3026 cFYI(1, ("error %d in GetExtAttr", rc));
3027 } else {
3028 /* decode response */
3029 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3030 if (rc || (pSMBr->ByteCount < 2))
3031 /* BB also check enough total bytes returned */
3032 /* If rc should we check for EOPNOSUPP and
3033 disable the srvino flag? or in caller? */
3034 rc = -EIO; /* bad smb */
3035 else {
3036 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3037 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3038 struct file_chattr_info *pfinfo;
3039 /* BB Do we need a cast or hash here ? */
3040 if (count != 16) {
3041 cFYI(1, ("Illegal size ret in GetExtAttr"));
3042 rc = -EIO;
3043 goto GetExtAttrOut;
3044 }
3045 pfinfo = (struct file_chattr_info *)
3046 (data_offset + (char *) &pSMBr->hdr.Protocol);
3047 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003048 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003049 }
3050 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003051GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003052 cifs_buf_release(pSMB);
3053 if (rc == -EAGAIN)
3054 goto GetExtAttrRetry;
3055 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003056}
3057
Steve Frenchf654bac2005-04-28 22:41:04 -07003058#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059
Steve French297647c2007-10-12 04:11:59 +00003060#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003061/* Get Security Descriptor (by handle) from remote server for a file or dir */
3062int
3063CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003064 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003065{
3066 int rc = 0;
3067 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003068 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003069 struct kvec iov[1];
3070
3071 cFYI(1, ("GetCifsACL"));
3072
Steve French630f3f02007-10-25 21:17:17 +00003073 *pbuflen = 0;
3074 *acl_inf = NULL;
3075
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003076 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003077 8 /* parm len */, tcon, (void **) &pSMB);
3078 if (rc)
3079 return rc;
3080
3081 pSMB->MaxParameterCount = cpu_to_le32(4);
3082 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3083 pSMB->MaxSetupCount = 0;
3084 pSMB->Fid = fid; /* file handle always le */
3085 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3086 CIFS_ACL_DACL);
3087 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3088 pSMB->hdr.smb_buf_length += 11;
3089 iov[0].iov_base = (char *)pSMB;
3090 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3091
Steve Frencha761ac52007-10-18 21:45:27 +00003092 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003093 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003094 cifs_stats_inc(&tcon->num_acl_get);
3095 if (rc) {
3096 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3097 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003098 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003099 __u32 parm_len;
3100 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003101 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003102 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003103
3104/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003105 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003106 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003107 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003108 goto qsec_out;
3109 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3110
Steve French630f3f02007-10-25 21:17:17 +00003111 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003112
3113 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3114 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003115 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003116 goto qsec_out;
3117 }
3118
3119/* BB check that data area is minimum length and as big as acl_len */
3120
Steve Frenchaf6f4612007-10-16 18:40:37 +00003121 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003122 if (acl_len != *pbuflen) {
3123 cERROR(1, ("acl length %d does not match %d",
3124 acl_len, *pbuflen));
3125 if (*pbuflen > acl_len)
3126 *pbuflen = acl_len;
3127 }
Steve French0a4b92c2006-01-12 15:44:21 -08003128
Steve French630f3f02007-10-25 21:17:17 +00003129 /* check if buffer is big enough for the acl
3130 header followed by the smallest SID */
3131 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3132 (*pbuflen >= 64 * 1024)) {
3133 cERROR(1, ("bad acl length %d", *pbuflen));
3134 rc = -EINVAL;
3135 *pbuflen = 0;
3136 } else {
3137 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3138 if (*acl_inf == NULL) {
3139 *pbuflen = 0;
3140 rc = -ENOMEM;
3141 }
3142 memcpy(*acl_inf, pdata, *pbuflen);
3143 }
Steve French0a4b92c2006-01-12 15:44:21 -08003144 }
3145qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003146 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003147 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003148 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003149 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003150/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003151 return rc;
3152}
Steve French97837582007-12-31 07:47:21 +00003153
3154int
3155CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3156 struct cifs_ntsd *pntsd, __u32 acllen)
3157{
3158 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3159 int rc = 0;
3160 int bytes_returned = 0;
3161 SET_SEC_DESC_REQ *pSMB = NULL;
3162 NTRANSACT_RSP *pSMBr = NULL;
3163
3164setCifsAclRetry:
3165 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3166 (void **) &pSMBr);
3167 if (rc)
3168 return (rc);
3169
3170 pSMB->MaxSetupCount = 0;
3171 pSMB->Reserved = 0;
3172
3173 param_count = 8;
3174 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3175 data_count = acllen;
3176 data_offset = param_offset + param_count;
3177 byte_count = 3 /* pad */ + param_count;
3178
3179 pSMB->DataCount = cpu_to_le32(data_count);
3180 pSMB->TotalDataCount = pSMB->DataCount;
3181 pSMB->MaxParameterCount = cpu_to_le32(4);
3182 pSMB->MaxDataCount = cpu_to_le32(16384);
3183 pSMB->ParameterCount = cpu_to_le32(param_count);
3184 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3185 pSMB->TotalParameterCount = pSMB->ParameterCount;
3186 pSMB->DataOffset = cpu_to_le32(data_offset);
3187 pSMB->SetupCount = 0;
3188 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3189 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3190
3191 pSMB->Fid = fid; /* file handle always le */
3192 pSMB->Reserved2 = 0;
3193 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3194
3195 if (pntsd && acllen) {
3196 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3197 (char *) pntsd,
3198 acllen);
3199 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3200
3201 } else
3202 pSMB->hdr.smb_buf_length += byte_count;
3203
3204 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3205 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3206
3207 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3208 if (rc)
3209 cFYI(1, ("Set CIFS ACL returned %d", rc));
3210 cifs_buf_release(pSMB);
3211
3212 if (rc == -EAGAIN)
3213 goto setCifsAclRetry;
3214
3215 return (rc);
3216}
3217
Steve French297647c2007-10-12 04:11:59 +00003218#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003219
Steve French6b8edfe2005-08-23 20:26:03 -07003220/* Legacy Query Path Information call for lookup to old servers such
3221 as Win9x/WinME */
3222int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003223 const unsigned char *searchName,
3224 FILE_ALL_INFO *pFinfo,
3225 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003226{
Steve Frenchad7a2922008-02-07 23:25:02 +00003227 QUERY_INFORMATION_REQ *pSMB;
3228 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003229 int rc = 0;
3230 int bytes_returned;
3231 int name_len;
3232
Steve French50c2f752007-07-13 00:33:32 +00003233 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003234QInfRetry:
3235 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003236 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003237 if (rc)
3238 return rc;
3239
3240 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3241 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003242 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3243 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003244 name_len++; /* trailing null */
3245 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003246 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003247 name_len = strnlen(searchName, PATH_MAX);
3248 name_len++; /* trailing null */
3249 strncpy(pSMB->FileName, searchName, name_len);
3250 }
3251 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003252 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003253 pSMB->hdr.smb_buf_length += (__u16) name_len;
3254 pSMB->ByteCount = cpu_to_le16(name_len);
3255
3256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003258 if (rc) {
3259 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003260 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003261 struct timespec ts;
3262 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003263
3264 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003265 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003266 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003267 ts.tv_nsec = 0;
3268 ts.tv_sec = time;
3269 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003270 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003271 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3272 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003273 pFinfo->AllocationSize =
3274 cpu_to_le64(le32_to_cpu(pSMBr->size));
3275 pFinfo->EndOfFile = pFinfo->AllocationSize;
3276 pFinfo->Attributes =
3277 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003278 } else
3279 rc = -EIO; /* bad buffer passed in */
3280
3281 cifs_buf_release(pSMB);
3282
3283 if (rc == -EAGAIN)
3284 goto QInfRetry;
3285
3286 return rc;
3287}
3288
3289
3290
3291
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292int
3293CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3294 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003295 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003296 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003297 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298{
3299/* level 263 SMB_QUERY_FILE_ALL_INFO */
3300 TRANSACTION2_QPI_REQ *pSMB = NULL;
3301 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3302 int rc = 0;
3303 int bytes_returned;
3304 int name_len;
3305 __u16 params, byte_count;
3306
3307/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3308QPathInfoRetry:
3309 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3310 (void **) &pSMBr);
3311 if (rc)
3312 return rc;
3313
3314 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3315 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003316 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003317 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 name_len++; /* trailing null */
3319 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003320 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 name_len = strnlen(searchName, PATH_MAX);
3322 name_len++; /* trailing null */
3323 strncpy(pSMB->FileName, searchName, name_len);
3324 }
3325
Steve French50c2f752007-07-13 00:33:32 +00003326 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 pSMB->TotalDataCount = 0;
3328 pSMB->MaxParameterCount = cpu_to_le16(2);
3329 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3330 pSMB->MaxSetupCount = 0;
3331 pSMB->Reserved = 0;
3332 pSMB->Flags = 0;
3333 pSMB->Timeout = 0;
3334 pSMB->Reserved2 = 0;
3335 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003336 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 pSMB->DataCount = 0;
3338 pSMB->DataOffset = 0;
3339 pSMB->SetupCount = 1;
3340 pSMB->Reserved3 = 0;
3341 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3342 byte_count = params + 1 /* pad */ ;
3343 pSMB->TotalParameterCount = cpu_to_le16(params);
3344 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003345 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003346 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3347 else
3348 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 pSMB->Reserved4 = 0;
3350 pSMB->hdr.smb_buf_length += byte_count;
3351 pSMB->ByteCount = cpu_to_le16(byte_count);
3352
3353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3355 if (rc) {
3356 cFYI(1, ("Send error in QPathInfo = %d", rc));
3357 } else { /* decode response */
3358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3359
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003360 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3361 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003362 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003364 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003365 rc = -EIO; /* 24 or 26 expected but we do not read
3366 last field */
3367 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003368 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003370
3371 /* On legacy responses we do not read the last field,
3372 EAsize, fortunately since it varies by subdialect and
3373 also note it differs on Set vs. Get, ie two bytes or 4
3374 bytes depending but we don't care here */
3375 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003376 size = sizeof(FILE_INFO_STANDARD);
3377 else
3378 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 memcpy((char *) pFindData,
3380 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003381 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 } else
3383 rc = -ENOMEM;
3384 }
3385 cifs_buf_release(pSMB);
3386 if (rc == -EAGAIN)
3387 goto QPathInfoRetry;
3388
3389 return rc;
3390}
3391
3392int
3393CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3394 const unsigned char *searchName,
3395 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003396 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397{
3398/* SMB_QUERY_FILE_UNIX_BASIC */
3399 TRANSACTION2_QPI_REQ *pSMB = NULL;
3400 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3401 int rc = 0;
3402 int bytes_returned = 0;
3403 int name_len;
3404 __u16 params, byte_count;
3405
3406 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3407UnixQPathInfoRetry:
3408 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3409 (void **) &pSMBr);
3410 if (rc)
3411 return rc;
3412
3413 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3414 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003415 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003416 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 name_len++; /* trailing null */
3418 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003419 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 name_len = strnlen(searchName, PATH_MAX);
3421 name_len++; /* trailing null */
3422 strncpy(pSMB->FileName, searchName, name_len);
3423 }
3424
Steve French50c2f752007-07-13 00:33:32 +00003425 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 pSMB->TotalDataCount = 0;
3427 pSMB->MaxParameterCount = cpu_to_le16(2);
3428 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003429 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 pSMB->MaxSetupCount = 0;
3431 pSMB->Reserved = 0;
3432 pSMB->Flags = 0;
3433 pSMB->Timeout = 0;
3434 pSMB->Reserved2 = 0;
3435 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003436 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 pSMB->DataCount = 0;
3438 pSMB->DataOffset = 0;
3439 pSMB->SetupCount = 1;
3440 pSMB->Reserved3 = 0;
3441 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3442 byte_count = params + 1 /* pad */ ;
3443 pSMB->TotalParameterCount = cpu_to_le16(params);
3444 pSMB->ParameterCount = pSMB->TotalParameterCount;
3445 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3446 pSMB->Reserved4 = 0;
3447 pSMB->hdr.smb_buf_length += byte_count;
3448 pSMB->ByteCount = cpu_to_le16(byte_count);
3449
3450 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3451 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3452 if (rc) {
3453 cFYI(1, ("Send error in QPathInfo = %d", rc));
3454 } else { /* decode response */
3455 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3456
3457 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003458 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3459 "Unix Extensions can be disabled on mount "
3460 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 rc = -EIO; /* bad smb */
3462 } else {
3463 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3464 memcpy((char *) pFindData,
3465 (char *) &pSMBr->hdr.Protocol +
3466 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003467 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 }
3469 }
3470 cifs_buf_release(pSMB);
3471 if (rc == -EAGAIN)
3472 goto UnixQPathInfoRetry;
3473
3474 return rc;
3475}
3476
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477/* xid, tcon, searchName and codepage are input parms, rest are returned */
3478int
3479CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003480 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003482 __u16 *pnetfid,
3483 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484{
3485/* level 257 SMB_ */
3486 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3487 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003488 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 int rc = 0;
3490 int bytes_returned = 0;
3491 int name_len;
3492 __u16 params, byte_count;
3493
Steve French50c2f752007-07-13 00:33:32 +00003494 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495
3496findFirstRetry:
3497 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3498 (void **) &pSMBr);
3499 if (rc)
3500 return rc;
3501
3502 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3503 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003504 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003505 PATH_MAX, nls_codepage, remap);
3506 /* We can not add the asterik earlier in case
3507 it got remapped to 0xF03A as if it were part of the
3508 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003510 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003511 pSMB->FileName[name_len+1] = 0;
3512 pSMB->FileName[name_len+2] = '*';
3513 pSMB->FileName[name_len+3] = 0;
3514 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3516 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003517 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 } else { /* BB add check for overrun of SMB buf BB */
3519 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003521 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 free buffer exit; BB */
3523 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003524 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003525 pSMB->FileName[name_len+1] = '*';
3526 pSMB->FileName[name_len+2] = 0;
3527 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 }
3529
3530 params = 12 + name_len /* includes null */ ;
3531 pSMB->TotalDataCount = 0; /* no EAs */
3532 pSMB->MaxParameterCount = cpu_to_le16(10);
3533 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3534 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3535 pSMB->MaxSetupCount = 0;
3536 pSMB->Reserved = 0;
3537 pSMB->Flags = 0;
3538 pSMB->Timeout = 0;
3539 pSMB->Reserved2 = 0;
3540 byte_count = params + 1 /* pad */ ;
3541 pSMB->TotalParameterCount = cpu_to_le16(params);
3542 pSMB->ParameterCount = pSMB->TotalParameterCount;
3543 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003544 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3545 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 pSMB->DataCount = 0;
3547 pSMB->DataOffset = 0;
3548 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3549 pSMB->Reserved3 = 0;
3550 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3551 pSMB->SearchAttributes =
3552 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3553 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003554 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3555 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 CIFS_SEARCH_RETURN_RESUME);
3557 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3558
3559 /* BB what should we set StorageType to? Does it matter? BB */
3560 pSMB->SearchStorageType = 0;
3561 pSMB->hdr.smb_buf_length += byte_count;
3562 pSMB->ByteCount = cpu_to_le16(byte_count);
3563
3564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003566 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567
Steve French88274812006-03-09 22:21:45 +00003568 if (rc) {/* BB add logic to retry regular search if Unix search
3569 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 /* BB Add code to handle unsupported level rc */
3571 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003572
Steve French88274812006-03-09 22:21:45 +00003573 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
3575 /* BB eventually could optimize out free and realloc of buf */
3576 /* for this case */
3577 if (rc == -EAGAIN)
3578 goto findFirstRetry;
3579 } else { /* decode response */
3580 /* BB remember to free buffer if error BB */
3581 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003582 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3584 psrch_inf->unicode = TRUE;
3585 else
3586 psrch_inf->unicode = FALSE;
3587
3588 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003589 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003590 psrch_inf->srch_entries_start =
3591 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3594 le16_to_cpu(pSMBr->t2.ParameterOffset));
3595
Steve French790fe572007-07-07 19:25:05 +00003596 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 psrch_inf->endOfSearch = TRUE;
3598 else
3599 psrch_inf->endOfSearch = FALSE;
3600
Steve French50c2f752007-07-13 00:33:32 +00003601 psrch_inf->entries_in_buffer =
3602 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003603 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 *pnetfid = parms->SearchHandle;
3606 } else {
3607 cifs_buf_release(pSMB);
3608 }
3609 }
3610
3611 return rc;
3612}
3613
3614int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003615 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616{
3617 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3618 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003619 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 char *response_data;
3621 int rc = 0;
3622 int bytes_returned, name_len;
3623 __u16 params, byte_count;
3624
3625 cFYI(1, ("In FindNext"));
3626
Steve French790fe572007-07-07 19:25:05 +00003627 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 return -ENOENT;
3629
3630 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3631 (void **) &pSMBr);
3632 if (rc)
3633 return rc;
3634
Steve French50c2f752007-07-13 00:33:32 +00003635 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 byte_count = 0;
3637 pSMB->TotalDataCount = 0; /* no EAs */
3638 pSMB->MaxParameterCount = cpu_to_le16(8);
3639 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003640 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3641 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 pSMB->MaxSetupCount = 0;
3643 pSMB->Reserved = 0;
3644 pSMB->Flags = 0;
3645 pSMB->Timeout = 0;
3646 pSMB->Reserved2 = 0;
3647 pSMB->ParameterOffset = cpu_to_le16(
3648 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3649 pSMB->DataCount = 0;
3650 pSMB->DataOffset = 0;
3651 pSMB->SetupCount = 1;
3652 pSMB->Reserved3 = 0;
3653 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3654 pSMB->SearchHandle = searchHandle; /* always kept as le */
3655 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003656 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3658 pSMB->ResumeKey = psrch_inf->resume_key;
3659 pSMB->SearchFlags =
3660 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3661
3662 name_len = psrch_inf->resume_name_len;
3663 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003664 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3666 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003667 /* 14 byte parm len above enough for 2 byte null terminator */
3668 pSMB->ResumeFileName[name_len] = 0;
3669 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 } else {
3671 rc = -EINVAL;
3672 goto FNext2_err_exit;
3673 }
3674 byte_count = params + 1 /* pad */ ;
3675 pSMB->TotalParameterCount = cpu_to_le16(params);
3676 pSMB->ParameterCount = pSMB->TotalParameterCount;
3677 pSMB->hdr.smb_buf_length += byte_count;
3678 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003679
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003682 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 if (rc) {
3684 if (rc == -EBADF) {
3685 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003686 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 } else
3688 cFYI(1, ("FindNext returned = %d", rc));
3689 } else { /* decode response */
3690 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003691
Steve French790fe572007-07-07 19:25:05 +00003692 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 /* BB fixme add lock for file (srch_info) struct here */
3694 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3695 psrch_inf->unicode = TRUE;
3696 else
3697 psrch_inf->unicode = FALSE;
3698 response_data = (char *) &pSMBr->hdr.Protocol +
3699 le16_to_cpu(pSMBr->t2.ParameterOffset);
3700 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3701 response_data = (char *)&pSMBr->hdr.Protocol +
3702 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003703 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003704 cifs_small_buf_release(
3705 psrch_inf->ntwrk_buf_start);
3706 else
3707 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 psrch_inf->srch_entries_start = response_data;
3709 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003710 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003711 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 psrch_inf->endOfSearch = TRUE;
3713 else
3714 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003715 psrch_inf->entries_in_buffer =
3716 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 psrch_inf->index_of_last_entry +=
3718 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003719/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3720 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721
3722 /* BB fixme add unlock here */
3723 }
3724
3725 }
3726
3727 /* BB On error, should we leave previous search buf (and count and
3728 last entry fields) intact or free the previous one? */
3729
3730 /* Note: On -EAGAIN error only caller can retry on handle based calls
3731 since file handle passed in no longer valid */
3732FNext2_err_exit:
3733 if (rc != 0)
3734 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 return rc;
3736}
3737
3738int
Steve French50c2f752007-07-13 00:33:32 +00003739CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3740 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741{
3742 int rc = 0;
3743 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
3745 cFYI(1, ("In CIFSSMBFindClose"));
3746 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3747
3748 /* no sense returning error if session restarted
3749 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003750 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 return 0;
3752 if (rc)
3753 return rc;
3754
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 pSMB->FileID = searchHandle;
3756 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003757 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003758 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003760
Steve Frencha4544342005-08-24 13:59:35 -07003761 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762
3763 /* Since session is dead, search handle closed on server already */
3764 if (rc == -EAGAIN)
3765 rc = 0;
3766
3767 return rc;
3768}
3769
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770int
3771CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003772 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003773 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003774 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775{
3776 int rc = 0;
3777 TRANSACTION2_QPI_REQ *pSMB = NULL;
3778 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3779 int name_len, bytes_returned;
3780 __u16 params, byte_count;
3781
Steve French50c2f752007-07-13 00:33:32 +00003782 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003783 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003784 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785
3786GetInodeNumberRetry:
3787 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003788 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 if (rc)
3790 return rc;
3791
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3793 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003794 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003795 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 name_len++; /* trailing null */
3797 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003798 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 name_len = strnlen(searchName, PATH_MAX);
3800 name_len++; /* trailing null */
3801 strncpy(pSMB->FileName, searchName, name_len);
3802 }
3803
3804 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3805 pSMB->TotalDataCount = 0;
3806 pSMB->MaxParameterCount = cpu_to_le16(2);
3807 /* BB find exact max data count below from sess structure BB */
3808 pSMB->MaxDataCount = cpu_to_le16(4000);
3809 pSMB->MaxSetupCount = 0;
3810 pSMB->Reserved = 0;
3811 pSMB->Flags = 0;
3812 pSMB->Timeout = 0;
3813 pSMB->Reserved2 = 0;
3814 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003815 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 pSMB->DataCount = 0;
3817 pSMB->DataOffset = 0;
3818 pSMB->SetupCount = 1;
3819 pSMB->Reserved3 = 0;
3820 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3821 byte_count = params + 1 /* pad */ ;
3822 pSMB->TotalParameterCount = cpu_to_le16(params);
3823 pSMB->ParameterCount = pSMB->TotalParameterCount;
3824 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3825 pSMB->Reserved4 = 0;
3826 pSMB->hdr.smb_buf_length += byte_count;
3827 pSMB->ByteCount = cpu_to_le16(byte_count);
3828
3829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3831 if (rc) {
3832 cFYI(1, ("error %d in QueryInternalInfo", rc));
3833 } else {
3834 /* decode response */
3835 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3836 if (rc || (pSMBr->ByteCount < 2))
3837 /* BB also check enough total bytes returned */
3838 /* If rc should we check for EOPNOSUPP and
3839 disable the srvino flag? or in caller? */
3840 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003841 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3843 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003844 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003846 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3848 rc = -EIO;
3849 goto GetInodeNumOut;
3850 }
3851 pfinfo = (struct file_internal_info *)
3852 (data_offset + (char *) &pSMBr->hdr.Protocol);
3853 *inode_number = pfinfo->UniqueId;
3854 }
3855 }
3856GetInodeNumOut:
3857 cifs_buf_release(pSMB);
3858 if (rc == -EAGAIN)
3859 goto GetInodeNumberRetry;
3860 return rc;
3861}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862
3863int
3864CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3865 const unsigned char *searchName,
3866 unsigned char **targetUNCs,
3867 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003868 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869{
3870/* TRANS2_GET_DFS_REFERRAL */
3871 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3872 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003873 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 int rc = 0;
3875 int bytes_returned;
3876 int name_len;
3877 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003878 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 __u16 params, byte_count;
3880 *number_of_UNC_in_array = 0;
3881 *targetUNCs = NULL;
3882
3883 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3884 if (ses == NULL)
3885 return -ENODEV;
3886getDFSRetry:
3887 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3888 (void **) &pSMBr);
3889 if (rc)
3890 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003891
3892 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003893 but should never be null here anyway */
3894 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 pSMB->hdr.Tid = ses->ipc_tid;
3896 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003897 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003899 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901
3902 if (ses->capabilities & CAP_UNICODE) {
3903 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3904 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003905 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003906 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 name_len++; /* trailing null */
3908 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003909 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 name_len = strnlen(searchName, PATH_MAX);
3911 name_len++; /* trailing null */
3912 strncpy(pSMB->RequestFileName, searchName, name_len);
3913 }
3914
Steve French790fe572007-07-07 19:25:05 +00003915 if (ses->server) {
3916 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003917 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3918 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3919 }
3920
Steve French50c2f752007-07-13 00:33:32 +00003921 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003922
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 params = 2 /* level */ + name_len /*includes null */ ;
3924 pSMB->TotalDataCount = 0;
3925 pSMB->DataCount = 0;
3926 pSMB->DataOffset = 0;
3927 pSMB->MaxParameterCount = 0;
3928 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3929 pSMB->MaxSetupCount = 0;
3930 pSMB->Reserved = 0;
3931 pSMB->Flags = 0;
3932 pSMB->Timeout = 0;
3933 pSMB->Reserved2 = 0;
3934 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003935 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 pSMB->SetupCount = 1;
3937 pSMB->Reserved3 = 0;
3938 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3939 byte_count = params + 3 /* pad */ ;
3940 pSMB->ParameterCount = cpu_to_le16(params);
3941 pSMB->TotalParameterCount = pSMB->ParameterCount;
3942 pSMB->MaxReferralLevel = cpu_to_le16(3);
3943 pSMB->hdr.smb_buf_length += byte_count;
3944 pSMB->ByteCount = cpu_to_le16(byte_count);
3945
3946 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3948 if (rc) {
3949 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3950 } else { /* decode response */
3951/* BB Add logic to parse referrals here */
3952 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3953
Steve French50c2f752007-07-13 00:33:32 +00003954 /* BB Also check if enough total bytes returned? */
3955 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 rc = -EIO; /* bad smb */
3957 else {
Steve French50c2f752007-07-13 00:33:32 +00003958 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3960
3961 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003962 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003964 referrals =
3965 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 (8 /* sizeof start of data block */ +
3967 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003968 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003969 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003970 "for referral one refer size: 0x%x srv "
3971 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003972 le16_to_cpu(pSMBr->NumberOfReferrals),
3973 le16_to_cpu(pSMBr->DFSFlags),
3974 le16_to_cpu(referrals->ReferralSize),
3975 le16_to_cpu(referrals->ServerType),
3976 le16_to_cpu(referrals->ReferralFlags),
3977 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 /* BB This field is actually two bytes in from start of
3979 data block so we could do safety check that DataBlock
3980 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003981 *number_of_UNC_in_array =
3982 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
3984 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003985 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 *number_of_UNC_in_array = 1;
3987
3988 /* get the length of the strings describing refs */
3989 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003990 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003992 __u16 offset =
3993 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003995 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 not try to copy any more */
3997 *number_of_UNC_in_array = i;
3998 break;
Steve French50c2f752007-07-13 00:33:32 +00003999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 temp = ((char *)referrals) + offset;
4001
4002 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004003 name_len += UniStrnlen((wchar_t *)temp,
4004 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 } else {
Steve French50c2f752007-07-13 00:33:32 +00004006 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 }
4008 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004009 /* BB add check that referral pointer does
4010 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 }
4012 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004013 *targetUNCs =
4014 kmalloc(name_len+1+(*number_of_UNC_in_array),
4015 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004016 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 rc = -ENOMEM;
4018 goto GetDFSRefExit;
4019 }
4020 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004021 referrals = (struct dfs_referral_level_3 *)
4022 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 (char *) &pSMBr->hdr.Protocol);
4024
Steve French50c2f752007-07-13 00:33:32 +00004025 for (i = 0; i < *number_of_UNC_in_array; i++) {
4026 temp = ((char *)referrals) +
4027 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4029 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004030 (__le16 *) temp,
4031 name_len,
4032 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 } else {
Steve French50c2f752007-07-13 00:33:32 +00004034 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 }
4036 /* BB update target_uncs pointers */
4037 referrals++;
4038 }
4039 temp = *targetUNCs;
4040 temp[name_len] = 0;
4041 }
4042
4043 }
4044GetDFSRefExit:
4045 if (pSMB)
4046 cifs_buf_release(pSMB);
4047
4048 if (rc == -EAGAIN)
4049 goto getDFSRetry;
4050
4051 return rc;
4052}
4053
Steve French20962432005-09-21 22:05:57 -07004054/* Query File System Info such as free space to old servers such as Win 9x */
4055int
4056SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4057{
4058/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4059 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4060 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4061 FILE_SYSTEM_ALLOC_INFO *response_data;
4062 int rc = 0;
4063 int bytes_returned = 0;
4064 __u16 params, byte_count;
4065
4066 cFYI(1, ("OldQFSInfo"));
4067oldQFSInfoRetry:
4068 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4069 (void **) &pSMBr);
4070 if (rc)
4071 return rc;
Steve French20962432005-09-21 22:05:57 -07004072
4073 params = 2; /* level */
4074 pSMB->TotalDataCount = 0;
4075 pSMB->MaxParameterCount = cpu_to_le16(2);
4076 pSMB->MaxDataCount = cpu_to_le16(1000);
4077 pSMB->MaxSetupCount = 0;
4078 pSMB->Reserved = 0;
4079 pSMB->Flags = 0;
4080 pSMB->Timeout = 0;
4081 pSMB->Reserved2 = 0;
4082 byte_count = params + 1 /* pad */ ;
4083 pSMB->TotalParameterCount = cpu_to_le16(params);
4084 pSMB->ParameterCount = pSMB->TotalParameterCount;
4085 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4086 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4087 pSMB->DataCount = 0;
4088 pSMB->DataOffset = 0;
4089 pSMB->SetupCount = 1;
4090 pSMB->Reserved3 = 0;
4091 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4092 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4093 pSMB->hdr.smb_buf_length += byte_count;
4094 pSMB->ByteCount = cpu_to_le16(byte_count);
4095
4096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4098 if (rc) {
4099 cFYI(1, ("Send error in QFSInfo = %d", rc));
4100 } else { /* decode response */
4101 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4102
4103 if (rc || (pSMBr->ByteCount < 18))
4104 rc = -EIO; /* bad smb */
4105 else {
4106 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004107 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004108 pSMBr->ByteCount, data_offset));
4109
Steve French50c2f752007-07-13 00:33:32 +00004110 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004111 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4112 FSData->f_bsize =
4113 le16_to_cpu(response_data->BytesPerSector) *
4114 le32_to_cpu(response_data->
4115 SectorsPerAllocationUnit);
4116 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004117 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004118 FSData->f_bfree = FSData->f_bavail =
4119 le32_to_cpu(response_data->FreeAllocationUnits);
4120 cFYI(1,
4121 ("Blocks: %lld Free: %lld Block size %ld",
4122 (unsigned long long)FSData->f_blocks,
4123 (unsigned long long)FSData->f_bfree,
4124 FSData->f_bsize));
4125 }
4126 }
4127 cifs_buf_release(pSMB);
4128
4129 if (rc == -EAGAIN)
4130 goto oldQFSInfoRetry;
4131
4132 return rc;
4133}
4134
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135int
Steve French737b7582005-04-28 22:41:06 -07004136CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137{
4138/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4139 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4140 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4141 FILE_SYSTEM_INFO *response_data;
4142 int rc = 0;
4143 int bytes_returned = 0;
4144 __u16 params, byte_count;
4145
4146 cFYI(1, ("In QFSInfo"));
4147QFSInfoRetry:
4148 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4149 (void **) &pSMBr);
4150 if (rc)
4151 return rc;
4152
4153 params = 2; /* level */
4154 pSMB->TotalDataCount = 0;
4155 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004156 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 pSMB->MaxSetupCount = 0;
4158 pSMB->Reserved = 0;
4159 pSMB->Flags = 0;
4160 pSMB->Timeout = 0;
4161 pSMB->Reserved2 = 0;
4162 byte_count = params + 1 /* pad */ ;
4163 pSMB->TotalParameterCount = cpu_to_le16(params);
4164 pSMB->ParameterCount = pSMB->TotalParameterCount;
4165 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004166 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 pSMB->DataCount = 0;
4168 pSMB->DataOffset = 0;
4169 pSMB->SetupCount = 1;
4170 pSMB->Reserved3 = 0;
4171 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4172 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4173 pSMB->hdr.smb_buf_length += byte_count;
4174 pSMB->ByteCount = cpu_to_le16(byte_count);
4175
4176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4178 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004179 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004181 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
Steve French20962432005-09-21 22:05:57 -07004183 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 rc = -EIO; /* bad smb */
4185 else {
4186 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
4188 response_data =
4189 (FILE_SYSTEM_INFO
4190 *) (((char *) &pSMBr->hdr.Protocol) +
4191 data_offset);
4192 FSData->f_bsize =
4193 le32_to_cpu(response_data->BytesPerSector) *
4194 le32_to_cpu(response_data->
4195 SectorsPerAllocationUnit);
4196 FSData->f_blocks =
4197 le64_to_cpu(response_data->TotalAllocationUnits);
4198 FSData->f_bfree = FSData->f_bavail =
4199 le64_to_cpu(response_data->FreeAllocationUnits);
4200 cFYI(1,
4201 ("Blocks: %lld Free: %lld Block size %ld",
4202 (unsigned long long)FSData->f_blocks,
4203 (unsigned long long)FSData->f_bfree,
4204 FSData->f_bsize));
4205 }
4206 }
4207 cifs_buf_release(pSMB);
4208
4209 if (rc == -EAGAIN)
4210 goto QFSInfoRetry;
4211
4212 return rc;
4213}
4214
4215int
Steve French737b7582005-04-28 22:41:06 -07004216CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4219 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4220 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4221 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4222 int rc = 0;
4223 int bytes_returned = 0;
4224 __u16 params, byte_count;
4225
4226 cFYI(1, ("In QFSAttributeInfo"));
4227QFSAttributeRetry:
4228 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4229 (void **) &pSMBr);
4230 if (rc)
4231 return rc;
4232
4233 params = 2; /* level */
4234 pSMB->TotalDataCount = 0;
4235 pSMB->MaxParameterCount = cpu_to_le16(2);
4236 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4237 pSMB->MaxSetupCount = 0;
4238 pSMB->Reserved = 0;
4239 pSMB->Flags = 0;
4240 pSMB->Timeout = 0;
4241 pSMB->Reserved2 = 0;
4242 byte_count = params + 1 /* pad */ ;
4243 pSMB->TotalParameterCount = cpu_to_le16(params);
4244 pSMB->ParameterCount = pSMB->TotalParameterCount;
4245 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004246 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 pSMB->DataCount = 0;
4248 pSMB->DataOffset = 0;
4249 pSMB->SetupCount = 1;
4250 pSMB->Reserved3 = 0;
4251 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4252 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4253 pSMB->hdr.smb_buf_length += byte_count;
4254 pSMB->ByteCount = cpu_to_le16(byte_count);
4255
4256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4258 if (rc) {
4259 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4260 } else { /* decode response */
4261 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4262
Steve French50c2f752007-07-13 00:33:32 +00004263 if (rc || (pSMBr->ByteCount < 13)) {
4264 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 rc = -EIO; /* bad smb */
4266 } else {
4267 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4268 response_data =
4269 (FILE_SYSTEM_ATTRIBUTE_INFO
4270 *) (((char *) &pSMBr->hdr.Protocol) +
4271 data_offset);
4272 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004273 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 }
4275 }
4276 cifs_buf_release(pSMB);
4277
4278 if (rc == -EAGAIN)
4279 goto QFSAttributeRetry;
4280
4281 return rc;
4282}
4283
4284int
Steve French737b7582005-04-28 22:41:06 -07004285CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286{
4287/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4288 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4289 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4290 FILE_SYSTEM_DEVICE_INFO *response_data;
4291 int rc = 0;
4292 int bytes_returned = 0;
4293 __u16 params, byte_count;
4294
4295 cFYI(1, ("In QFSDeviceInfo"));
4296QFSDeviceRetry:
4297 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4298 (void **) &pSMBr);
4299 if (rc)
4300 return rc;
4301
4302 params = 2; /* level */
4303 pSMB->TotalDataCount = 0;
4304 pSMB->MaxParameterCount = cpu_to_le16(2);
4305 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4306 pSMB->MaxSetupCount = 0;
4307 pSMB->Reserved = 0;
4308 pSMB->Flags = 0;
4309 pSMB->Timeout = 0;
4310 pSMB->Reserved2 = 0;
4311 byte_count = params + 1 /* pad */ ;
4312 pSMB->TotalParameterCount = cpu_to_le16(params);
4313 pSMB->ParameterCount = pSMB->TotalParameterCount;
4314 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004315 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316
4317 pSMB->DataCount = 0;
4318 pSMB->DataOffset = 0;
4319 pSMB->SetupCount = 1;
4320 pSMB->Reserved3 = 0;
4321 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4322 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4323 pSMB->hdr.smb_buf_length += byte_count;
4324 pSMB->ByteCount = cpu_to_le16(byte_count);
4325
4326 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4327 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4328 if (rc) {
4329 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4330 } else { /* decode response */
4331 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4332
Steve French630f3f02007-10-25 21:17:17 +00004333 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 rc = -EIO; /* bad smb */
4335 else {
4336 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4337 response_data =
Steve French737b7582005-04-28 22:41:06 -07004338 (FILE_SYSTEM_DEVICE_INFO *)
4339 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 data_offset);
4341 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004342 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 }
4344 }
4345 cifs_buf_release(pSMB);
4346
4347 if (rc == -EAGAIN)
4348 goto QFSDeviceRetry;
4349
4350 return rc;
4351}
4352
4353int
Steve French737b7582005-04-28 22:41:06 -07004354CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355{
4356/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4357 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4358 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4359 FILE_SYSTEM_UNIX_INFO *response_data;
4360 int rc = 0;
4361 int bytes_returned = 0;
4362 __u16 params, byte_count;
4363
4364 cFYI(1, ("In QFSUnixInfo"));
4365QFSUnixRetry:
4366 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4367 (void **) &pSMBr);
4368 if (rc)
4369 return rc;
4370
4371 params = 2; /* level */
4372 pSMB->TotalDataCount = 0;
4373 pSMB->DataCount = 0;
4374 pSMB->DataOffset = 0;
4375 pSMB->MaxParameterCount = cpu_to_le16(2);
4376 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4377 pSMB->MaxSetupCount = 0;
4378 pSMB->Reserved = 0;
4379 pSMB->Flags = 0;
4380 pSMB->Timeout = 0;
4381 pSMB->Reserved2 = 0;
4382 byte_count = params + 1 /* pad */ ;
4383 pSMB->ParameterCount = cpu_to_le16(params);
4384 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004385 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4386 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 pSMB->SetupCount = 1;
4388 pSMB->Reserved3 = 0;
4389 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4390 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4391 pSMB->hdr.smb_buf_length += byte_count;
4392 pSMB->ByteCount = cpu_to_le16(byte_count);
4393
4394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4395 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4396 if (rc) {
4397 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4398 } else { /* decode response */
4399 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4400
4401 if (rc || (pSMBr->ByteCount < 13)) {
4402 rc = -EIO; /* bad smb */
4403 } else {
4404 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4405 response_data =
4406 (FILE_SYSTEM_UNIX_INFO
4407 *) (((char *) &pSMBr->hdr.Protocol) +
4408 data_offset);
4409 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004410 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 }
4412 }
4413 cifs_buf_release(pSMB);
4414
4415 if (rc == -EAGAIN)
4416 goto QFSUnixRetry;
4417
4418
4419 return rc;
4420}
4421
Jeremy Allisonac670552005-06-22 17:26:35 -07004422int
Steve French45abc6e2005-06-23 13:42:03 -05004423CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004424{
4425/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4426 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4427 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4428 int rc = 0;
4429 int bytes_returned = 0;
4430 __u16 params, param_offset, offset, byte_count;
4431
4432 cFYI(1, ("In SETFSUnixInfo"));
4433SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004434 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4436 (void **) &pSMBr);
4437 if (rc)
4438 return rc;
4439
4440 params = 4; /* 2 bytes zero followed by info level. */
4441 pSMB->MaxSetupCount = 0;
4442 pSMB->Reserved = 0;
4443 pSMB->Flags = 0;
4444 pSMB->Timeout = 0;
4445 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004446 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4447 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004448 offset = param_offset + params;
4449
4450 pSMB->MaxParameterCount = cpu_to_le16(4);
4451 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4452 pSMB->SetupCount = 1;
4453 pSMB->Reserved3 = 0;
4454 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4455 byte_count = 1 /* pad */ + params + 12;
4456
4457 pSMB->DataCount = cpu_to_le16(12);
4458 pSMB->ParameterCount = cpu_to_le16(params);
4459 pSMB->TotalDataCount = pSMB->DataCount;
4460 pSMB->TotalParameterCount = pSMB->ParameterCount;
4461 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4462 pSMB->DataOffset = cpu_to_le16(offset);
4463
4464 /* Params. */
4465 pSMB->FileNum = 0;
4466 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4467
4468 /* Data. */
4469 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4470 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4471 pSMB->ClientUnixCap = cpu_to_le64(cap);
4472
4473 pSMB->hdr.smb_buf_length += byte_count;
4474 pSMB->ByteCount = cpu_to_le16(byte_count);
4475
4476 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4477 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4478 if (rc) {
4479 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4480 } else { /* decode response */
4481 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004482 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004483 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004484 }
4485 cifs_buf_release(pSMB);
4486
4487 if (rc == -EAGAIN)
4488 goto SETFSUnixRetry;
4489
4490 return rc;
4491}
4492
4493
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
4495int
4496CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004497 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498{
4499/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4500 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4501 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4502 FILE_SYSTEM_POSIX_INFO *response_data;
4503 int rc = 0;
4504 int bytes_returned = 0;
4505 __u16 params, byte_count;
4506
4507 cFYI(1, ("In QFSPosixInfo"));
4508QFSPosixRetry:
4509 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4510 (void **) &pSMBr);
4511 if (rc)
4512 return rc;
4513
4514 params = 2; /* level */
4515 pSMB->TotalDataCount = 0;
4516 pSMB->DataCount = 0;
4517 pSMB->DataOffset = 0;
4518 pSMB->MaxParameterCount = cpu_to_le16(2);
4519 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4520 pSMB->MaxSetupCount = 0;
4521 pSMB->Reserved = 0;
4522 pSMB->Flags = 0;
4523 pSMB->Timeout = 0;
4524 pSMB->Reserved2 = 0;
4525 byte_count = params + 1 /* pad */ ;
4526 pSMB->ParameterCount = cpu_to_le16(params);
4527 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004528 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4529 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 pSMB->SetupCount = 1;
4531 pSMB->Reserved3 = 0;
4532 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4533 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4534 pSMB->hdr.smb_buf_length += byte_count;
4535 pSMB->ByteCount = cpu_to_le16(byte_count);
4536
4537 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4538 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4539 if (rc) {
4540 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4541 } else { /* decode response */
4542 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4543
4544 if (rc || (pSMBr->ByteCount < 13)) {
4545 rc = -EIO; /* bad smb */
4546 } else {
4547 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4548 response_data =
4549 (FILE_SYSTEM_POSIX_INFO
4550 *) (((char *) &pSMBr->hdr.Protocol) +
4551 data_offset);
4552 FSData->f_bsize =
4553 le32_to_cpu(response_data->BlockSize);
4554 FSData->f_blocks =
4555 le64_to_cpu(response_data->TotalBlocks);
4556 FSData->f_bfree =
4557 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004558 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 FSData->f_bavail = FSData->f_bfree;
4560 } else {
4561 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004562 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 }
Steve French790fe572007-07-07 19:25:05 +00004564 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004566 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004567 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004569 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 }
4571 }
4572 cifs_buf_release(pSMB);
4573
4574 if (rc == -EAGAIN)
4575 goto QFSPosixRetry;
4576
4577 return rc;
4578}
4579
4580
Steve French50c2f752007-07-13 00:33:32 +00004581/* We can not use write of zero bytes trick to
4582 set file size due to need for large file support. Also note that
4583 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 routine which is only needed to work around a sharing violation bug
4585 in Samba which this routine can run into */
4586
4587int
4588CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004589 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004590 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591{
4592 struct smb_com_transaction2_spi_req *pSMB = NULL;
4593 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4594 struct file_end_of_file_info *parm_data;
4595 int name_len;
4596 int rc = 0;
4597 int bytes_returned = 0;
4598 __u16 params, byte_count, data_count, param_offset, offset;
4599
4600 cFYI(1, ("In SetEOF"));
4601SetEOFRetry:
4602 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4603 (void **) &pSMBr);
4604 if (rc)
4605 return rc;
4606
4607 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4608 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004609 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004610 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 name_len++; /* trailing null */
4612 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004613 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 name_len = strnlen(fileName, PATH_MAX);
4615 name_len++; /* trailing null */
4616 strncpy(pSMB->FileName, fileName, name_len);
4617 }
4618 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004619 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004621 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 pSMB->MaxSetupCount = 0;
4623 pSMB->Reserved = 0;
4624 pSMB->Flags = 0;
4625 pSMB->Timeout = 0;
4626 pSMB->Reserved2 = 0;
4627 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004628 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004630 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004631 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4632 pSMB->InformationLevel =
4633 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4634 else
4635 pSMB->InformationLevel =
4636 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4637 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4639 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004640 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 else
4642 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004643 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 }
4645
4646 parm_data =
4647 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4648 offset);
4649 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4650 pSMB->DataOffset = cpu_to_le16(offset);
4651 pSMB->SetupCount = 1;
4652 pSMB->Reserved3 = 0;
4653 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4654 byte_count = 3 /* pad */ + params + data_count;
4655 pSMB->DataCount = cpu_to_le16(data_count);
4656 pSMB->TotalDataCount = pSMB->DataCount;
4657 pSMB->ParameterCount = cpu_to_le16(params);
4658 pSMB->TotalParameterCount = pSMB->ParameterCount;
4659 pSMB->Reserved4 = 0;
4660 pSMB->hdr.smb_buf_length += byte_count;
4661 parm_data->FileSize = cpu_to_le64(size);
4662 pSMB->ByteCount = cpu_to_le16(byte_count);
4663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4664 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004665 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667
4668 cifs_buf_release(pSMB);
4669
4670 if (rc == -EAGAIN)
4671 goto SetEOFRetry;
4672
4673 return rc;
4674}
4675
4676int
Steve French50c2f752007-07-13 00:33:32 +00004677CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4678 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679{
4680 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 char *data_offset;
4682 struct file_end_of_file_info *parm_data;
4683 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 __u16 params, param_offset, offset, byte_count, count;
4685
4686 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4687 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004688 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4689
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 if (rc)
4691 return rc;
4692
4693 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4694 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004695
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 params = 6;
4697 pSMB->MaxSetupCount = 0;
4698 pSMB->Reserved = 0;
4699 pSMB->Flags = 0;
4700 pSMB->Timeout = 0;
4701 pSMB->Reserved2 = 0;
4702 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4703 offset = param_offset + params;
4704
Steve French50c2f752007-07-13 00:33:32 +00004705 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
4707 count = sizeof(struct file_end_of_file_info);
4708 pSMB->MaxParameterCount = cpu_to_le16(2);
4709 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4710 pSMB->SetupCount = 1;
4711 pSMB->Reserved3 = 0;
4712 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4713 byte_count = 3 /* pad */ + params + count;
4714 pSMB->DataCount = cpu_to_le16(count);
4715 pSMB->ParameterCount = cpu_to_le16(params);
4716 pSMB->TotalDataCount = pSMB->DataCount;
4717 pSMB->TotalParameterCount = pSMB->ParameterCount;
4718 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4719 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004720 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4721 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 pSMB->DataOffset = cpu_to_le16(offset);
4723 parm_data->FileSize = cpu_to_le64(size);
4724 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004725 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4727 pSMB->InformationLevel =
4728 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4729 else
4730 pSMB->InformationLevel =
4731 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004732 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4734 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004735 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 else
4737 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004738 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 }
4740 pSMB->Reserved4 = 0;
4741 pSMB->hdr.smb_buf_length += byte_count;
4742 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004743 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 if (rc) {
4745 cFYI(1,
4746 ("Send error in SetFileInfo (SetFileSize) = %d",
4747 rc));
4748 }
4749
Steve French50c2f752007-07-13 00:33:32 +00004750 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 since file handle passed in no longer valid */
4752
4753 return rc;
4754}
4755
Steve French50c2f752007-07-13 00:33:32 +00004756/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 an open handle, rather than by pathname - this is awkward due to
4758 potential access conflicts on the open, but it is unavoidable for these
4759 old servers since the only other choice is to go from 100 nanosecond DCE
4760 time and resort to the original setpathinfo level which takes the ancient
4761 DOS time format with 2 second granularity */
4762int
Steve French50c2f752007-07-13 00:33:32 +00004763CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4764 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765{
4766 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 char *data_offset;
4768 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 __u16 params, param_offset, offset, byte_count, count;
4770
4771 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004772 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4773
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 if (rc)
4775 return rc;
4776
4777 /* At this point there is no need to override the current pid
4778 with the pid of the opener, but that could change if we someday
4779 use an existing handle (rather than opening one on the fly) */
4780 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4781 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004782
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 params = 6;
4784 pSMB->MaxSetupCount = 0;
4785 pSMB->Reserved = 0;
4786 pSMB->Flags = 0;
4787 pSMB->Timeout = 0;
4788 pSMB->Reserved2 = 0;
4789 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4790 offset = param_offset + params;
4791
Steve French50c2f752007-07-13 00:33:32 +00004792 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793
Steve French26f57362007-08-30 22:09:15 +00004794 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 pSMB->MaxParameterCount = cpu_to_le16(2);
4796 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4797 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);
4863 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4864 pSMB->MaxSetupCount = 0;
4865 pSMB->Reserved = 0;
4866 pSMB->Flags = 0;
4867 pSMB->Timeout = 0;
4868 pSMB->Reserved2 = 0;
4869 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004870 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 offset = param_offset + params;
4872 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4873 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4874 pSMB->DataOffset = cpu_to_le16(offset);
4875 pSMB->SetupCount = 1;
4876 pSMB->Reserved3 = 0;
4877 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4878 byte_count = 3 /* pad */ + params + count;
4879
4880 pSMB->DataCount = cpu_to_le16(count);
4881 pSMB->ParameterCount = cpu_to_le16(params);
4882 pSMB->TotalDataCount = pSMB->DataCount;
4883 pSMB->TotalParameterCount = pSMB->ParameterCount;
4884 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4885 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4886 else
4887 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4888 pSMB->Reserved4 = 0;
4889 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004890 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 pSMB->ByteCount = cpu_to_le16(byte_count);
4892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004894 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896
4897 cifs_buf_release(pSMB);
4898
4899 if (rc == -EAGAIN)
4900 goto SetTimesRetry;
4901
4902 return rc;
4903}
4904
4905/* Can not be used to set time stamps yet (due to old DOS time format) */
4906/* Can be used to set attributes */
4907#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4908 handling it anyway and NT4 was what we thought it would be needed for
4909 Do not delete it until we prove whether needed for Win9x though */
4910int
4911CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4912 __u16 dos_attrs, const struct nls_table *nls_codepage)
4913{
4914 SETATTR_REQ *pSMB = NULL;
4915 SETATTR_RSP *pSMBr = NULL;
4916 int rc = 0;
4917 int bytes_returned;
4918 int name_len;
4919
4920 cFYI(1, ("In SetAttrLegacy"));
4921
4922SetAttrLgcyRetry:
4923 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4924 (void **) &pSMBr);
4925 if (rc)
4926 return rc;
4927
4928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4929 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004930 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 PATH_MAX, nls_codepage);
4932 name_len++; /* trailing null */
4933 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004934 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 name_len = strnlen(fileName, PATH_MAX);
4936 name_len++; /* trailing null */
4937 strncpy(pSMB->fileName, fileName, name_len);
4938 }
4939 pSMB->attr = cpu_to_le16(dos_attrs);
4940 pSMB->BufferFormat = 0x04;
4941 pSMB->hdr.smb_buf_length += name_len + 1;
4942 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4943 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4944 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004945 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947
4948 cifs_buf_release(pSMB);
4949
4950 if (rc == -EAGAIN)
4951 goto SetAttrLgcyRetry;
4952
4953 return rc;
4954}
4955#endif /* temporarily unneeded SetAttr legacy function */
4956
4957int
4958CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004959 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4960 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004961 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962{
4963 TRANSACTION2_SPI_REQ *pSMB = NULL;
4964 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4965 int name_len;
4966 int rc = 0;
4967 int bytes_returned = 0;
4968 FILE_UNIX_BASIC_INFO *data_offset;
4969 __u16 params, param_offset, offset, count, byte_count;
4970
4971 cFYI(1, ("In SetUID/GID/Mode"));
4972setPermsRetry:
4973 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4974 (void **) &pSMBr);
4975 if (rc)
4976 return rc;
4977
4978 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4979 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004980 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004981 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 name_len++; /* trailing null */
4983 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004984 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 name_len = strnlen(fileName, PATH_MAX);
4986 name_len++; /* trailing null */
4987 strncpy(pSMB->FileName, fileName, name_len);
4988 }
4989
4990 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004991 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 pSMB->MaxParameterCount = cpu_to_le16(2);
4993 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4994 pSMB->MaxSetupCount = 0;
4995 pSMB->Reserved = 0;
4996 pSMB->Flags = 0;
4997 pSMB->Timeout = 0;
4998 pSMB->Reserved2 = 0;
4999 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005000 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 offset = param_offset + params;
5002 data_offset =
5003 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5004 offset);
5005 memset(data_offset, 0, count);
5006 pSMB->DataOffset = cpu_to_le16(offset);
5007 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5008 pSMB->SetupCount = 1;
5009 pSMB->Reserved3 = 0;
5010 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5011 byte_count = 3 /* pad */ + params + count;
5012 pSMB->ParameterCount = cpu_to_le16(params);
5013 pSMB->DataCount = cpu_to_le16(count);
5014 pSMB->TotalParameterCount = pSMB->ParameterCount;
5015 pSMB->TotalDataCount = pSMB->DataCount;
5016 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5017 pSMB->Reserved4 = 0;
5018 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005019 /* Samba server ignores set of file size to zero due to bugs in some
5020 older clients, but we should be precise - we use SetFileSize to
5021 set file size and do not want to truncate file size to zero
5022 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005023 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005024 data_offset->EndOfFile = NO_CHANGE_64;
5025 data_offset->NumOfBytes = NO_CHANGE_64;
5026 data_offset->LastStatusChange = NO_CHANGE_64;
5027 data_offset->LastAccessTime = NO_CHANGE_64;
5028 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 data_offset->Uid = cpu_to_le64(uid);
5030 data_offset->Gid = cpu_to_le64(gid);
5031 /* better to leave device as zero when it is */
5032 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5033 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5034 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005035
Steve French790fe572007-07-07 19:25:05 +00005036 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005038 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005040 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005042 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005044 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005046 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005048 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5050
5051
5052 pSMB->ByteCount = cpu_to_le16(byte_count);
5053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005055 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057
5058 if (pSMB)
5059 cifs_buf_release(pSMB);
5060 if (rc == -EAGAIN)
5061 goto setPermsRetry;
5062 return rc;
5063}
5064
Steve French50c2f752007-07-13 00:33:32 +00005065int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005066 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005067 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005068 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069{
5070 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005071 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5072 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005073 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 int bytes_returned;
5075
Steve French50c2f752007-07-13 00:33:32 +00005076 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005078 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 if (rc)
5080 return rc;
5081
5082 pSMB->TotalParameterCount = 0 ;
5083 pSMB->TotalDataCount = 0;
5084 pSMB->MaxParameterCount = cpu_to_le32(2);
5085 /* BB find exact data count max from sess structure BB */
5086 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005087/* BB VERIFY verify which is correct for above BB */
5088 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5089 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5090
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 pSMB->MaxSetupCount = 4;
5092 pSMB->Reserved = 0;
5093 pSMB->ParameterOffset = 0;
5094 pSMB->DataCount = 0;
5095 pSMB->DataOffset = 0;
5096 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5097 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5098 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005099 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5101 pSMB->Reserved2 = 0;
5102 pSMB->CompletionFilter = cpu_to_le32(filter);
5103 pSMB->Fid = netfid; /* file handle always le */
5104 pSMB->ByteCount = 0;
5105
5106 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005107 (struct smb_hdr *)pSMBr, &bytes_returned,
5108 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 if (rc) {
5110 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005111 } else {
5112 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005113 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005114 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005115 sizeof(struct dir_notify_req),
5116 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005117 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005118 dnotify_req->Pid = pSMB->hdr.Pid;
5119 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5120 dnotify_req->Mid = pSMB->hdr.Mid;
5121 dnotify_req->Tid = pSMB->hdr.Tid;
5122 dnotify_req->Uid = pSMB->hdr.Uid;
5123 dnotify_req->netfid = netfid;
5124 dnotify_req->pfile = pfile;
5125 dnotify_req->filter = filter;
5126 dnotify_req->multishot = multishot;
5127 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005128 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005129 &GlobalDnotifyReqList);
5130 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005131 } else
Steve French47c786e2005-10-11 20:03:18 -07005132 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 }
5134 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005135 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136}
5137#ifdef CONFIG_CIFS_XATTR
5138ssize_t
5139CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5140 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005141 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005142 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143{
5144 /* BB assumes one setup word */
5145 TRANSACTION2_QPI_REQ *pSMB = NULL;
5146 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5147 int rc = 0;
5148 int bytes_returned;
5149 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005150 struct fea *temp_fea;
5151 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 __u16 params, byte_count;
5153
5154 cFYI(1, ("In Query All EAs path %s", searchName));
5155QAllEAsRetry:
5156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5157 (void **) &pSMBr);
5158 if (rc)
5159 return rc;
5160
5161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5162 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005163 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005164 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 name_len++; /* trailing null */
5166 name_len *= 2;
5167 } else { /* BB improve the check for buffer overruns BB */
5168 name_len = strnlen(searchName, PATH_MAX);
5169 name_len++; /* trailing null */
5170 strncpy(pSMB->FileName, searchName, name_len);
5171 }
5172
Steve French50c2f752007-07-13 00:33:32 +00005173 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 pSMB->TotalDataCount = 0;
5175 pSMB->MaxParameterCount = cpu_to_le16(2);
5176 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5177 pSMB->MaxSetupCount = 0;
5178 pSMB->Reserved = 0;
5179 pSMB->Flags = 0;
5180 pSMB->Timeout = 0;
5181 pSMB->Reserved2 = 0;
5182 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005183 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 pSMB->DataCount = 0;
5185 pSMB->DataOffset = 0;
5186 pSMB->SetupCount = 1;
5187 pSMB->Reserved3 = 0;
5188 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5189 byte_count = params + 1 /* pad */ ;
5190 pSMB->TotalParameterCount = cpu_to_le16(params);
5191 pSMB->ParameterCount = pSMB->TotalParameterCount;
5192 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5193 pSMB->Reserved4 = 0;
5194 pSMB->hdr.smb_buf_length += byte_count;
5195 pSMB->ByteCount = cpu_to_le16(byte_count);
5196
5197 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5198 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5199 if (rc) {
5200 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5201 } else { /* decode response */
5202 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5203
5204 /* BB also check enough total bytes returned */
5205 /* BB we need to improve the validity checking
5206 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005207 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 rc = -EIO; /* bad smb */
5209 /* else if (pFindData){
5210 memcpy((char *) pFindData,
5211 (char *) &pSMBr->hdr.Protocol +
5212 data_offset, kl);
5213 }*/ else {
5214 /* check that length of list is not more than bcc */
5215 /* check that each entry does not go beyond length
5216 of list */
5217 /* check that each element of each entry does not
5218 go beyond end of list */
5219 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005220 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 rc = 0;
5222 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005223 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 ea_response_data = (struct fealist *)
5225 (((char *) &pSMBr->hdr.Protocol) +
5226 data_offset);
5227 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005228 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005229 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005231 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 } else {
5233 /* account for ea list len */
5234 name_len -= 4;
5235 temp_fea = ea_response_data->list;
5236 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005237 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 __u16 value_len;
5239 name_len -= 4;
5240 temp_ptr += 4;
5241 rc += temp_fea->name_len;
5242 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005243 rc = rc + 5 + 1;
5244 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005245 memcpy(EAData, "user.", 5);
5246 EAData += 5;
5247 memcpy(EAData, temp_ptr,
5248 temp_fea->name_len);
5249 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 /* null terminate name */
5251 *EAData = 0;
5252 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005253 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 /* skip copy - calc size only */
5255 } else {
5256 /* stop before overrun buffer */
5257 rc = -ERANGE;
5258 break;
5259 }
5260 name_len -= temp_fea->name_len;
5261 temp_ptr += temp_fea->name_len;
5262 /* account for trailing null */
5263 name_len--;
5264 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005265 value_len =
5266 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 name_len -= value_len;
5268 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005269 /* BB check that temp_ptr is still
5270 within the SMB BB*/
5271
5272 /* no trailing null to account for
5273 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 /* go on to next EA */
5275 temp_fea = (struct fea *)temp_ptr;
5276 }
5277 }
5278 }
5279 }
5280 if (pSMB)
5281 cifs_buf_release(pSMB);
5282 if (rc == -EAGAIN)
5283 goto QAllEAsRetry;
5284
5285 return (ssize_t)rc;
5286}
5287
Steve French50c2f752007-07-13 00:33:32 +00005288ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5289 const unsigned char *searchName, const unsigned char *ea_name,
5290 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005291 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292{
5293 TRANSACTION2_QPI_REQ *pSMB = NULL;
5294 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5295 int rc = 0;
5296 int bytes_returned;
5297 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005298 struct fea *temp_fea;
5299 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 __u16 params, byte_count;
5301
5302 cFYI(1, ("In Query EA path %s", searchName));
5303QEARetry:
5304 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5305 (void **) &pSMBr);
5306 if (rc)
5307 return rc;
5308
5309 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5310 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005311 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005312 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 name_len++; /* trailing null */
5314 name_len *= 2;
5315 } else { /* BB improve the check for buffer overruns BB */
5316 name_len = strnlen(searchName, PATH_MAX);
5317 name_len++; /* trailing null */
5318 strncpy(pSMB->FileName, searchName, name_len);
5319 }
5320
Steve French50c2f752007-07-13 00:33:32 +00005321 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 pSMB->TotalDataCount = 0;
5323 pSMB->MaxParameterCount = cpu_to_le16(2);
5324 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5325 pSMB->MaxSetupCount = 0;
5326 pSMB->Reserved = 0;
5327 pSMB->Flags = 0;
5328 pSMB->Timeout = 0;
5329 pSMB->Reserved2 = 0;
5330 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005331 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 pSMB->DataCount = 0;
5333 pSMB->DataOffset = 0;
5334 pSMB->SetupCount = 1;
5335 pSMB->Reserved3 = 0;
5336 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5337 byte_count = params + 1 /* pad */ ;
5338 pSMB->TotalParameterCount = cpu_to_le16(params);
5339 pSMB->ParameterCount = pSMB->TotalParameterCount;
5340 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5341 pSMB->Reserved4 = 0;
5342 pSMB->hdr.smb_buf_length += byte_count;
5343 pSMB->ByteCount = cpu_to_le16(byte_count);
5344
5345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5347 if (rc) {
5348 cFYI(1, ("Send error in Query EA = %d", rc));
5349 } else { /* decode response */
5350 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5351
5352 /* BB also check enough total bytes returned */
5353 /* BB we need to improve the validity checking
5354 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005355 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 rc = -EIO; /* bad smb */
5357 /* else if (pFindData){
5358 memcpy((char *) pFindData,
5359 (char *) &pSMBr->hdr.Protocol +
5360 data_offset, kl);
5361 }*/ else {
5362 /* check that length of list is not more than bcc */
5363 /* check that each entry does not go beyond length
5364 of list */
5365 /* check that each element of each entry does not
5366 go beyond end of list */
5367 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005368 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 rc = -ENODATA;
5370 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005371 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 ea_response_data = (struct fealist *)
5373 (((char *) &pSMBr->hdr.Protocol) +
5374 data_offset);
5375 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005376 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005377 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005379 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 } else {
5381 /* account for ea list len */
5382 name_len -= 4;
5383 temp_fea = ea_response_data->list;
5384 temp_ptr = (char *)temp_fea;
5385 /* loop through checking if we have a matching
5386 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005387 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 __u16 value_len;
5389 name_len -= 4;
5390 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005391 value_len =
5392 le16_to_cpu(temp_fea->value_len);
5393 /* BB validate that value_len falls within SMB,
5394 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005395 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 temp_fea->name_len) == 0) {
5397 /* found a match */
5398 rc = value_len;
5399 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005400 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 memcpy(ea_value,
5402 temp_fea->name+temp_fea->name_len+1,
5403 rc);
Steve French50c2f752007-07-13 00:33:32 +00005404 /* ea values, unlike ea
5405 names, are not null
5406 terminated */
Steve French790fe572007-07-07 19:25:05 +00005407 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 /* skip copy - calc size only */
5409 } else {
Steve French50c2f752007-07-13 00:33:32 +00005410 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 rc = -ERANGE;
5412 }
5413 break;
5414 }
5415 name_len -= temp_fea->name_len;
5416 temp_ptr += temp_fea->name_len;
5417 /* account for trailing null */
5418 name_len--;
5419 temp_ptr++;
5420 name_len -= value_len;
5421 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005422 /* No trailing null to account for in
5423 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 temp_fea = (struct fea *)temp_ptr;
5425 }
Steve French50c2f752007-07-13 00:33:32 +00005426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 }
5428 }
5429 if (pSMB)
5430 cifs_buf_release(pSMB);
5431 if (rc == -EAGAIN)
5432 goto QEARetry;
5433
5434 return (ssize_t)rc;
5435}
5436
5437int
5438CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005439 const char *ea_name, const void *ea_value,
5440 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5441 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442{
5443 struct smb_com_transaction2_spi_req *pSMB = NULL;
5444 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5445 struct fealist *parm_data;
5446 int name_len;
5447 int rc = 0;
5448 int bytes_returned = 0;
5449 __u16 params, param_offset, byte_count, offset, count;
5450
5451 cFYI(1, ("In SetEA"));
5452SetEARetry:
5453 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5454 (void **) &pSMBr);
5455 if (rc)
5456 return rc;
5457
5458 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5459 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005460 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005461 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 name_len++; /* trailing null */
5463 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005464 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 name_len = strnlen(fileName, PATH_MAX);
5466 name_len++; /* trailing null */
5467 strncpy(pSMB->FileName, fileName, name_len);
5468 }
5469
5470 params = 6 + name_len;
5471
5472 /* done calculating parms using name_len of file name,
5473 now use name_len to calculate length of ea name
5474 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005475 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 name_len = 0;
5477 else
Steve French50c2f752007-07-13 00:33:32 +00005478 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005480 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 pSMB->MaxParameterCount = cpu_to_le16(2);
5482 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5483 pSMB->MaxSetupCount = 0;
5484 pSMB->Reserved = 0;
5485 pSMB->Flags = 0;
5486 pSMB->Timeout = 0;
5487 pSMB->Reserved2 = 0;
5488 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005489 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 offset = param_offset + params;
5491 pSMB->InformationLevel =
5492 cpu_to_le16(SMB_SET_FILE_EA);
5493
5494 parm_data =
5495 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5496 offset);
5497 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5498 pSMB->DataOffset = cpu_to_le16(offset);
5499 pSMB->SetupCount = 1;
5500 pSMB->Reserved3 = 0;
5501 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5502 byte_count = 3 /* pad */ + params + count;
5503 pSMB->DataCount = cpu_to_le16(count);
5504 parm_data->list_len = cpu_to_le32(count);
5505 parm_data->list[0].EA_flags = 0;
5506 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005507 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005509 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005510 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 parm_data->list[0].name[name_len] = 0;
5512 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5513 /* caller ensures that ea_value_len is less than 64K but
5514 we need to ensure that it fits within the smb */
5515
Steve French50c2f752007-07-13 00:33:32 +00005516 /*BB add length check to see if it would fit in
5517 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005518 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5519 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005520 memcpy(parm_data->list[0].name+name_len+1,
5521 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522
5523 pSMB->TotalDataCount = pSMB->DataCount;
5524 pSMB->ParameterCount = cpu_to_le16(params);
5525 pSMB->TotalParameterCount = pSMB->ParameterCount;
5526 pSMB->Reserved4 = 0;
5527 pSMB->hdr.smb_buf_length += byte_count;
5528 pSMB->ByteCount = cpu_to_le16(byte_count);
5529 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5530 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005531 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533
5534 cifs_buf_release(pSMB);
5535
5536 if (rc == -EAGAIN)
5537 goto SetEARetry;
5538
5539 return rc;
5540}
5541
5542#endif