blob: 9b8b4cfdf993eb49725ee011fee5ebda83321648 [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
Igor Mammedovfec45852008-05-16 13:06:30 +040084/* Allocates buffer into dst and copies smb string from src to it.
85 * caller is responsible for freeing dst if function returned 0.
86 * returns:
87 * on success - 0
88 * on failure - errno
89 */
90static int
91cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
92 const bool is_unicode, const struct nls_table *nls_codepage)
93{
94 int plen;
95
96 if (is_unicode) {
97 plen = UniStrnlen((wchar_t *)src, maxlen);
98 *dst = kmalloc(plen + 2, GFP_KERNEL);
99 if (!*dst)
100 goto cifs_strncpy_to_host_ErrExit;
101 cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
102 } else {
103 plen = strnlen(src, maxlen);
104 *dst = kmalloc(plen + 2, GFP_KERNEL);
105 if (!*dst)
106 goto cifs_strncpy_to_host_ErrExit;
107 strncpy(*dst, src, plen);
108 }
109 (*dst)[plen] = 0;
Steve Frencha1fe78f2008-05-16 18:48:38 +0000110 (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
Igor Mammedovfec45852008-05-16 13:06:30 +0400111 return 0;
112
113cifs_strncpy_to_host_ErrExit:
114 cERROR(1, ("Failed to allocate buffer for string\n"));
115 return -ENOMEM;
116}
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119/* Mark as invalid, all open files on tree connections since they
120 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +0000121static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
123 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000124 struct list_head *tmp;
125 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127/* list all files open on tree connection and mark them invalid */
128 write_lock(&GlobalSMBSeslock);
129 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000130 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve French26f57362007-08-30 22:09:15 +0000131 if (open_file)
Steve French4b18f2a2008-04-29 00:06:05 +0000132 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 }
134 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700135 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
136 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Steve Frenchad7a2922008-02-07 23:25:02 +0000139/* Allocate and return pointer to an SMB request buffer, and set basic
140 SMB information in the SMB header. If the return code is zero, this
141 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static int
143small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000144 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
146 int rc = 0;
147
148 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
149 check for tcp and smb session status done differently
150 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000151 if (tcon) {
152 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800153 /* only tree disconnect, open, and write,
154 (and ulogoff which does not have tcon)
155 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000156 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000157 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800158 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000159 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800160 smb_command));
161 return -ENODEV;
162 }
163 }
Steve French790fe572007-07-07 19:25:05 +0000164 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000165 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000167 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700168 reconnect, should be greater than cifs socket
169 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000170 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000171 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000173 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000174 CifsGood), 10 * HZ);
175 if (tcon->ses->server->tcpStatus ==
176 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000178 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000180 cFYI(1, ("gave up waiting on "
181 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700183 } /* else "hard" mount - keep retrying
184 until process is killed or server
185 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 } else /* TCP session is reestablished now */
187 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 }
Steve French50c2f752007-07-13 00:33:32 +0000189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 nls_codepage = load_nls_default();
191 /* need to prevent multiple threads trying to
192 simultaneously reconnect the same SMB session */
193 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000194 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000195 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700196 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000197 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000199 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000200 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700202 /* BB FIXME add code to check if wsize needs
203 update due to negotiated smb buffer size
204 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000205 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000207 /* tell server Unix caps we support */
208 if (tcon->ses->capabilities & CAP_UNIX)
209 reset_cifs_unix_caps(
210 0 /* no xid */,
211 tcon,
212 NULL /* we do not know sb */,
213 NULL /* no vol info */);
214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000217 /* Removed call to reopen open files here.
218 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700219 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Steve French50c2f752007-07-13 00:33:32 +0000221 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700222 know whether we can continue or not without
223 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000224 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 case SMB_COM_READ_ANDX:
226 case SMB_COM_WRITE_ANDX:
227 case SMB_COM_CLOSE:
228 case SMB_COM_FIND_CLOSE2:
229 case SMB_COM_LOCKING_ANDX: {
230 unload_nls(nls_codepage);
231 return -EAGAIN;
232 }
233 }
234 } else {
235 up(&tcon->ses->sesSem);
236 }
237 unload_nls(nls_codepage);
238
239 } else {
240 return -EIO;
241 }
242 }
Steve French790fe572007-07-07 19:25:05 +0000243 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 return rc;
245
246 *request_buf = cifs_small_buf_get();
247 if (*request_buf == NULL) {
248 /* BB should we add a retry in here if not a writepage? */
249 return -ENOMEM;
250 }
251
Steve French63135e02007-07-17 17:34:02 +0000252 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000253 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Steve French790fe572007-07-07 19:25:05 +0000255 if (tcon != NULL)
256 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000259}
260
Steve French12b3b8f2006-02-09 21:12:47 +0000261int
Steve French50c2f752007-07-13 00:33:32 +0000262small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000263 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000264{
265 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000266 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000267
Steve French5815449d2006-02-14 01:36:20 +0000268 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000269 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000270 return rc;
271
Steve French04fdabe2006-02-10 05:52:50 +0000272 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000273 buffer->Mid = GetNextMid(ses->server);
274 if (ses->capabilities & CAP_UNICODE)
275 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000276 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000277 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
278
279 /* uid, tid can stay at zero as set in header assemble */
280
Steve French50c2f752007-07-13 00:33:32 +0000281 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000282 this function is used after 1st of session setup requests */
283
284 return rc;
285}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287/* If the return code is zero, this function must fill in request_buf pointer */
288static int
289smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
290 void **request_buf /* returned */ ,
291 void **response_buf /* returned */ )
292{
293 int rc = 0;
294
295 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
296 check for tcp and smb session status done differently
297 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000298 if (tcon) {
299 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800300 /* only tree disconnect, open, and write,
301 (and ulogoff which does not have tcon)
302 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000303 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800304 (smb_command != SMB_COM_OPEN_ANDX) &&
305 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000306 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800307 smb_command));
308 return -ENODEV;
309 }
310 }
311
Steve French790fe572007-07-07 19:25:05 +0000312 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000313 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700315 /* Give Demultiplex thread up to 10 seconds to
316 reconnect, should be greater than cifs socket
317 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000318 while (tcon->ses->server->tcpStatus ==
319 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000321 (tcon->ses->server->tcpStatus ==
322 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000323 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700324 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000326 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000328 cFYI(1, ("gave up waiting on "
329 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700331 } /* else "hard" mount - keep retrying
332 until process is killed or server
333 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 } else /* TCP session is reestablished now */
335 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 nls_codepage = load_nls_default();
338 /* need to prevent multiple threads trying to
339 simultaneously reconnect the same SMB session */
340 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000341 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000342 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700343 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000344 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700346 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
347 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700349 /* BB FIXME add code to check if wsize needs
350 update due to negotiated smb buffer size
351 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000352 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000354 /* tell server Unix caps we support */
355 if (tcon->ses->capabilities & CAP_UNIX)
356 reset_cifs_unix_caps(
357 0 /* no xid */,
358 tcon,
359 NULL /* do not know sb */,
360 NULL /* no vol info */);
361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000364 /* Removed call to reopen open files here.
365 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700366 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Steve French50c2f752007-07-13 00:33:32 +0000368 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700369 know whether we can continue or not without
370 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000371 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 case SMB_COM_READ_ANDX:
373 case SMB_COM_WRITE_ANDX:
374 case SMB_COM_CLOSE:
375 case SMB_COM_FIND_CLOSE2:
376 case SMB_COM_LOCKING_ANDX: {
377 unload_nls(nls_codepage);
378 return -EAGAIN;
379 }
380 }
381 } else {
382 up(&tcon->ses->sesSem);
383 }
384 unload_nls(nls_codepage);
385
386 } else {
387 return -EIO;
388 }
389 }
Steve French790fe572007-07-07 19:25:05 +0000390 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 return rc;
392
393 *request_buf = cifs_buf_get();
394 if (*request_buf == NULL) {
395 /* BB should we add a retry in here if not a writepage? */
396 return -ENOMEM;
397 }
398 /* Although the original thought was we needed the response buf for */
399 /* potential retries of smb operations it turns out we can determine */
400 /* from the mid flags when the request buffer can be resent without */
401 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000402 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000403 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000406 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Steve French790fe572007-07-07 19:25:05 +0000408 if (tcon != NULL)
409 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 return rc;
412}
413
Steve French50c2f752007-07-13 00:33:32 +0000414static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 int rc = -EINVAL;
417 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000418 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
420 /* check for plausible wct, bcc and t2 data and parm sizes */
421 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000422 if (pSMB->hdr.WordCount >= 10) {
423 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
425 /* check that bcc is at least as big as parms + data */
426 /* check that bcc is less than negotiated smb buffer */
427 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000428 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000429 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000430 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000432 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700433 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000435 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000436 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
438 return 0;
439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 }
441 }
442 }
Steve French50c2f752007-07-13 00:33:32 +0000443 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 sizeof(struct smb_t2_rsp) + 16);
445 return rc;
446}
447int
448CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
449{
450 NEGOTIATE_REQ *pSMB;
451 NEGOTIATE_RSP *pSMBr;
452 int rc = 0;
453 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000454 int i;
Steve French50c2f752007-07-13 00:33:32 +0000455 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000457 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100458 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
Steve French790fe572007-07-07 19:25:05 +0000460 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 server = ses->server;
462 else {
463 rc = -EIO;
464 return rc;
465 }
466 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
467 (void **) &pSMB, (void **) &pSMBr);
468 if (rc)
469 return rc;
Steve French750d1152006-06-27 06:28:30 +0000470
471 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000472 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000473 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000474 else /* if override flags set only sign/seal OR them with global auth */
475 secFlags = extended_security | ses->overrideSecFlg;
476
Steve French762e5ab2007-06-28 18:41:42 +0000477 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000478
Steve French1982c342005-08-17 12:38:22 -0700479 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000480 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000481
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000482 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000483 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000484 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
485 cFYI(1, ("Kerberos only mechanism, enable extended security"));
486 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
487 }
Steve French50c2f752007-07-13 00:33:32 +0000488
Steve French39798772006-05-31 22:40:51 +0000489 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000490 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000491 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
492 count += strlen(protocols[i].name) + 1;
493 /* null at end of source and target buffers anyway */
494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 pSMB->hdr.smb_buf_length += count;
496 pSMB->ByteCount = cpu_to_le16(count);
497
498 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000500 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000501 goto neg_err_exit;
502
Al Viro733f99a2006-10-14 16:48:26 +0100503 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000504 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000505 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000506 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000507 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000508 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000509 could not negotiate a common dialect */
510 rc = -EOPNOTSUPP;
511 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000512#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000513 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100514 && ((dialect == LANMAN_PROT)
515 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000516 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000517 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000518
Steve French790fe572007-07-07 19:25:05 +0000519 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000520 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000521 server->secType = LANMAN;
522 else {
523 cERROR(1, ("mount failed weak security disabled"
524 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000525 rc = -EOPNOTSUPP;
526 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000527 }
Steve French254e55e2006-06-04 05:53:15 +0000528 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
529 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
530 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000531 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000532 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
533 /* even though we do not use raw we might as well set this
534 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000535 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000536 server->maxRw = 0xFF00;
537 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
538 } else {
539 server->maxRw = 0;/* we do not need to use raw anyway */
540 server->capabilities = CAP_MPX_MODE;
541 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000542 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000543 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000544 /* OS/2 often does not set timezone therefore
545 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000546 * Could deviate slightly from the right zone.
547 * Smallest defined timezone difference is 15 minutes
548 * (i.e. Nepal). Rounding up/down is done to match
549 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000550 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000551 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000552 struct timespec ts, utc;
553 utc = CURRENT_TIME;
554 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
555 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000556 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
557 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000558 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000559 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000560 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000561 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000562 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000563 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000564 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000565 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000566 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000567 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000568 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000569 server->timeAdj = (int)tmp;
570 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000571 }
Steve French790fe572007-07-07 19:25:05 +0000572 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000573
Steve French39798772006-05-31 22:40:51 +0000574
Steve French254e55e2006-06-04 05:53:15 +0000575 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000576 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000577
Steve French50c2f752007-07-13 00:33:32 +0000578 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000579 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000580 memcpy(server->cryptKey, rsp->EncryptionKey,
581 CIFS_CRYPTO_KEY_SIZE);
582 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
583 rc = -EIO; /* need cryptkey unless plain text */
584 goto neg_err_exit;
585 }
Steve French39798772006-05-31 22:40:51 +0000586
Steve French790fe572007-07-07 19:25:05 +0000587 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000588 /* we will not end up setting signing flags - as no signing
589 was in LANMAN and server did not return the flags on */
590 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000591#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000592 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000593 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000594 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000595 rc = -EOPNOTSUPP;
596#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000597 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000598 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000599 /* unknown wct */
600 rc = -EOPNOTSUPP;
601 goto neg_err_exit;
602 }
603 /* else wct == 17 NTLM */
604 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000605 if ((server->secMode & SECMODE_USER) == 0)
606 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000607
Steve French790fe572007-07-07 19:25:05 +0000608 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000609#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000610 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000611#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000612 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000613 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000614
Steve French790fe572007-07-07 19:25:05 +0000615 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000616 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000617 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000618 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000619 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000620 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000621 else if (secFlags & CIFSSEC_MAY_KRB5)
622 server->secType = Kerberos;
623 else if (secFlags & CIFSSEC_MAY_LANMAN)
624 server->secType = LANMAN;
625/* #ifdef CONFIG_CIFS_EXPERIMENTAL
626 else if (secFlags & CIFSSEC_MAY_PLNTXT)
627 server->secType = ??
628#endif */
629 else {
630 rc = -EOPNOTSUPP;
631 cERROR(1, ("Invalid security type"));
632 goto neg_err_exit;
633 }
634 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000635
Steve French254e55e2006-06-04 05:53:15 +0000636 /* one byte, so no need to convert this or EncryptionKeyLen from
637 little endian */
638 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
639 /* probably no need to store and check maxvcs */
640 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000642 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000643 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000644 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
645 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000646 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
647 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000648 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
649 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
650 CIFS_CRYPTO_KEY_SIZE);
651 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
652 && (pSMBr->EncryptionKeyLength == 0)) {
653 /* decode security blob */
654 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
655 rc = -EIO; /* no crypt key only if plain text pwd */
656 goto neg_err_exit;
657 }
658
659 /* BB might be helpful to save off the domain of server here */
660
Steve French50c2f752007-07-13 00:33:32 +0000661 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000662 (server->capabilities & CAP_EXTENDED_SECURITY)) {
663 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000664 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000666 goto neg_err_exit;
667 }
668
669 if (server->socketUseCount.counter > 1) {
670 if (memcmp(server->server_GUID,
671 pSMBr->u.extended_response.
672 GUID, 16) != 0) {
673 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000674 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000675 pSMBr->u.extended_response.GUID,
676 16);
677 }
678 } else
679 memcpy(server->server_GUID,
680 pSMBr->u.extended_response.GUID, 16);
681
682 if (count == 16) {
683 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000684 } else {
685 rc = decode_negTokenInit(pSMBr->u.extended_response.
686 SecurityBlob,
687 count - 16,
688 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000689 if (rc == 1) {
Jeff Laytone5459372007-11-03 05:11:06 +0000690 rc = 0;
Steve French254e55e2006-06-04 05:53:15 +0000691 } else {
692 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Steve French254e55e2006-06-04 05:53:15 +0000695 } else
696 server->capabilities &= ~CAP_EXTENDED_SECURITY;
697
Steve French6344a422006-06-12 04:18:35 +0000698#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000699signing_check:
Steve French6344a422006-06-12 04:18:35 +0000700#endif
Steve French762e5ab2007-06-28 18:41:42 +0000701 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
702 /* MUST_SIGN already includes the MAY_SIGN FLAG
703 so if this is zero it means that signing is disabled */
704 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000705 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000706 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000707 "packet signing to be enabled in "
708 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000709 rc = -EOPNOTSUPP;
710 }
Steve French50c2f752007-07-13 00:33:32 +0000711 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000712 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000713 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
714 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000715 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000716 if ((server->secMode &
717 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
718 cERROR(1,
719 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000720 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000721 } else
722 server->secMode |= SECMODE_SIGN_REQUIRED;
723 } else {
724 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000725 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000726 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000727 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 }
Steve French50c2f752007-07-13 00:33:32 +0000729
730neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700731 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000732
Steve French790fe572007-07-07 19:25:05 +0000733 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 return rc;
735}
736
737int
738CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
739{
740 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743 cFYI(1, ("In tree disconnect"));
744 /*
745 * If last user of the connection and
746 * connection alive - disconnect it
747 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000748 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 * to be freed and kernel thread woken up).
750 */
751 if (tcon)
752 down(&tcon->tconSem);
753 else
754 return -EIO;
755
756 atomic_dec(&tcon->useCount);
757 if (atomic_read(&tcon->useCount) > 0) {
758 up(&tcon->tconSem);
759 return -EBUSY;
760 }
761
Steve French50c2f752007-07-13 00:33:32 +0000762 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000764 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000766 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 }
768
Steve French790fe572007-07-07 19:25:05 +0000769 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 up(&tcon->tconSem);
771 return -EIO;
772 }
Steve French50c2f752007-07-13 00:33:32 +0000773 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700774 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (rc) {
776 up(&tcon->tconSem);
777 return rc;
Steve Frenchcd634992005-04-28 22:41:10 -0700778 }
Steve French133672e2007-11-13 22:41:37 +0000779
780 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700782 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 up(&tcon->tconSem);
785
Steve French50c2f752007-07-13 00:33:32 +0000786 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 closed on server already e.g. due to tcp session crashing */
788 if (rc == -EAGAIN)
789 rc = 0;
790
791 return rc;
792}
793
794int
795CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
796{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 LOGOFF_ANDX_REQ *pSMB;
798 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 cFYI(1, ("In SMBLogoff for session disconnect"));
801 if (ses)
802 down(&ses->sesSem);
803 else
804 return -EIO;
805
806 atomic_dec(&ses->inUse);
807 if (atomic_read(&ses->inUse) > 0) {
808 up(&ses->sesSem);
809 return -EBUSY;
810 }
811 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
812 if (rc) {
813 up(&ses->sesSem);
814 return rc;
815 }
816
Steve French790fe572007-07-07 19:25:05 +0000817 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700818 pSMB->hdr.Mid = GetNextMid(ses->server);
819
Steve French790fe572007-07-07 19:25:05 +0000820 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
822 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
823 }
824
825 pSMB->hdr.Uid = ses->Suid;
826
827 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000828 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (ses->server) {
830 atomic_dec(&ses->server->socketUseCount);
831 if (atomic_read(&ses->server->socketUseCount) == 0) {
832 spin_lock(&GlobalMid_Lock);
833 ses->server->tcpStatus = CifsExiting;
834 spin_unlock(&GlobalMid_Lock);
835 rc = -ESHUTDOWN;
836 }
837 }
Steve Frencha59c6582005-08-17 12:12:19 -0700838 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000841 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 error */
843 if (rc == -EAGAIN)
844 rc = 0;
845 return rc;
846}
847
848int
Steve French2d785a52007-07-15 01:48:57 +0000849CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
850 __u16 type, const struct nls_table *nls_codepage, int remap)
851{
852 TRANSACTION2_SPI_REQ *pSMB = NULL;
853 TRANSACTION2_SPI_RSP *pSMBr = NULL;
854 struct unlink_psx_rq *pRqD;
855 int name_len;
856 int rc = 0;
857 int bytes_returned = 0;
858 __u16 params, param_offset, offset, byte_count;
859
860 cFYI(1, ("In POSIX delete"));
861PsxDelete:
862 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
863 (void **) &pSMBr);
864 if (rc)
865 return rc;
866
867 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
868 name_len =
869 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
870 PATH_MAX, nls_codepage, remap);
871 name_len++; /* trailing null */
872 name_len *= 2;
873 } else { /* BB add path length overrun check */
874 name_len = strnlen(fileName, PATH_MAX);
875 name_len++; /* trailing null */
876 strncpy(pSMB->FileName, fileName, name_len);
877 }
878
879 params = 6 + name_len;
880 pSMB->MaxParameterCount = cpu_to_le16(2);
881 pSMB->MaxDataCount = 0; /* BB double check this with jra */
882 pSMB->MaxSetupCount = 0;
883 pSMB->Reserved = 0;
884 pSMB->Flags = 0;
885 pSMB->Timeout = 0;
886 pSMB->Reserved2 = 0;
887 param_offset = offsetof(struct smb_com_transaction2_spi_req,
888 InformationLevel) - 4;
889 offset = param_offset + params;
890
891 /* Setup pointer to Request Data (inode type) */
892 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
893 pRqD->type = cpu_to_le16(type);
894 pSMB->ParameterOffset = cpu_to_le16(param_offset);
895 pSMB->DataOffset = cpu_to_le16(offset);
896 pSMB->SetupCount = 1;
897 pSMB->Reserved3 = 0;
898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
899 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
900
901 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
902 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
903 pSMB->ParameterCount = cpu_to_le16(params);
904 pSMB->TotalParameterCount = pSMB->ParameterCount;
905 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
906 pSMB->Reserved4 = 0;
907 pSMB->hdr.smb_buf_length += byte_count;
908 pSMB->ByteCount = cpu_to_le16(byte_count);
909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000911 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000912 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000913 cifs_buf_release(pSMB);
914
915 cifs_stats_inc(&tcon->num_deletes);
916
917 if (rc == -EAGAIN)
918 goto PsxDelete;
919
920 return rc;
921}
922
923int
Steve French737b7582005-04-28 22:41:06 -0700924CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
925 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926{
927 DELETE_FILE_REQ *pSMB = NULL;
928 DELETE_FILE_RSP *pSMBr = NULL;
929 int rc = 0;
930 int bytes_returned;
931 int name_len;
932
933DelFileRetry:
934 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
935 (void **) &pSMBr);
936 if (rc)
937 return rc;
938
939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
940 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000941 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700942 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len++; /* trailing null */
944 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700945 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len = strnlen(fileName, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->fileName, fileName, name_len);
949 }
950 pSMB->SearchAttributes =
951 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
952 pSMB->BufferFormat = 0x04;
953 pSMB->hdr.smb_buf_length += name_len + 1;
954 pSMB->ByteCount = cpu_to_le16(name_len + 1);
955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700957 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000958 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 cifs_buf_release(pSMB);
962 if (rc == -EAGAIN)
963 goto DelFileRetry;
964
965 return rc;
966}
967
968int
Steve French50c2f752007-07-13 00:33:32 +0000969CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700970 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
972 DELETE_DIRECTORY_REQ *pSMB = NULL;
973 DELETE_DIRECTORY_RSP *pSMBr = NULL;
974 int rc = 0;
975 int bytes_returned;
976 int name_len;
977
978 cFYI(1, ("In CIFSSMBRmDir"));
979RmDirRetry:
980 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
981 (void **) &pSMBr);
982 if (rc)
983 return rc;
984
985 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700986 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
987 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 name_len++; /* trailing null */
989 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700990 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 name_len = strnlen(dirName, PATH_MAX);
992 name_len++; /* trailing null */
993 strncpy(pSMB->DirName, dirName, name_len);
994 }
995
996 pSMB->BufferFormat = 0x04;
997 pSMB->hdr.smb_buf_length += name_len + 1;
998 pSMB->ByteCount = cpu_to_le16(name_len + 1);
999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001001 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001002 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 cifs_buf_release(pSMB);
1006 if (rc == -EAGAIN)
1007 goto RmDirRetry;
1008 return rc;
1009}
1010
1011int
1012CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07001013 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014{
1015 int rc = 0;
1016 CREATE_DIRECTORY_REQ *pSMB = NULL;
1017 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1018 int bytes_returned;
1019 int name_len;
1020
1021 cFYI(1, ("In CIFSSMBMkDir"));
1022MkDirRetry:
1023 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1024 (void **) &pSMBr);
1025 if (rc)
1026 return rc;
1027
1028 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001029 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001030 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 name_len++; /* trailing null */
1032 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001033 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 name_len = strnlen(name, PATH_MAX);
1035 name_len++; /* trailing null */
1036 strncpy(pSMB->DirName, name, name_len);
1037 }
1038
1039 pSMB->BufferFormat = 0x04;
1040 pSMB->hdr.smb_buf_length += name_len + 1;
1041 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1042 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001044 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001045 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07001047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 cifs_buf_release(pSMB);
1049 if (rc == -EAGAIN)
1050 goto MkDirRetry;
1051 return rc;
1052}
1053
Steve French2dd29d32007-04-23 22:07:35 +00001054int
1055CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001056 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001057 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001058 const struct nls_table *nls_codepage, int remap)
1059{
1060 TRANSACTION2_SPI_REQ *pSMB = NULL;
1061 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1062 int name_len;
1063 int rc = 0;
1064 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001065 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001066 OPEN_PSX_REQ *pdata;
1067 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001068
1069 cFYI(1, ("In POSIX Create"));
1070PsxCreat:
1071 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1072 (void **) &pSMBr);
1073 if (rc)
1074 return rc;
1075
1076 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1077 name_len =
1078 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1079 PATH_MAX, nls_codepage, remap);
1080 name_len++; /* trailing null */
1081 name_len *= 2;
1082 } else { /* BB improve the check for buffer overruns BB */
1083 name_len = strnlen(name, PATH_MAX);
1084 name_len++; /* trailing null */
1085 strncpy(pSMB->FileName, name, name_len);
1086 }
1087
1088 params = 6 + name_len;
1089 count = sizeof(OPEN_PSX_REQ);
1090 pSMB->MaxParameterCount = cpu_to_le16(2);
1091 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1092 pSMB->MaxSetupCount = 0;
1093 pSMB->Reserved = 0;
1094 pSMB->Flags = 0;
1095 pSMB->Timeout = 0;
1096 pSMB->Reserved2 = 0;
1097 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001098 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001099 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001100 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001101 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001102 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001103 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001104 pdata->OpenFlags = cpu_to_le32(*pOplock);
1105 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1106 pSMB->DataOffset = cpu_to_le16(offset);
1107 pSMB->SetupCount = 1;
1108 pSMB->Reserved3 = 0;
1109 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1110 byte_count = 3 /* pad */ + params + count;
1111
1112 pSMB->DataCount = cpu_to_le16(count);
1113 pSMB->ParameterCount = cpu_to_le16(params);
1114 pSMB->TotalDataCount = pSMB->DataCount;
1115 pSMB->TotalParameterCount = pSMB->ParameterCount;
1116 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1117 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001118 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001119 pSMB->ByteCount = cpu_to_le16(byte_count);
1120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1121 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1122 if (rc) {
1123 cFYI(1, ("Posix create returned %d", rc));
1124 goto psx_create_err;
1125 }
1126
Steve French790fe572007-07-07 19:25:05 +00001127 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001128 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1129
1130 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1131 rc = -EIO; /* bad smb */
1132 goto psx_create_err;
1133 }
1134
1135 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001136 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001137 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001138
Steve French2dd29d32007-04-23 22:07:35 +00001139 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001140 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001141 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1142 /* Let caller know file was created so we can set the mode. */
1143 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001144 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001145 *pOplock |= CIFS_CREATE_ACTION;
1146 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001147 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1148 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001149 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001150 } else {
Steve French790fe572007-07-07 19:25:05 +00001151 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001152 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001153 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001154 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001155 goto psx_create_err;
1156 }
Steve French50c2f752007-07-13 00:33:32 +00001157 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001158 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001159 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001160 }
Steve French2dd29d32007-04-23 22:07:35 +00001161
1162psx_create_err:
1163 cifs_buf_release(pSMB);
1164
1165 cifs_stats_inc(&tcon->num_mkdirs);
1166
1167 if (rc == -EAGAIN)
1168 goto PsxCreat;
1169
Steve French50c2f752007-07-13 00:33:32 +00001170 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001171}
1172
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173static __u16 convert_disposition(int disposition)
1174{
1175 __u16 ofun = 0;
1176
1177 switch (disposition) {
1178 case FILE_SUPERSEDE:
1179 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1180 break;
1181 case FILE_OPEN:
1182 ofun = SMBOPEN_OAPPEND;
1183 break;
1184 case FILE_CREATE:
1185 ofun = SMBOPEN_OCREATE;
1186 break;
1187 case FILE_OPEN_IF:
1188 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1189 break;
1190 case FILE_OVERWRITE:
1191 ofun = SMBOPEN_OTRUNC;
1192 break;
1193 case FILE_OVERWRITE_IF:
1194 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1195 break;
1196 default:
Steve French790fe572007-07-07 19:25:05 +00001197 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001198 ofun = SMBOPEN_OAPPEND; /* regular open */
1199 }
1200 return ofun;
1201}
1202
Jeff Layton35fc37d2008-05-14 10:22:03 -07001203static int
1204access_flags_to_smbopen_mode(const int access_flags)
1205{
1206 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1207
1208 if (masked_flags == GENERIC_READ)
1209 return SMBOPEN_READ;
1210 else if (masked_flags == GENERIC_WRITE)
1211 return SMBOPEN_WRITE;
1212
1213 /* just go for read/write */
1214 return SMBOPEN_READWRITE;
1215}
1216
Steve Frencha9d02ad2005-08-24 23:06:05 -07001217int
1218SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1219 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001220 const int access_flags, const int create_options, __u16 *netfid,
1221 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222 const struct nls_table *nls_codepage, int remap)
1223{
1224 int rc = -EACCES;
1225 OPENX_REQ *pSMB = NULL;
1226 OPENX_RSP *pSMBr = NULL;
1227 int bytes_returned;
1228 int name_len;
1229 __u16 count;
1230
1231OldOpenRetry:
1232 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1233 (void **) &pSMBr);
1234 if (rc)
1235 return rc;
1236
1237 pSMB->AndXCommand = 0xFF; /* none */
1238
1239 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1240 count = 1; /* account for one byte pad to word boundary */
1241 name_len =
1242 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1243 fileName, PATH_MAX, nls_codepage, remap);
1244 name_len++; /* trailing null */
1245 name_len *= 2;
1246 } else { /* BB improve check for buffer overruns BB */
1247 count = 0; /* no pad */
1248 name_len = strnlen(fileName, PATH_MAX);
1249 name_len++; /* trailing null */
1250 strncpy(pSMB->fileName, fileName, name_len);
1251 }
1252 if (*pOplock & REQ_OPLOCK)
1253 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001254 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001256
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001258 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1260 /* set file as system file if special file such
1261 as fifo and server expecting SFU style and
1262 no Unix extensions */
1263
Steve French790fe572007-07-07 19:25:05 +00001264 if (create_options & CREATE_OPTION_SPECIAL)
1265 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001266 else /* BB FIXME BB */
1267 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268
Jeff Layton67750fb2008-05-09 22:28:02 +00001269 if (create_options & CREATE_OPTION_READONLY)
1270 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271
1272 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001273/* pSMB->CreateOptions = cpu_to_le32(create_options &
1274 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001276
1277 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001278 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 count += name_len;
1280 pSMB->hdr.smb_buf_length += count;
1281
1282 pSMB->ByteCount = cpu_to_le16(count);
1283 /* long_op set to 1 to allow for oplock break timeouts */
1284 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001285 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001286 cifs_stats_inc(&tcon->num_opens);
1287 if (rc) {
1288 cFYI(1, ("Error in Open = %d", rc));
1289 } else {
1290 /* BB verify if wct == 15 */
1291
Steve French582d21e2008-05-13 04:54:12 +00001292/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001293
1294 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1295 /* Let caller know file was created so we can set the mode. */
1296 /* Do we care about the CreateAction in any other cases? */
1297 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001298/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001299 *pOplock |= CIFS_CREATE_ACTION; */
1300 /* BB FIXME END */
1301
Steve French790fe572007-07-07 19:25:05 +00001302 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001303 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1304 pfile_info->LastAccessTime = 0; /* BB fixme */
1305 pfile_info->LastWriteTime = 0; /* BB fixme */
1306 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001307 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001308 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001309 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001310 pfile_info->AllocationSize =
1311 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1312 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001313 pfile_info->NumberOfLinks = cpu_to_le32(1);
1314 }
1315 }
1316
1317 cifs_buf_release(pSMB);
1318 if (rc == -EAGAIN)
1319 goto OldOpenRetry;
1320 return rc;
1321}
1322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323int
1324CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1325 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001326 const int access_flags, const int create_options, __u16 *netfid,
1327 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001328 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329{
1330 int rc = -EACCES;
1331 OPEN_REQ *pSMB = NULL;
1332 OPEN_RSP *pSMBr = NULL;
1333 int bytes_returned;
1334 int name_len;
1335 __u16 count;
1336
1337openRetry:
1338 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1339 (void **) &pSMBr);
1340 if (rc)
1341 return rc;
1342
1343 pSMB->AndXCommand = 0xFF; /* none */
1344
1345 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1346 count = 1; /* account for one byte pad to word boundary */
1347 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001348 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001349 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 name_len++; /* trailing null */
1351 name_len *= 2;
1352 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001353 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 count = 0; /* no pad */
1355 name_len = strnlen(fileName, PATH_MAX);
1356 name_len++; /* trailing null */
1357 pSMB->NameLength = cpu_to_le16(name_len);
1358 strncpy(pSMB->fileName, fileName, name_len);
1359 }
1360 if (*pOplock & REQ_OPLOCK)
1361 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001362 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1365 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001366 /* set file as system file if special file such
1367 as fifo and server expecting SFU style and
1368 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001369 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001370 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1371 else
1372 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 /* XP does not handle ATTR_POSIX_SEMANTICS */
1375 /* but it helps speed up case sensitive checks for other
1376 servers such as Samba */
1377 if (tcon->ses->capabilities & CAP_UNIX)
1378 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1379
Jeff Layton67750fb2008-05-09 22:28:02 +00001380 if (create_options & CREATE_OPTION_READONLY)
1381 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1382
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1384 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001385 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001386 /* BB Expirement with various impersonation levels and verify */
1387 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 pSMB->SecurityFlags =
1389 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1390
1391 count += name_len;
1392 pSMB->hdr.smb_buf_length += count;
1393
1394 pSMB->ByteCount = cpu_to_le16(count);
1395 /* long_op set to 1 to allow for oplock break timeouts */
1396 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001397 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001398 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 if (rc) {
1400 cFYI(1, ("Error in Open = %d", rc));
1401 } else {
Steve French09d1db52005-04-28 22:41:08 -07001402 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1404 /* Let caller know file was created so we can set the mode. */
1405 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001406 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001407 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001408 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001409 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 36 /* CreationTime to Attributes */);
1411 /* the file_info buf is endian converted by caller */
1412 pfile_info->AllocationSize = pSMBr->AllocationSize;
1413 pfile_info->EndOfFile = pSMBr->EndOfFile;
1414 pfile_info->NumberOfLinks = cpu_to_le32(1);
1415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 cifs_buf_release(pSMB);
1419 if (rc == -EAGAIN)
1420 goto openRetry;
1421 return rc;
1422}
1423
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424int
Steve French50c2f752007-07-13 00:33:32 +00001425CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1426 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1427 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428{
1429 int rc = -EACCES;
1430 READ_REQ *pSMB = NULL;
1431 READ_RSP *pSMBr = NULL;
1432 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001433 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001434 int resp_buf_type = 0;
1435 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
Steve French790fe572007-07-07 19:25:05 +00001437 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1438 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001439 wct = 12;
1440 else
1441 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
1443 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001444 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 if (rc)
1446 return rc;
1447
1448 /* tcon and ses pointer are checked in smb_init */
1449 if (tcon->ses->server == NULL)
1450 return -ECONNABORTED;
1451
Steve Frenchec637e32005-12-12 20:53:18 -08001452 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 pSMB->Fid = netfid;
1454 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001455 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001456 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001457 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001458 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 pSMB->Remaining = 0;
1461 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1462 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001463 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001464 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1465 else {
1466 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001467 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001468 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001469 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001470 }
Steve Frenchec637e32005-12-12 20:53:18 -08001471
1472 iov[0].iov_base = (char *)pSMB;
1473 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001474 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001475 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001476 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001477 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 if (rc) {
1479 cERROR(1, ("Send error in read = %d", rc));
1480 } else {
1481 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1482 data_length = data_length << 16;
1483 data_length += le16_to_cpu(pSMBr->DataLength);
1484 *nbytes = data_length;
1485
1486 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001487 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001489 cFYI(1, ("bad length %d for count %d",
1490 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 rc = -EIO;
1492 *nbytes = 0;
1493 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001494 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001495 le16_to_cpu(pSMBr->DataOffset);
1496/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001497 cERROR(1,("Faulting on read rc = %d",rc));
1498 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001499 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001500 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001501 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 }
1503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
Steve French4b8f9302006-02-26 16:41:18 +00001505/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001506 if (*buf) {
1507 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001508 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001509 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001510 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001511 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001512 /* return buffer to caller to free */
1513 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001514 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001515 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001516 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001517 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001518 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001519
1520 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 since file handle passed in no longer valid */
1522 return rc;
1523}
1524
Steve Frenchec637e32005-12-12 20:53:18 -08001525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526int
1527CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1528 const int netfid, const unsigned int count,
1529 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001530 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531{
1532 int rc = -EACCES;
1533 WRITE_REQ *pSMB = NULL;
1534 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001535 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 __u32 bytes_sent;
1537 __u16 byte_count;
1538
1539 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001540 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001541 return -ECONNABORTED;
1542
Steve French790fe572007-07-07 19:25:05 +00001543 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001544 wct = 14;
1545 else
1546 wct = 12;
1547
1548 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 (void **) &pSMBr);
1550 if (rc)
1551 return rc;
1552 /* tcon and ses pointer are checked in smb_init */
1553 if (tcon->ses->server == NULL)
1554 return -ECONNABORTED;
1555
1556 pSMB->AndXCommand = 0xFF; /* none */
1557 pSMB->Fid = netfid;
1558 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001559 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001560 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001561 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001562 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001563
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 pSMB->Reserved = 0xFFFFFFFF;
1565 pSMB->WriteMode = 0;
1566 pSMB->Remaining = 0;
1567
Steve French50c2f752007-07-13 00:33:32 +00001568 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 can send more if LARGE_WRITE_X capability returned by the server and if
1570 our buffer is big enough or if we convert to iovecs on socket writes
1571 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001572 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1574 } else {
1575 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1576 & ~0xFF;
1577 }
1578
1579 if (bytes_sent > count)
1580 bytes_sent = count;
1581 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001582 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001583 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001584 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001585 else if (ubuf) {
1586 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 cifs_buf_release(pSMB);
1588 return -EFAULT;
1589 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001590 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 /* No buffer */
1592 cifs_buf_release(pSMB);
1593 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001594 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001595 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001596 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001597 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001598 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001599
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1601 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001602 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001603
Steve French790fe572007-07-07 19:25:05 +00001604 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001605 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001606 else { /* old style write has byte count 4 bytes earlier
1607 so 4 bytes pad */
1608 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001609 (struct smb_com_writex_req *)pSMB;
1610 pSMBW->ByteCount = cpu_to_le16(byte_count);
1611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
1613 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1614 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001615 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 if (rc) {
1617 cFYI(1, ("Send error in write = %d", rc));
1618 *nbytes = 0;
1619 } else {
1620 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1621 *nbytes = (*nbytes) << 16;
1622 *nbytes += le16_to_cpu(pSMBr->Count);
1623 }
1624
1625 cifs_buf_release(pSMB);
1626
Steve French50c2f752007-07-13 00:33:32 +00001627 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 since file handle passed in no longer valid */
1629
1630 return rc;
1631}
1632
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001633int
1634CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001636 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1637 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638{
1639 int rc = -EACCES;
1640 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001641 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001642 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001643 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
Steve French790fe572007-07-07 19:25:05 +00001645 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001646
Steve French790fe572007-07-07 19:25:05 +00001647 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001648 wct = 14;
1649 else
1650 wct = 12;
1651 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 if (rc)
1653 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 /* tcon and ses pointer are checked in smb_init */
1655 if (tcon->ses->server == NULL)
1656 return -ECONNABORTED;
1657
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001658 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 pSMB->Fid = netfid;
1660 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001661 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001662 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001663 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001664 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 pSMB->Reserved = 0xFFFFFFFF;
1666 pSMB->WriteMode = 0;
1667 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001670 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
Steve French3e844692005-10-03 13:37:24 -07001672 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1673 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001674 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001675 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001676 pSMB->hdr.smb_buf_length += count+1;
1677 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001678 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1679 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001680 pSMB->ByteCount = cpu_to_le16(count + 1);
1681 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001682 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001683 (struct smb_com_writex_req *)pSMB;
1684 pSMBW->ByteCount = cpu_to_le16(count + 5);
1685 }
Steve French3e844692005-10-03 13:37:24 -07001686 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001687 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001688 iov[0].iov_len = smb_hdr_len + 4;
1689 else /* wct == 12 pad bigger by four bytes */
1690 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001691
Steve French3e844692005-10-03 13:37:24 -07001692
Steve Frenchec637e32005-12-12 20:53:18 -08001693 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001694 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001695 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001697 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001699 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001700 /* presumably this can not happen, but best to be safe */
1701 rc = -EIO;
1702 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001703 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001704 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001705 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1706 *nbytes = (*nbytes) << 16;
1707 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
Steve French4b8f9302006-02-26 16:41:18 +00001710/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001711 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001712 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001713 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001714 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715
Steve French50c2f752007-07-13 00:33:32 +00001716 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 since file handle passed in no longer valid */
1718
1719 return rc;
1720}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001721
1722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723int
1724CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1725 const __u16 smb_file_id, const __u64 len,
1726 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001727 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728{
1729 int rc = 0;
1730 LOCK_REQ *pSMB = NULL;
1731 LOCK_RSP *pSMBr = NULL;
1732 int bytes_returned;
1733 int timeout = 0;
1734 __u16 count;
1735
Steve French4b18f2a2008-04-29 00:06:05 +00001736 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001737 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1738
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 if (rc)
1740 return rc;
1741
Steve French46810cb2005-04-28 22:41:09 -07001742 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1743
Steve French790fe572007-07-07 19:25:05 +00001744 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001745 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001747 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001748 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1750 } else {
1751 pSMB->Timeout = 0;
1752 }
1753
1754 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1755 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1756 pSMB->LockType = lockType;
1757 pSMB->AndXCommand = 0xFF; /* none */
1758 pSMB->Fid = smb_file_id; /* netfid stays le */
1759
Steve French790fe572007-07-07 19:25:05 +00001760 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1762 /* BB where to store pid high? */
1763 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1764 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1765 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1766 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1767 count = sizeof(LOCKING_ANDX_RANGE);
1768 } else {
1769 /* oplock break */
1770 count = 0;
1771 }
1772 pSMB->hdr.smb_buf_length += count;
1773 pSMB->ByteCount = cpu_to_le16(count);
1774
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001775 if (waitFlag) {
1776 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1777 (struct smb_hdr *) pSMBr, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001778 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001779 } else {
Steve French133672e2007-11-13 22:41:37 +00001780 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1781 timeout);
1782 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001783 }
Steve Frencha4544342005-08-24 13:59:35 -07001784 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001785 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
Steve French50c2f752007-07-13 00:33:32 +00001788 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 since file handle passed in no longer valid */
1790 return rc;
1791}
1792
1793int
Steve French08547b02006-02-28 22:39:25 +00001794CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1795 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001796 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001797 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001798{
1799 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1800 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001801 struct cifs_posix_lock *parm_data;
1802 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001803 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001804 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001805 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001806 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001807 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001808
1809 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001810
Steve French790fe572007-07-07 19:25:05 +00001811 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001812 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001813
Steve French08547b02006-02-28 22:39:25 +00001814 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1815
1816 if (rc)
1817 return rc;
1818
1819 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1820
Steve French50c2f752007-07-13 00:33:32 +00001821 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001822 pSMB->MaxSetupCount = 0;
1823 pSMB->Reserved = 0;
1824 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001825 pSMB->Reserved2 = 0;
1826 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1827 offset = param_offset + params;
1828
Steve French08547b02006-02-28 22:39:25 +00001829 count = sizeof(struct cifs_posix_lock);
1830 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001831 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001832 pSMB->SetupCount = 1;
1833 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001834 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001835 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1836 else
1837 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1838 byte_count = 3 /* pad */ + params + count;
1839 pSMB->DataCount = cpu_to_le16(count);
1840 pSMB->ParameterCount = cpu_to_le16(params);
1841 pSMB->TotalDataCount = pSMB->DataCount;
1842 pSMB->TotalParameterCount = pSMB->ParameterCount;
1843 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001844 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001845 (((char *) &pSMB->hdr.Protocol) + offset);
1846
1847 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001848 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001849 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001850 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001851 pSMB->Timeout = cpu_to_le32(-1);
1852 } else
1853 pSMB->Timeout = 0;
1854
Steve French08547b02006-02-28 22:39:25 +00001855 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001856 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001857 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001858
1859 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001860 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001861 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1862 pSMB->Reserved4 = 0;
1863 pSMB->hdr.smb_buf_length += byte_count;
1864 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001865 if (waitFlag) {
1866 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1867 (struct smb_hdr *) pSMBr, &bytes_returned);
1868 } else {
Steve French133672e2007-11-13 22:41:37 +00001869 iov[0].iov_base = (char *)pSMB;
1870 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1871 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1872 &resp_buf_type, timeout);
1873 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1874 not try to free it twice below on exit */
1875 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001876 }
1877
Steve French08547b02006-02-28 22:39:25 +00001878 if (rc) {
1879 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001880 } else if (get_flag) {
1881 /* lock structure can be returned on get */
1882 __u16 data_offset;
1883 __u16 data_count;
1884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001885
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001886 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1887 rc = -EIO; /* bad smb */
1888 goto plk_err_exit;
1889 }
Steve French790fe572007-07-07 19:25:05 +00001890 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001891 rc = -EINVAL;
1892 goto plk_err_exit;
1893 }
1894 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1895 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001896 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001897 rc = -EIO;
1898 goto plk_err_exit;
1899 }
1900 parm_data = (struct cifs_posix_lock *)
1901 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001902 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001903 pLockData->fl_type = F_UNLCK;
1904 }
Steve French50c2f752007-07-13 00:33:32 +00001905
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001906plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001907 if (pSMB)
1908 cifs_small_buf_release(pSMB);
1909
Steve French133672e2007-11-13 22:41:37 +00001910 if (resp_buf_type == CIFS_SMALL_BUFFER)
1911 cifs_small_buf_release(iov[0].iov_base);
1912 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1913 cifs_buf_release(iov[0].iov_base);
1914
Steve French08547b02006-02-28 22:39:25 +00001915 /* Note: On -EAGAIN error only caller can retry on handle based calls
1916 since file handle passed in no longer valid */
1917
1918 return rc;
1919}
1920
1921
1922int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1924{
1925 int rc = 0;
1926 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 cFYI(1, ("In CIFSSMBClose"));
1928
1929/* do not retry on dead session on close */
1930 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001931 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 return 0;
1933 if (rc)
1934 return rc;
1935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001937 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001939 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001940 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001942 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 /* EINTR is expected when user ctl-c to kill app */
1944 cERROR(1, ("Send error in Close = %d", rc));
1945 }
1946 }
1947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001949 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 rc = 0;
1951
1952 return rc;
1953}
1954
1955int
1956CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1957 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001958 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959{
1960 int rc = 0;
1961 RENAME_REQ *pSMB = NULL;
1962 RENAME_RSP *pSMBr = NULL;
1963 int bytes_returned;
1964 int name_len, name_len2;
1965 __u16 count;
1966
1967 cFYI(1, ("In CIFSSMBRename"));
1968renameRetry:
1969 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1970 (void **) &pSMBr);
1971 if (rc)
1972 return rc;
1973
1974 pSMB->BufferFormat = 0x04;
1975 pSMB->SearchAttributes =
1976 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1977 ATTR_DIRECTORY);
1978
1979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1980 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001981 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 name_len++; /* trailing null */
1984 name_len *= 2;
1985 pSMB->OldFileName[name_len] = 0x04; /* pad */
1986 /* protocol requires ASCII signature byte on Unicode string */
1987 pSMB->OldFileName[name_len + 1] = 0x00;
1988 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001989 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001990 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1992 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001993 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 name_len = strnlen(fromName, PATH_MAX);
1995 name_len++; /* trailing null */
1996 strncpy(pSMB->OldFileName, fromName, name_len);
1997 name_len2 = strnlen(toName, PATH_MAX);
1998 name_len2++; /* trailing null */
1999 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2000 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2001 name_len2++; /* trailing null */
2002 name_len2++; /* signature byte */
2003 }
2004
2005 count = 1 /* 1st signature byte */ + name_len + name_len2;
2006 pSMB->hdr.smb_buf_length += count;
2007 pSMB->ByteCount = cpu_to_le16(count);
2008
2009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002011 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002012 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 cifs_buf_release(pSMB);
2016
2017 if (rc == -EAGAIN)
2018 goto renameRetry;
2019
2020 return rc;
2021}
2022
Steve French50c2f752007-07-13 00:33:32 +00002023int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2024 int netfid, char *target_name,
2025 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026{
2027 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2028 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002029 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 char *data_offset;
2031 char dummy_string[30];
2032 int rc = 0;
2033 int bytes_returned = 0;
2034 int len_of_str;
2035 __u16 params, param_offset, offset, count, byte_count;
2036
2037 cFYI(1, ("Rename to File by handle"));
2038 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2039 (void **) &pSMBr);
2040 if (rc)
2041 return rc;
2042
2043 params = 6;
2044 pSMB->MaxSetupCount = 0;
2045 pSMB->Reserved = 0;
2046 pSMB->Flags = 0;
2047 pSMB->Timeout = 0;
2048 pSMB->Reserved2 = 0;
2049 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2050 offset = param_offset + params;
2051
2052 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2053 rename_info = (struct set_file_rename *) data_offset;
2054 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002055 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 pSMB->SetupCount = 1;
2057 pSMB->Reserved3 = 0;
2058 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2059 byte_count = 3 /* pad */ + params;
2060 pSMB->ParameterCount = cpu_to_le16(params);
2061 pSMB->TotalParameterCount = pSMB->ParameterCount;
2062 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2063 pSMB->DataOffset = cpu_to_le16(offset);
2064 /* construct random name ".cifs_tmp<inodenum><mid>" */
2065 rename_info->overwrite = cpu_to_le32(1);
2066 rename_info->root_fid = 0;
2067 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002068 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002069 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2070 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002071 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002073 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002074 target_name, PATH_MAX, nls_codepage,
2075 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 }
2077 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2078 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2079 byte_count += count;
2080 pSMB->DataCount = cpu_to_le16(count);
2081 pSMB->TotalDataCount = pSMB->DataCount;
2082 pSMB->Fid = netfid;
2083 pSMB->InformationLevel =
2084 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2085 pSMB->Reserved4 = 0;
2086 pSMB->hdr.smb_buf_length += byte_count;
2087 pSMB->ByteCount = cpu_to_le16(byte_count);
2088 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002089 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002090 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002091 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002092 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002093
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 cifs_buf_release(pSMB);
2095
2096 /* Note: On -EAGAIN error only caller can retry on handle based calls
2097 since file handle passed in no longer valid */
2098
2099 return rc;
2100}
2101
2102int
Steve French50c2f752007-07-13 00:33:32 +00002103CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2104 const __u16 target_tid, const char *toName, const int flags,
2105 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106{
2107 int rc = 0;
2108 COPY_REQ *pSMB = NULL;
2109 COPY_RSP *pSMBr = NULL;
2110 int bytes_returned;
2111 int name_len, name_len2;
2112 __u16 count;
2113
2114 cFYI(1, ("In CIFSSMBCopy"));
2115copyRetry:
2116 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2117 (void **) &pSMBr);
2118 if (rc)
2119 return rc;
2120
2121 pSMB->BufferFormat = 0x04;
2122 pSMB->Tid2 = target_tid;
2123
2124 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2125
2126 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002127 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002128 fromName, PATH_MAX, nls_codepage,
2129 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 name_len++; /* trailing null */
2131 name_len *= 2;
2132 pSMB->OldFileName[name_len] = 0x04; /* pad */
2133 /* protocol requires ASCII signature byte on Unicode string */
2134 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002135 name_len2 =
2136 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002137 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2139 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002140 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 name_len = strnlen(fromName, PATH_MAX);
2142 name_len++; /* trailing null */
2143 strncpy(pSMB->OldFileName, fromName, name_len);
2144 name_len2 = strnlen(toName, PATH_MAX);
2145 name_len2++; /* trailing null */
2146 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2147 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2148 name_len2++; /* trailing null */
2149 name_len2++; /* signature byte */
2150 }
2151
2152 count = 1 /* 1st signature byte */ + name_len + name_len2;
2153 pSMB->hdr.smb_buf_length += count;
2154 pSMB->ByteCount = cpu_to_le16(count);
2155
2156 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2157 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2158 if (rc) {
2159 cFYI(1, ("Send error in copy = %d with %d files copied",
2160 rc, le16_to_cpu(pSMBr->CopyCount)));
2161 }
Steve French0d817bc2008-05-22 02:02:03 +00002162 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163
2164 if (rc == -EAGAIN)
2165 goto copyRetry;
2166
2167 return rc;
2168}
2169
2170int
2171CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2172 const char *fromName, const char *toName,
2173 const struct nls_table *nls_codepage)
2174{
2175 TRANSACTION2_SPI_REQ *pSMB = NULL;
2176 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2177 char *data_offset;
2178 int name_len;
2179 int name_len_target;
2180 int rc = 0;
2181 int bytes_returned = 0;
2182 __u16 params, param_offset, offset, byte_count;
2183
2184 cFYI(1, ("In Symlink Unix style"));
2185createSymLinkRetry:
2186 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2187 (void **) &pSMBr);
2188 if (rc)
2189 return rc;
2190
2191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2192 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002193 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 /* find define for this maxpathcomponent */
2195 , nls_codepage);
2196 name_len++; /* trailing null */
2197 name_len *= 2;
2198
Steve French50c2f752007-07-13 00:33:32 +00002199 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 name_len = strnlen(fromName, PATH_MAX);
2201 name_len++; /* trailing null */
2202 strncpy(pSMB->FileName, fromName, name_len);
2203 }
2204 params = 6 + name_len;
2205 pSMB->MaxSetupCount = 0;
2206 pSMB->Reserved = 0;
2207 pSMB->Flags = 0;
2208 pSMB->Timeout = 0;
2209 pSMB->Reserved2 = 0;
2210 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002211 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 offset = param_offset + params;
2213
2214 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2216 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002217 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 /* find define for this maxpathcomponent */
2219 , nls_codepage);
2220 name_len_target++; /* trailing null */
2221 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002222 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 name_len_target = strnlen(toName, PATH_MAX);
2224 name_len_target++; /* trailing null */
2225 strncpy(data_offset, toName, name_len_target);
2226 }
2227
2228 pSMB->MaxParameterCount = cpu_to_le16(2);
2229 /* BB find exact max on data count below from sess */
2230 pSMB->MaxDataCount = cpu_to_le16(1000);
2231 pSMB->SetupCount = 1;
2232 pSMB->Reserved3 = 0;
2233 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2234 byte_count = 3 /* pad */ + params + name_len_target;
2235 pSMB->DataCount = cpu_to_le16(name_len_target);
2236 pSMB->ParameterCount = cpu_to_le16(params);
2237 pSMB->TotalDataCount = pSMB->DataCount;
2238 pSMB->TotalParameterCount = pSMB->ParameterCount;
2239 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2240 pSMB->DataOffset = cpu_to_le16(offset);
2241 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2242 pSMB->Reserved4 = 0;
2243 pSMB->hdr.smb_buf_length += byte_count;
2244 pSMB->ByteCount = cpu_to_le16(byte_count);
2245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2246 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002247 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002248 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002249 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Steve French0d817bc2008-05-22 02:02:03 +00002251 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
2253 if (rc == -EAGAIN)
2254 goto createSymLinkRetry;
2255
2256 return rc;
2257}
2258
2259int
2260CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2261 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002262 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263{
2264 TRANSACTION2_SPI_REQ *pSMB = NULL;
2265 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2266 char *data_offset;
2267 int name_len;
2268 int name_len_target;
2269 int rc = 0;
2270 int bytes_returned = 0;
2271 __u16 params, param_offset, offset, byte_count;
2272
2273 cFYI(1, ("In Create Hard link Unix style"));
2274createHardLinkRetry:
2275 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2276 (void **) &pSMBr);
2277 if (rc)
2278 return rc;
2279
2280 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002281 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002282 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 name_len++; /* trailing null */
2284 name_len *= 2;
2285
Steve French50c2f752007-07-13 00:33:32 +00002286 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 name_len = strnlen(toName, PATH_MAX);
2288 name_len++; /* trailing null */
2289 strncpy(pSMB->FileName, toName, name_len);
2290 }
2291 params = 6 + name_len;
2292 pSMB->MaxSetupCount = 0;
2293 pSMB->Reserved = 0;
2294 pSMB->Flags = 0;
2295 pSMB->Timeout = 0;
2296 pSMB->Reserved2 = 0;
2297 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002298 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 offset = param_offset + params;
2300
2301 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2302 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2303 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002304 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002305 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 name_len_target++; /* trailing null */
2307 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002308 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 name_len_target = strnlen(fromName, PATH_MAX);
2310 name_len_target++; /* trailing null */
2311 strncpy(data_offset, fromName, name_len_target);
2312 }
2313
2314 pSMB->MaxParameterCount = cpu_to_le16(2);
2315 /* BB find exact max on data count below from sess*/
2316 pSMB->MaxDataCount = cpu_to_le16(1000);
2317 pSMB->SetupCount = 1;
2318 pSMB->Reserved3 = 0;
2319 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2320 byte_count = 3 /* pad */ + params + name_len_target;
2321 pSMB->ParameterCount = cpu_to_le16(params);
2322 pSMB->TotalParameterCount = pSMB->ParameterCount;
2323 pSMB->DataCount = cpu_to_le16(name_len_target);
2324 pSMB->TotalDataCount = pSMB->DataCount;
2325 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2326 pSMB->DataOffset = cpu_to_le16(offset);
2327 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2328 pSMB->Reserved4 = 0;
2329 pSMB->hdr.smb_buf_length += byte_count;
2330 pSMB->ByteCount = cpu_to_le16(byte_count);
2331 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2332 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002333 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002334 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
2337 cifs_buf_release(pSMB);
2338 if (rc == -EAGAIN)
2339 goto createHardLinkRetry;
2340
2341 return rc;
2342}
2343
2344int
2345CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2346 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002347 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348{
2349 int rc = 0;
2350 NT_RENAME_REQ *pSMB = NULL;
2351 RENAME_RSP *pSMBr = NULL;
2352 int bytes_returned;
2353 int name_len, name_len2;
2354 __u16 count;
2355
2356 cFYI(1, ("In CIFSCreateHardLink"));
2357winCreateHardLinkRetry:
2358
2359 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2360 (void **) &pSMBr);
2361 if (rc)
2362 return rc;
2363
2364 pSMB->SearchAttributes =
2365 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2366 ATTR_DIRECTORY);
2367 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2368 pSMB->ClusterCount = 0;
2369
2370 pSMB->BufferFormat = 0x04;
2371
2372 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2373 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002374 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002375 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 name_len++; /* trailing null */
2377 name_len *= 2;
2378 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002379 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002381 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002382 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2384 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002385 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 name_len = strnlen(fromName, PATH_MAX);
2387 name_len++; /* trailing null */
2388 strncpy(pSMB->OldFileName, fromName, name_len);
2389 name_len2 = strnlen(toName, PATH_MAX);
2390 name_len2++; /* trailing null */
2391 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2392 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2393 name_len2++; /* trailing null */
2394 name_len2++; /* signature byte */
2395 }
2396
2397 count = 1 /* string type byte */ + name_len + name_len2;
2398 pSMB->hdr.smb_buf_length += count;
2399 pSMB->ByteCount = cpu_to_le16(count);
2400
2401 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2402 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002403 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002404 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002406
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 cifs_buf_release(pSMB);
2408 if (rc == -EAGAIN)
2409 goto winCreateHardLinkRetry;
2410
2411 return rc;
2412}
2413
2414int
2415CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2416 const unsigned char *searchName,
2417 char *symlinkinfo, const int buflen,
2418 const struct nls_table *nls_codepage)
2419{
2420/* SMB_QUERY_FILE_UNIX_LINK */
2421 TRANSACTION2_QPI_REQ *pSMB = NULL;
2422 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2423 int rc = 0;
2424 int bytes_returned;
2425 int name_len;
2426 __u16 params, byte_count;
2427
2428 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2429
2430querySymLinkRetry:
2431 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2432 (void **) &pSMBr);
2433 if (rc)
2434 return rc;
2435
2436 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2437 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002438 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2439 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 name_len++; /* trailing null */
2441 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002442 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 name_len = strnlen(searchName, PATH_MAX);
2444 name_len++; /* trailing null */
2445 strncpy(pSMB->FileName, searchName, name_len);
2446 }
2447
2448 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2449 pSMB->TotalDataCount = 0;
2450 pSMB->MaxParameterCount = cpu_to_le16(2);
2451 /* BB find exact max data count below from sess structure BB */
2452 pSMB->MaxDataCount = cpu_to_le16(4000);
2453 pSMB->MaxSetupCount = 0;
2454 pSMB->Reserved = 0;
2455 pSMB->Flags = 0;
2456 pSMB->Timeout = 0;
2457 pSMB->Reserved2 = 0;
2458 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002459 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 pSMB->DataCount = 0;
2461 pSMB->DataOffset = 0;
2462 pSMB->SetupCount = 1;
2463 pSMB->Reserved3 = 0;
2464 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2465 byte_count = params + 1 /* pad */ ;
2466 pSMB->TotalParameterCount = cpu_to_le16(params);
2467 pSMB->ParameterCount = pSMB->TotalParameterCount;
2468 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2469 pSMB->Reserved4 = 0;
2470 pSMB->hdr.smb_buf_length += byte_count;
2471 pSMB->ByteCount = cpu_to_le16(byte_count);
2472
2473 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2474 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2475 if (rc) {
2476 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2477 } else {
2478 /* decode response */
2479
2480 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2481 if (rc || (pSMBr->ByteCount < 2))
2482 /* BB also check enough total bytes returned */
2483 rc = -EIO; /* bad smb */
2484 else {
2485 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2486 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2487
2488 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2489 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002490 &pSMBr->hdr.Protocol + data_offset),
2491 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002492 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002494 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2495 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 name_len, nls_codepage);
2497 } else {
2498 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002499 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 data_offset,
2501 min_t(const int, buflen, count));
2502 }
2503 symlinkinfo[buflen] = 0;
2504 /* just in case so calling code does not go off the end of buffer */
2505 }
2506 }
2507 cifs_buf_release(pSMB);
2508 if (rc == -EAGAIN)
2509 goto querySymLinkRetry;
2510 return rc;
2511}
2512
Parag Warudkarc9489772007-10-23 18:09:48 +00002513#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002514/* Initialize NT TRANSACT SMB into small smb request buffer.
2515 This assumes that all NT TRANSACTS that we init here have
2516 total parm and data under about 400 bytes (to fit in small cifs
2517 buffer size), which is the case so far, it easily fits. NB:
2518 Setup words themselves and ByteCount
2519 MaxSetupCount (size of returned setup area) and
2520 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002521static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002522smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002523 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002524 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002525{
2526 int rc;
2527 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002528 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002529
2530 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2531 (void **)&pSMB);
2532 if (rc)
2533 return rc;
2534 *ret_buf = (void *)pSMB;
2535 pSMB->Reserved = 0;
2536 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2537 pSMB->TotalDataCount = 0;
2538 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2539 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2540 pSMB->ParameterCount = pSMB->TotalParameterCount;
2541 pSMB->DataCount = pSMB->TotalDataCount;
2542 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2543 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2544 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2545 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2546 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2547 pSMB->SubCommand = cpu_to_le16(sub_command);
2548 return 0;
2549}
2550
2551static int
Steve French50c2f752007-07-13 00:33:32 +00002552validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002553 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002554{
Steve French50c2f752007-07-13 00:33:32 +00002555 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002556 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002557 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002558
Steve French630f3f0c2007-10-25 21:17:17 +00002559 *pdatalen = 0;
2560 *pparmlen = 0;
2561
Steve French790fe572007-07-07 19:25:05 +00002562 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002563 return -EINVAL;
2564
2565 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2566
2567 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002568 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002569 (char *)&pSMBr->ByteCount;
2570
Steve French0a4b92c2006-01-12 15:44:21 -08002571 data_offset = le32_to_cpu(pSMBr->DataOffset);
2572 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002573 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002574 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2575
2576 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2577 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2578
2579 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002580 if (*ppparm > end_of_smb) {
2581 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002582 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002583 } else if (parm_count + *ppparm > end_of_smb) {
2584 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002585 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002586 } else if (*ppdata > end_of_smb) {
2587 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002588 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002589 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002590 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002591 *ppdata, data_count, (data_count + *ppdata),
2592 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002593 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002594 } else if (parm_count + data_count > pSMBr->ByteCount) {
2595 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002596 return -EINVAL;
2597 }
Steve French630f3f0c2007-10-25 21:17:17 +00002598 *pdatalen = data_count;
2599 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002600 return 0;
2601}
Parag Warudkarc9489772007-10-23 18:09:48 +00002602#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604int
2605CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2606 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002607 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 const struct nls_table *nls_codepage)
2609{
2610 int rc = 0;
2611 int bytes_returned;
2612 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002613 struct smb_com_transaction_ioctl_req *pSMB;
2614 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615
2616 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2617 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2618 (void **) &pSMBr);
2619 if (rc)
2620 return rc;
2621
2622 pSMB->TotalParameterCount = 0 ;
2623 pSMB->TotalDataCount = 0;
2624 pSMB->MaxParameterCount = cpu_to_le32(2);
2625 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002626 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2627 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 pSMB->MaxSetupCount = 4;
2629 pSMB->Reserved = 0;
2630 pSMB->ParameterOffset = 0;
2631 pSMB->DataCount = 0;
2632 pSMB->DataOffset = 0;
2633 pSMB->SetupCount = 4;
2634 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2635 pSMB->ParameterCount = pSMB->TotalParameterCount;
2636 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2637 pSMB->IsFsctl = 1; /* FSCTL */
2638 pSMB->IsRootFlag = 0;
2639 pSMB->Fid = fid; /* file handle always le */
2640 pSMB->ByteCount = 0;
2641
2642 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2643 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2644 if (rc) {
2645 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2646 } else { /* decode response */
2647 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2648 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2649 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2650 /* BB also check enough total bytes returned */
2651 rc = -EIO; /* bad smb */
2652 else {
Steve French790fe572007-07-07 19:25:05 +00002653 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002654 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002655 pSMBr->ByteCount +
2656 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Steve French50c2f752007-07-13 00:33:32 +00002658 struct reparse_data *reparse_buf =
2659 (struct reparse_data *)
2660 ((char *)&pSMBr->hdr.Protocol
2661 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002662 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 rc = -EIO;
2664 goto qreparse_out;
2665 }
Steve French790fe572007-07-07 19:25:05 +00002666 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 reparse_buf->TargetNameOffset +
2668 reparse_buf->TargetNameLen) >
2669 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002670 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 rc = -EIO;
2672 goto qreparse_out;
2673 }
Steve French50c2f752007-07-13 00:33:32 +00002674
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2676 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002677 (reparse_buf->LinkNamesBuf +
2678 reparse_buf->TargetNameOffset),
2679 min(buflen/2,
2680 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002682 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 reparse_buf->TargetNameOffset),
2684 name_len, nls_codepage);
2685 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002686 strncpy(symlinkinfo,
2687 reparse_buf->LinkNamesBuf +
2688 reparse_buf->TargetNameOffset,
2689 min_t(const int, buflen,
2690 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 }
2692 } else {
2693 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002694 cFYI(1, ("Invalid return data count on "
2695 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 }
2697 symlinkinfo[buflen] = 0; /* just in case so the caller
2698 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002699 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 }
2701 }
2702qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002703 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705 /* Note: On -EAGAIN error only caller can retry on handle based calls
2706 since file handle passed in no longer valid */
2707
2708 return rc;
2709}
2710
2711#ifdef CONFIG_CIFS_POSIX
2712
2713/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002714static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2715 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716{
2717 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002718 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2719 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2720 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2722
2723 return;
2724}
2725
2726/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002727static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2728 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
2730 int size = 0;
2731 int i;
2732 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002733 struct cifs_posix_ace *pACE;
2734 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2735 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
2737 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2738 return -EOPNOTSUPP;
2739
Steve French790fe572007-07-07 19:25:05 +00002740 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 count = le16_to_cpu(cifs_acl->access_entry_count);
2742 pACE = &cifs_acl->ace_array[0];
2743 size = sizeof(struct cifs_posix_acl);
2744 size += sizeof(struct cifs_posix_ace) * count;
2745 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002746 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002747 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2748 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 return -EINVAL;
2750 }
Steve French790fe572007-07-07 19:25:05 +00002751 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 count = le16_to_cpu(cifs_acl->access_entry_count);
2753 size = sizeof(struct cifs_posix_acl);
2754 size += sizeof(struct cifs_posix_ace) * count;
2755/* skip past access ACEs to get to default ACEs */
2756 pACE = &cifs_acl->ace_array[count];
2757 count = le16_to_cpu(cifs_acl->default_entry_count);
2758 size += sizeof(struct cifs_posix_ace) * count;
2759 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002760 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 return -EINVAL;
2762 } else {
2763 /* illegal type */
2764 return -EINVAL;
2765 }
2766
2767 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002768 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002769 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002770 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 return -ERANGE;
2772 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002773 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002774 for (i = 0; i < count ; i++) {
2775 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2776 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 }
2778 }
2779 return size;
2780}
2781
Steve French50c2f752007-07-13 00:33:32 +00002782static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2783 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784{
2785 __u16 rc = 0; /* 0 = ACL converted ok */
2786
Steve Frenchff7feac2005-11-15 16:45:16 -08002787 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2788 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002790 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 /* Probably no need to le convert -1 on any arch but can not hurt */
2792 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002793 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002794 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002795 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 return rc;
2797}
2798
2799/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002800static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2801 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802{
2803 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002804 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2805 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 int count;
2807 int i;
2808
Steve French790fe572007-07-07 19:25:05 +00002809 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 return 0;
2811
2812 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002813 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002814 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002815 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002816 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002817 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002818 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 return 0;
2820 }
2821 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002822 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002823 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002824 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002825 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 else {
Steve French50c2f752007-07-13 00:33:32 +00002827 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 return 0;
2829 }
Steve French50c2f752007-07-13 00:33:32 +00002830 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2832 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002833 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 /* ACE not converted */
2835 break;
2836 }
2837 }
Steve French790fe572007-07-07 19:25:05 +00002838 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2840 rc += sizeof(struct cifs_posix_acl);
2841 /* BB add check to make sure ACL does not overflow SMB */
2842 }
2843 return rc;
2844}
2845
2846int
2847CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002848 const unsigned char *searchName,
2849 char *acl_inf, const int buflen, const int acl_type,
2850 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851{
2852/* SMB_QUERY_POSIX_ACL */
2853 TRANSACTION2_QPI_REQ *pSMB = NULL;
2854 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2855 int rc = 0;
2856 int bytes_returned;
2857 int name_len;
2858 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002859
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2861
2862queryAclRetry:
2863 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2864 (void **) &pSMBr);
2865 if (rc)
2866 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002867
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2869 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002870 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002871 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 name_len++; /* trailing null */
2873 name_len *= 2;
2874 pSMB->FileName[name_len] = 0;
2875 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002876 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 name_len = strnlen(searchName, PATH_MAX);
2878 name_len++; /* trailing null */
2879 strncpy(pSMB->FileName, searchName, name_len);
2880 }
2881
2882 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2883 pSMB->TotalDataCount = 0;
2884 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002885 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 pSMB->MaxDataCount = cpu_to_le16(4000);
2887 pSMB->MaxSetupCount = 0;
2888 pSMB->Reserved = 0;
2889 pSMB->Flags = 0;
2890 pSMB->Timeout = 0;
2891 pSMB->Reserved2 = 0;
2892 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002893 offsetof(struct smb_com_transaction2_qpi_req,
2894 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 pSMB->DataCount = 0;
2896 pSMB->DataOffset = 0;
2897 pSMB->SetupCount = 1;
2898 pSMB->Reserved3 = 0;
2899 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2900 byte_count = params + 1 /* pad */ ;
2901 pSMB->TotalParameterCount = cpu_to_le16(params);
2902 pSMB->ParameterCount = pSMB->TotalParameterCount;
2903 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2904 pSMB->Reserved4 = 0;
2905 pSMB->hdr.smb_buf_length += byte_count;
2906 pSMB->ByteCount = cpu_to_le16(byte_count);
2907
2908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002910 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 if (rc) {
2912 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2913 } else {
2914 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002915
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2917 if (rc || (pSMBr->ByteCount < 2))
2918 /* BB also check enough total bytes returned */
2919 rc = -EIO; /* bad smb */
2920 else {
2921 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2922 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2923 rc = cifs_copy_posix_acl(acl_inf,
2924 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002925 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 }
2927 }
2928 cifs_buf_release(pSMB);
2929 if (rc == -EAGAIN)
2930 goto queryAclRetry;
2931 return rc;
2932}
2933
2934int
2935CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002936 const unsigned char *fileName,
2937 const char *local_acl, const int buflen,
2938 const int acl_type,
2939 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940{
2941 struct smb_com_transaction2_spi_req *pSMB = NULL;
2942 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2943 char *parm_data;
2944 int name_len;
2945 int rc = 0;
2946 int bytes_returned = 0;
2947 __u16 params, byte_count, data_count, param_offset, offset;
2948
2949 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2950setAclRetry:
2951 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002952 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 if (rc)
2954 return rc;
2955 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2956 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002957 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002958 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 name_len++; /* trailing null */
2960 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002961 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 name_len = strnlen(fileName, PATH_MAX);
2963 name_len++; /* trailing null */
2964 strncpy(pSMB->FileName, fileName, name_len);
2965 }
2966 params = 6 + name_len;
2967 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002968 /* BB find max SMB size from sess */
2969 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 pSMB->MaxSetupCount = 0;
2971 pSMB->Reserved = 0;
2972 pSMB->Flags = 0;
2973 pSMB->Timeout = 0;
2974 pSMB->Reserved2 = 0;
2975 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002976 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 offset = param_offset + params;
2978 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2979 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2980
2981 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002982 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983
Steve French790fe572007-07-07 19:25:05 +00002984 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 rc = -EOPNOTSUPP;
2986 goto setACLerrorExit;
2987 }
2988 pSMB->DataOffset = cpu_to_le16(offset);
2989 pSMB->SetupCount = 1;
2990 pSMB->Reserved3 = 0;
2991 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2992 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2993 byte_count = 3 /* pad */ + params + data_count;
2994 pSMB->DataCount = cpu_to_le16(data_count);
2995 pSMB->TotalDataCount = pSMB->DataCount;
2996 pSMB->ParameterCount = cpu_to_le16(params);
2997 pSMB->TotalParameterCount = pSMB->ParameterCount;
2998 pSMB->Reserved4 = 0;
2999 pSMB->hdr.smb_buf_length += byte_count;
3000 pSMB->ByteCount = cpu_to_le16(byte_count);
3001 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003002 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003003 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
3006setACLerrorExit:
3007 cifs_buf_release(pSMB);
3008 if (rc == -EAGAIN)
3009 goto setAclRetry;
3010 return rc;
3011}
3012
Steve Frenchf654bac2005-04-28 22:41:04 -07003013/* BB fix tabs in this function FIXME BB */
3014int
3015CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003016 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003017{
Steve French50c2f752007-07-13 00:33:32 +00003018 int rc = 0;
3019 struct smb_t2_qfi_req *pSMB = NULL;
3020 struct smb_t2_qfi_rsp *pSMBr = NULL;
3021 int bytes_returned;
3022 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003023
Steve French790fe572007-07-07 19:25:05 +00003024 cFYI(1, ("In GetExtAttr"));
3025 if (tcon == NULL)
3026 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003027
3028GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003029 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3030 (void **) &pSMBr);
3031 if (rc)
3032 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003033
Steve Frenchad7a2922008-02-07 23:25:02 +00003034 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003035 pSMB->t2.TotalDataCount = 0;
3036 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3037 /* BB find exact max data count below from sess structure BB */
3038 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3039 pSMB->t2.MaxSetupCount = 0;
3040 pSMB->t2.Reserved = 0;
3041 pSMB->t2.Flags = 0;
3042 pSMB->t2.Timeout = 0;
3043 pSMB->t2.Reserved2 = 0;
3044 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3045 Fid) - 4);
3046 pSMB->t2.DataCount = 0;
3047 pSMB->t2.DataOffset = 0;
3048 pSMB->t2.SetupCount = 1;
3049 pSMB->t2.Reserved3 = 0;
3050 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3051 byte_count = params + 1 /* pad */ ;
3052 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3053 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3054 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3055 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003056 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003057 pSMB->hdr.smb_buf_length += byte_count;
3058 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003059
Steve French790fe572007-07-07 19:25:05 +00003060 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3061 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3062 if (rc) {
3063 cFYI(1, ("error %d in GetExtAttr", rc));
3064 } else {
3065 /* decode response */
3066 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3067 if (rc || (pSMBr->ByteCount < 2))
3068 /* BB also check enough total bytes returned */
3069 /* If rc should we check for EOPNOSUPP and
3070 disable the srvino flag? or in caller? */
3071 rc = -EIO; /* bad smb */
3072 else {
3073 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3074 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3075 struct file_chattr_info *pfinfo;
3076 /* BB Do we need a cast or hash here ? */
3077 if (count != 16) {
3078 cFYI(1, ("Illegal size ret in GetExtAttr"));
3079 rc = -EIO;
3080 goto GetExtAttrOut;
3081 }
3082 pfinfo = (struct file_chattr_info *)
3083 (data_offset + (char *) &pSMBr->hdr.Protocol);
3084 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003085 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003086 }
3087 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003088GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003089 cifs_buf_release(pSMB);
3090 if (rc == -EAGAIN)
3091 goto GetExtAttrRetry;
3092 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003093}
3094
Steve Frenchf654bac2005-04-28 22:41:04 -07003095#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Steve French297647c2007-10-12 04:11:59 +00003097#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003098/* Get Security Descriptor (by handle) from remote server for a file or dir */
3099int
3100CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003101 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003102{
3103 int rc = 0;
3104 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003105 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003106 struct kvec iov[1];
3107
3108 cFYI(1, ("GetCifsACL"));
3109
Steve French630f3f0c2007-10-25 21:17:17 +00003110 *pbuflen = 0;
3111 *acl_inf = NULL;
3112
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003113 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003114 8 /* parm len */, tcon, (void **) &pSMB);
3115 if (rc)
3116 return rc;
3117
3118 pSMB->MaxParameterCount = cpu_to_le32(4);
3119 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3120 pSMB->MaxSetupCount = 0;
3121 pSMB->Fid = fid; /* file handle always le */
3122 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3123 CIFS_ACL_DACL);
3124 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3125 pSMB->hdr.smb_buf_length += 11;
3126 iov[0].iov_base = (char *)pSMB;
3127 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3128
Steve Frencha761ac52007-10-18 21:45:27 +00003129 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003130 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003131 cifs_stats_inc(&tcon->num_acl_get);
3132 if (rc) {
3133 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3134 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003135 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003136 __u32 parm_len;
3137 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003138 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003139 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003140
3141/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003142 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003143 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003144 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003145 goto qsec_out;
3146 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3147
Steve French630f3f0c2007-10-25 21:17:17 +00003148 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003149
3150 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3151 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003152 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003153 goto qsec_out;
3154 }
3155
3156/* BB check that data area is minimum length and as big as acl_len */
3157
Steve Frenchaf6f4612007-10-16 18:40:37 +00003158 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003159 if (acl_len != *pbuflen) {
3160 cERROR(1, ("acl length %d does not match %d",
3161 acl_len, *pbuflen));
3162 if (*pbuflen > acl_len)
3163 *pbuflen = acl_len;
3164 }
Steve French0a4b92c2006-01-12 15:44:21 -08003165
Steve French630f3f0c2007-10-25 21:17:17 +00003166 /* check if buffer is big enough for the acl
3167 header followed by the smallest SID */
3168 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3169 (*pbuflen >= 64 * 1024)) {
3170 cERROR(1, ("bad acl length %d", *pbuflen));
3171 rc = -EINVAL;
3172 *pbuflen = 0;
3173 } else {
3174 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3175 if (*acl_inf == NULL) {
3176 *pbuflen = 0;
3177 rc = -ENOMEM;
3178 }
3179 memcpy(*acl_inf, pdata, *pbuflen);
3180 }
Steve French0a4b92c2006-01-12 15:44:21 -08003181 }
3182qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003183 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003184 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003185 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003186 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003187/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003188 return rc;
3189}
Steve French97837582007-12-31 07:47:21 +00003190
3191int
3192CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3193 struct cifs_ntsd *pntsd, __u32 acllen)
3194{
3195 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3196 int rc = 0;
3197 int bytes_returned = 0;
3198 SET_SEC_DESC_REQ *pSMB = NULL;
3199 NTRANSACT_RSP *pSMBr = NULL;
3200
3201setCifsAclRetry:
3202 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3203 (void **) &pSMBr);
3204 if (rc)
3205 return (rc);
3206
3207 pSMB->MaxSetupCount = 0;
3208 pSMB->Reserved = 0;
3209
3210 param_count = 8;
3211 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3212 data_count = acllen;
3213 data_offset = param_offset + param_count;
3214 byte_count = 3 /* pad */ + param_count;
3215
3216 pSMB->DataCount = cpu_to_le32(data_count);
3217 pSMB->TotalDataCount = pSMB->DataCount;
3218 pSMB->MaxParameterCount = cpu_to_le32(4);
3219 pSMB->MaxDataCount = cpu_to_le32(16384);
3220 pSMB->ParameterCount = cpu_to_le32(param_count);
3221 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3222 pSMB->TotalParameterCount = pSMB->ParameterCount;
3223 pSMB->DataOffset = cpu_to_le32(data_offset);
3224 pSMB->SetupCount = 0;
3225 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3226 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3227
3228 pSMB->Fid = fid; /* file handle always le */
3229 pSMB->Reserved2 = 0;
3230 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3231
3232 if (pntsd && acllen) {
3233 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3234 (char *) pntsd,
3235 acllen);
3236 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3237
3238 } else
3239 pSMB->hdr.smb_buf_length += byte_count;
3240
3241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3242 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3243
3244 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3245 if (rc)
3246 cFYI(1, ("Set CIFS ACL returned %d", rc));
3247 cifs_buf_release(pSMB);
3248
3249 if (rc == -EAGAIN)
3250 goto setCifsAclRetry;
3251
3252 return (rc);
3253}
3254
Steve French297647c2007-10-12 04:11:59 +00003255#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003256
Steve French6b8edfe2005-08-23 20:26:03 -07003257/* Legacy Query Path Information call for lookup to old servers such
3258 as Win9x/WinME */
3259int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003260 const unsigned char *searchName,
3261 FILE_ALL_INFO *pFinfo,
3262 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003263{
Steve Frenchad7a2922008-02-07 23:25:02 +00003264 QUERY_INFORMATION_REQ *pSMB;
3265 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003266 int rc = 0;
3267 int bytes_returned;
3268 int name_len;
3269
Steve French50c2f752007-07-13 00:33:32 +00003270 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003271QInfRetry:
3272 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003273 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003274 if (rc)
3275 return rc;
3276
3277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3278 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003279 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3280 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003281 name_len++; /* trailing null */
3282 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003283 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003284 name_len = strnlen(searchName, PATH_MAX);
3285 name_len++; /* trailing null */
3286 strncpy(pSMB->FileName, searchName, name_len);
3287 }
3288 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003289 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003290 pSMB->hdr.smb_buf_length += (__u16) name_len;
3291 pSMB->ByteCount = cpu_to_le16(name_len);
3292
3293 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003294 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003295 if (rc) {
3296 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003297 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003298 struct timespec ts;
3299 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003300
3301 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003302 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003303 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003304 ts.tv_nsec = 0;
3305 ts.tv_sec = time;
3306 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003307 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003308 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3309 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003310 pFinfo->AllocationSize =
3311 cpu_to_le64(le32_to_cpu(pSMBr->size));
3312 pFinfo->EndOfFile = pFinfo->AllocationSize;
3313 pFinfo->Attributes =
3314 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003315 } else
3316 rc = -EIO; /* bad buffer passed in */
3317
3318 cifs_buf_release(pSMB);
3319
3320 if (rc == -EAGAIN)
3321 goto QInfRetry;
3322
3323 return rc;
3324}
3325
3326
3327
3328
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329int
3330CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3331 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003332 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003333 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003334 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335{
3336/* level 263 SMB_QUERY_FILE_ALL_INFO */
3337 TRANSACTION2_QPI_REQ *pSMB = NULL;
3338 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3339 int rc = 0;
3340 int bytes_returned;
3341 int name_len;
3342 __u16 params, byte_count;
3343
3344/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3345QPathInfoRetry:
3346 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3347 (void **) &pSMBr);
3348 if (rc)
3349 return rc;
3350
3351 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3352 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003353 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003354 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 name_len++; /* trailing null */
3356 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003357 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 name_len = strnlen(searchName, PATH_MAX);
3359 name_len++; /* trailing null */
3360 strncpy(pSMB->FileName, searchName, name_len);
3361 }
3362
Steve French50c2f752007-07-13 00:33:32 +00003363 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 pSMB->TotalDataCount = 0;
3365 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003366 /* BB find exact max SMB PDU from sess structure BB */
3367 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 pSMB->MaxSetupCount = 0;
3369 pSMB->Reserved = 0;
3370 pSMB->Flags = 0;
3371 pSMB->Timeout = 0;
3372 pSMB->Reserved2 = 0;
3373 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003374 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 pSMB->DataCount = 0;
3376 pSMB->DataOffset = 0;
3377 pSMB->SetupCount = 1;
3378 pSMB->Reserved3 = 0;
3379 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3380 byte_count = params + 1 /* pad */ ;
3381 pSMB->TotalParameterCount = cpu_to_le16(params);
3382 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003383 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003384 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3385 else
3386 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 pSMB->Reserved4 = 0;
3388 pSMB->hdr.smb_buf_length += byte_count;
3389 pSMB->ByteCount = cpu_to_le16(byte_count);
3390
3391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3392 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3393 if (rc) {
3394 cFYI(1, ("Send error in QPathInfo = %d", rc));
3395 } else { /* decode response */
3396 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3397
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003398 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3399 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003400 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003402 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003403 rc = -EIO; /* 24 or 26 expected but we do not read
3404 last field */
3405 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003406 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003408
3409 /* On legacy responses we do not read the last field,
3410 EAsize, fortunately since it varies by subdialect and
3411 also note it differs on Set vs. Get, ie two bytes or 4
3412 bytes depending but we don't care here */
3413 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003414 size = sizeof(FILE_INFO_STANDARD);
3415 else
3416 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 memcpy((char *) pFindData,
3418 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003419 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 } else
3421 rc = -ENOMEM;
3422 }
3423 cifs_buf_release(pSMB);
3424 if (rc == -EAGAIN)
3425 goto QPathInfoRetry;
3426
3427 return rc;
3428}
3429
3430int
3431CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3432 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003433 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003434 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435{
3436/* SMB_QUERY_FILE_UNIX_BASIC */
3437 TRANSACTION2_QPI_REQ *pSMB = NULL;
3438 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3439 int rc = 0;
3440 int bytes_returned = 0;
3441 int name_len;
3442 __u16 params, byte_count;
3443
3444 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3445UnixQPathInfoRetry:
3446 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3447 (void **) &pSMBr);
3448 if (rc)
3449 return rc;
3450
3451 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3452 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003453 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003454 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 name_len++; /* trailing null */
3456 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003457 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 name_len = strnlen(searchName, PATH_MAX);
3459 name_len++; /* trailing null */
3460 strncpy(pSMB->FileName, searchName, name_len);
3461 }
3462
Steve French50c2f752007-07-13 00:33:32 +00003463 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 pSMB->TotalDataCount = 0;
3465 pSMB->MaxParameterCount = cpu_to_le16(2);
3466 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003467 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 pSMB->MaxSetupCount = 0;
3469 pSMB->Reserved = 0;
3470 pSMB->Flags = 0;
3471 pSMB->Timeout = 0;
3472 pSMB->Reserved2 = 0;
3473 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003474 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 pSMB->DataCount = 0;
3476 pSMB->DataOffset = 0;
3477 pSMB->SetupCount = 1;
3478 pSMB->Reserved3 = 0;
3479 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3480 byte_count = params + 1 /* pad */ ;
3481 pSMB->TotalParameterCount = cpu_to_le16(params);
3482 pSMB->ParameterCount = pSMB->TotalParameterCount;
3483 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3484 pSMB->Reserved4 = 0;
3485 pSMB->hdr.smb_buf_length += byte_count;
3486 pSMB->ByteCount = cpu_to_le16(byte_count);
3487
3488 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3489 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3490 if (rc) {
3491 cFYI(1, ("Send error in QPathInfo = %d", rc));
3492 } else { /* decode response */
3493 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3494
3495 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003496 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3497 "Unix Extensions can be disabled on mount "
3498 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 rc = -EIO; /* bad smb */
3500 } else {
3501 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3502 memcpy((char *) pFindData,
3503 (char *) &pSMBr->hdr.Protocol +
3504 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003505 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 }
3507 }
3508 cifs_buf_release(pSMB);
3509 if (rc == -EAGAIN)
3510 goto UnixQPathInfoRetry;
3511
3512 return rc;
3513}
3514
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515/* xid, tcon, searchName and codepage are input parms, rest are returned */
3516int
3517CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003518 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003520 __u16 *pnetfid,
3521 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522{
3523/* level 257 SMB_ */
3524 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3525 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003526 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 int rc = 0;
3528 int bytes_returned = 0;
3529 int name_len;
3530 __u16 params, byte_count;
3531
Steve French50c2f752007-07-13 00:33:32 +00003532 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534findFirstRetry:
3535 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3536 (void **) &pSMBr);
3537 if (rc)
3538 return rc;
3539
3540 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3541 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003542 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003543 PATH_MAX, nls_codepage, remap);
3544 /* We can not add the asterik earlier in case
3545 it got remapped to 0xF03A as if it were part of the
3546 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003548 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003549 pSMB->FileName[name_len+1] = 0;
3550 pSMB->FileName[name_len+2] = '*';
3551 pSMB->FileName[name_len+3] = 0;
3552 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3554 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003555 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 } else { /* BB add check for overrun of SMB buf BB */
3557 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003559 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 free buffer exit; BB */
3561 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003562 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003563 pSMB->FileName[name_len+1] = '*';
3564 pSMB->FileName[name_len+2] = 0;
3565 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 }
3567
3568 params = 12 + name_len /* includes null */ ;
3569 pSMB->TotalDataCount = 0; /* no EAs */
3570 pSMB->MaxParameterCount = cpu_to_le16(10);
3571 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3572 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3573 pSMB->MaxSetupCount = 0;
3574 pSMB->Reserved = 0;
3575 pSMB->Flags = 0;
3576 pSMB->Timeout = 0;
3577 pSMB->Reserved2 = 0;
3578 byte_count = params + 1 /* pad */ ;
3579 pSMB->TotalParameterCount = cpu_to_le16(params);
3580 pSMB->ParameterCount = pSMB->TotalParameterCount;
3581 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003582 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3583 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 pSMB->DataCount = 0;
3585 pSMB->DataOffset = 0;
3586 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3587 pSMB->Reserved3 = 0;
3588 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3589 pSMB->SearchAttributes =
3590 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3591 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003592 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3593 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 CIFS_SEARCH_RETURN_RESUME);
3595 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3596
3597 /* BB what should we set StorageType to? Does it matter? BB */
3598 pSMB->SearchStorageType = 0;
3599 pSMB->hdr.smb_buf_length += byte_count;
3600 pSMB->ByteCount = cpu_to_le16(byte_count);
3601
3602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003604 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605
Steve French88274812006-03-09 22:21:45 +00003606 if (rc) {/* BB add logic to retry regular search if Unix search
3607 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 /* BB Add code to handle unsupported level rc */
3609 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003610
Steve French88274812006-03-09 22:21:45 +00003611 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
3613 /* BB eventually could optimize out free and realloc of buf */
3614 /* for this case */
3615 if (rc == -EAGAIN)
3616 goto findFirstRetry;
3617 } else { /* decode response */
3618 /* BB remember to free buffer if error BB */
3619 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003620 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003622 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 else
Steve French4b18f2a2008-04-29 00:06:05 +00003624 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625
3626 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003627 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003628 psrch_inf->srch_entries_start =
3629 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3632 le16_to_cpu(pSMBr->t2.ParameterOffset));
3633
Steve French790fe572007-07-07 19:25:05 +00003634 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003635 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 else
Steve French4b18f2a2008-04-29 00:06:05 +00003637 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
Steve French50c2f752007-07-13 00:33:32 +00003639 psrch_inf->entries_in_buffer =
3640 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003641 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 *pnetfid = parms->SearchHandle;
3644 } else {
3645 cifs_buf_release(pSMB);
3646 }
3647 }
3648
3649 return rc;
3650}
3651
3652int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003653 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654{
3655 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3656 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003657 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 char *response_data;
3659 int rc = 0;
3660 int bytes_returned, name_len;
3661 __u16 params, byte_count;
3662
3663 cFYI(1, ("In FindNext"));
3664
Steve French4b18f2a2008-04-29 00:06:05 +00003665 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 return -ENOENT;
3667
3668 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3669 (void **) &pSMBr);
3670 if (rc)
3671 return rc;
3672
Steve French50c2f752007-07-13 00:33:32 +00003673 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 byte_count = 0;
3675 pSMB->TotalDataCount = 0; /* no EAs */
3676 pSMB->MaxParameterCount = cpu_to_le16(8);
3677 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003678 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3679 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 pSMB->MaxSetupCount = 0;
3681 pSMB->Reserved = 0;
3682 pSMB->Flags = 0;
3683 pSMB->Timeout = 0;
3684 pSMB->Reserved2 = 0;
3685 pSMB->ParameterOffset = cpu_to_le16(
3686 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3687 pSMB->DataCount = 0;
3688 pSMB->DataOffset = 0;
3689 pSMB->SetupCount = 1;
3690 pSMB->Reserved3 = 0;
3691 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3692 pSMB->SearchHandle = searchHandle; /* always kept as le */
3693 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003694 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3696 pSMB->ResumeKey = psrch_inf->resume_key;
3697 pSMB->SearchFlags =
3698 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3699
3700 name_len = psrch_inf->resume_name_len;
3701 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003702 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3704 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003705 /* 14 byte parm len above enough for 2 byte null terminator */
3706 pSMB->ResumeFileName[name_len] = 0;
3707 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 } else {
3709 rc = -EINVAL;
3710 goto FNext2_err_exit;
3711 }
3712 byte_count = params + 1 /* pad */ ;
3713 pSMB->TotalParameterCount = cpu_to_le16(params);
3714 pSMB->ParameterCount = pSMB->TotalParameterCount;
3715 pSMB->hdr.smb_buf_length += byte_count;
3716 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003717
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3719 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003720 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 if (rc) {
3722 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003723 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003724 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003725 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 } else
3727 cFYI(1, ("FindNext returned = %d", rc));
3728 } else { /* decode response */
3729 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003730
Steve French790fe572007-07-07 19:25:05 +00003731 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 /* BB fixme add lock for file (srch_info) struct here */
3733 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003734 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 else
Steve French4b18f2a2008-04-29 00:06:05 +00003736 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 response_data = (char *) &pSMBr->hdr.Protocol +
3738 le16_to_cpu(pSMBr->t2.ParameterOffset);
3739 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3740 response_data = (char *)&pSMBr->hdr.Protocol +
3741 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003742 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003743 cifs_small_buf_release(
3744 psrch_inf->ntwrk_buf_start);
3745 else
3746 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 psrch_inf->srch_entries_start = response_data;
3748 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003749 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003750 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003751 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 else
Steve French4b18f2a2008-04-29 00:06:05 +00003753 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003754 psrch_inf->entries_in_buffer =
3755 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 psrch_inf->index_of_last_entry +=
3757 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003758/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3759 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760
3761 /* BB fixme add unlock here */
3762 }
3763
3764 }
3765
3766 /* BB On error, should we leave previous search buf (and count and
3767 last entry fields) intact or free the previous one? */
3768
3769 /* Note: On -EAGAIN error only caller can retry on handle based calls
3770 since file handle passed in no longer valid */
3771FNext2_err_exit:
3772 if (rc != 0)
3773 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 return rc;
3775}
3776
3777int
Steve French50c2f752007-07-13 00:33:32 +00003778CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3779 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780{
3781 int rc = 0;
3782 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
3784 cFYI(1, ("In CIFSSMBFindClose"));
3785 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3786
3787 /* no sense returning error if session restarted
3788 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003789 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 return 0;
3791 if (rc)
3792 return rc;
3793
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 pSMB->FileID = searchHandle;
3795 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003796 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003797 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003799
Steve Frencha4544342005-08-24 13:59:35 -07003800 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801
3802 /* Since session is dead, search handle closed on server already */
3803 if (rc == -EAGAIN)
3804 rc = 0;
3805
3806 return rc;
3807}
3808
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809int
3810CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003811 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003812 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003813 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814{
3815 int rc = 0;
3816 TRANSACTION2_QPI_REQ *pSMB = NULL;
3817 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3818 int name_len, bytes_returned;
3819 __u16 params, byte_count;
3820
Steve French50c2f752007-07-13 00:33:32 +00003821 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003822 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003823 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824
3825GetInodeNumberRetry:
3826 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003827 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 if (rc)
3829 return rc;
3830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3832 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003833 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003834 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 name_len++; /* trailing null */
3836 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003837 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 name_len = strnlen(searchName, PATH_MAX);
3839 name_len++; /* trailing null */
3840 strncpy(pSMB->FileName, searchName, name_len);
3841 }
3842
3843 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3844 pSMB->TotalDataCount = 0;
3845 pSMB->MaxParameterCount = cpu_to_le16(2);
3846 /* BB find exact max data count below from sess structure BB */
3847 pSMB->MaxDataCount = cpu_to_le16(4000);
3848 pSMB->MaxSetupCount = 0;
3849 pSMB->Reserved = 0;
3850 pSMB->Flags = 0;
3851 pSMB->Timeout = 0;
3852 pSMB->Reserved2 = 0;
3853 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003854 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 pSMB->DataCount = 0;
3856 pSMB->DataOffset = 0;
3857 pSMB->SetupCount = 1;
3858 pSMB->Reserved3 = 0;
3859 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3860 byte_count = params + 1 /* pad */ ;
3861 pSMB->TotalParameterCount = cpu_to_le16(params);
3862 pSMB->ParameterCount = pSMB->TotalParameterCount;
3863 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3864 pSMB->Reserved4 = 0;
3865 pSMB->hdr.smb_buf_length += byte_count;
3866 pSMB->ByteCount = cpu_to_le16(byte_count);
3867
3868 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3870 if (rc) {
3871 cFYI(1, ("error %d in QueryInternalInfo", rc));
3872 } else {
3873 /* decode response */
3874 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3875 if (rc || (pSMBr->ByteCount < 2))
3876 /* BB also check enough total bytes returned */
3877 /* If rc should we check for EOPNOSUPP and
3878 disable the srvino flag? or in caller? */
3879 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003880 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3882 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003883 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003885 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3887 rc = -EIO;
3888 goto GetInodeNumOut;
3889 }
3890 pfinfo = (struct file_internal_info *)
3891 (data_offset + (char *) &pSMBr->hdr.Protocol);
3892 *inode_number = pfinfo->UniqueId;
3893 }
3894 }
3895GetInodeNumOut:
3896 cifs_buf_release(pSMB);
3897 if (rc == -EAGAIN)
3898 goto GetInodeNumberRetry;
3899 return rc;
3900}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901
Igor Mammedovfec45852008-05-16 13:06:30 +04003902/* parses DFS refferal V3 structure
3903 * caller is responsible for freeing target_nodes
3904 * returns:
3905 * on success - 0
3906 * on failure - errno
3907 */
3908static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003909parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003910 unsigned int *num_of_nodes,
3911 struct dfs_info3_param **target_nodes,
3912 const struct nls_table *nls_codepage)
3913{
3914 int i, rc = 0;
3915 char *data_end;
3916 bool is_unicode;
3917 struct dfs_referral_level_3 *ref;
3918
3919 is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE;
3920 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3921
3922 if (*num_of_nodes < 1) {
3923 cERROR(1, ("num_referrals: must be at least > 0,"
3924 "but we get num_referrals = %d\n", *num_of_nodes));
3925 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003926 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003927 }
3928
3929 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
3930 if (ref->VersionNumber != 3) {
3931 cERROR(1, ("Referrals of V%d version are not supported,"
3932 "should be V3", ref->VersionNumber));
3933 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003934 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003935 }
3936
3937 /* get the upper boundary of the resp buffer */
3938 data_end = (char *)(&(pSMBr->PathConsumed)) +
3939 le16_to_cpu(pSMBr->t2.DataCount);
3940
3941 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3942 *num_of_nodes,
3943 le16_to_cpu(pSMBr->DFSFlags)));
3944
3945 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3946 *num_of_nodes, GFP_KERNEL);
3947 if (*target_nodes == NULL) {
3948 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3949 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003950 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003951 }
3952
3953 /* collect neccessary data from referrals */
3954 for (i = 0; i < *num_of_nodes; i++) {
3955 char *temp;
3956 int max_len;
3957 struct dfs_info3_param *node = (*target_nodes)+i;
3958
3959 node->flags = le16_to_cpu(pSMBr->DFSFlags);
3960 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3961 node->server_type = le16_to_cpu(ref->ServerType);
3962 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3963
3964 /* copy DfsPath */
3965 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3966 max_len = data_end - temp;
3967 rc = cifs_strncpy_to_host(&(node->path_name), temp,
3968 max_len, is_unicode, nls_codepage);
3969 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00003970 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003971
3972 /* copy link target UNC */
3973 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3974 max_len = data_end - temp;
3975 rc = cifs_strncpy_to_host(&(node->node_name), temp,
3976 max_len, is_unicode, nls_codepage);
3977 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00003978 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003979
3980 ref += ref->Size;
3981 }
3982
Steve Frencha1fe78f2008-05-16 18:48:38 +00003983parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04003984 if (rc) {
3985 free_dfs_info_array(*target_nodes, *num_of_nodes);
3986 *target_nodes = NULL;
3987 *num_of_nodes = 0;
3988 }
3989 return rc;
3990}
3991
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992int
3993CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3994 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003995 struct dfs_info3_param **target_nodes,
3996 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07003997 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998{
3999/* TRANS2_GET_DFS_REFERRAL */
4000 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4001 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 int rc = 0;
4003 int bytes_returned;
4004 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004006 *num_of_nodes = 0;
4007 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008
4009 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4010 if (ses == NULL)
4011 return -ENODEV;
4012getDFSRetry:
4013 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4014 (void **) &pSMBr);
4015 if (rc)
4016 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004017
4018 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004019 but should never be null here anyway */
4020 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 pSMB->hdr.Tid = ses->ipc_tid;
4022 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004023 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004025 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027
4028 if (ses->capabilities & CAP_UNICODE) {
4029 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4030 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004031 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004032 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 name_len++; /* trailing null */
4034 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004035 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 name_len = strnlen(searchName, PATH_MAX);
4037 name_len++; /* trailing null */
4038 strncpy(pSMB->RequestFileName, searchName, name_len);
4039 }
4040
Steve French790fe572007-07-07 19:25:05 +00004041 if (ses->server) {
4042 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004043 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4044 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4045 }
4046
Steve French50c2f752007-07-13 00:33:32 +00004047 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004048
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 params = 2 /* level */ + name_len /*includes null */ ;
4050 pSMB->TotalDataCount = 0;
4051 pSMB->DataCount = 0;
4052 pSMB->DataOffset = 0;
4053 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004054 /* BB find exact max SMB PDU from sess structure BB */
4055 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 pSMB->MaxSetupCount = 0;
4057 pSMB->Reserved = 0;
4058 pSMB->Flags = 0;
4059 pSMB->Timeout = 0;
4060 pSMB->Reserved2 = 0;
4061 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004062 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 pSMB->SetupCount = 1;
4064 pSMB->Reserved3 = 0;
4065 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4066 byte_count = params + 3 /* pad */ ;
4067 pSMB->ParameterCount = cpu_to_le16(params);
4068 pSMB->TotalParameterCount = pSMB->ParameterCount;
4069 pSMB->MaxReferralLevel = cpu_to_le16(3);
4070 pSMB->hdr.smb_buf_length += byte_count;
4071 pSMB->ByteCount = cpu_to_le16(byte_count);
4072
4073 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4075 if (rc) {
4076 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004077 goto GetDFSRefExit;
4078 }
4079 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004081 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004082 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004083 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004084 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004086
4087 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4088 pSMBr->ByteCount,
4089 le16_to_cpu(pSMBr->t2.DataOffset)));
4090
4091 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004092 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedovfec45852008-05-16 13:06:30 +04004093 target_nodes, nls_codepage);
4094
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004096 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097
4098 if (rc == -EAGAIN)
4099 goto getDFSRetry;
4100
4101 return rc;
4102}
4103
Steve French20962432005-09-21 22:05:57 -07004104/* Query File System Info such as free space to old servers such as Win 9x */
4105int
4106SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4107{
4108/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4109 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4110 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4111 FILE_SYSTEM_ALLOC_INFO *response_data;
4112 int rc = 0;
4113 int bytes_returned = 0;
4114 __u16 params, byte_count;
4115
4116 cFYI(1, ("OldQFSInfo"));
4117oldQFSInfoRetry:
4118 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4119 (void **) &pSMBr);
4120 if (rc)
4121 return rc;
Steve French20962432005-09-21 22:05:57 -07004122
4123 params = 2; /* level */
4124 pSMB->TotalDataCount = 0;
4125 pSMB->MaxParameterCount = cpu_to_le16(2);
4126 pSMB->MaxDataCount = cpu_to_le16(1000);
4127 pSMB->MaxSetupCount = 0;
4128 pSMB->Reserved = 0;
4129 pSMB->Flags = 0;
4130 pSMB->Timeout = 0;
4131 pSMB->Reserved2 = 0;
4132 byte_count = params + 1 /* pad */ ;
4133 pSMB->TotalParameterCount = cpu_to_le16(params);
4134 pSMB->ParameterCount = pSMB->TotalParameterCount;
4135 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4136 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4137 pSMB->DataCount = 0;
4138 pSMB->DataOffset = 0;
4139 pSMB->SetupCount = 1;
4140 pSMB->Reserved3 = 0;
4141 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4142 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4143 pSMB->hdr.smb_buf_length += byte_count;
4144 pSMB->ByteCount = cpu_to_le16(byte_count);
4145
4146 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4147 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4148 if (rc) {
4149 cFYI(1, ("Send error in QFSInfo = %d", rc));
4150 } else { /* decode response */
4151 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4152
4153 if (rc || (pSMBr->ByteCount < 18))
4154 rc = -EIO; /* bad smb */
4155 else {
4156 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004157 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004158 pSMBr->ByteCount, data_offset));
4159
Steve French50c2f752007-07-13 00:33:32 +00004160 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004161 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4162 FSData->f_bsize =
4163 le16_to_cpu(response_data->BytesPerSector) *
4164 le32_to_cpu(response_data->
4165 SectorsPerAllocationUnit);
4166 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004167 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004168 FSData->f_bfree = FSData->f_bavail =
4169 le32_to_cpu(response_data->FreeAllocationUnits);
4170 cFYI(1,
4171 ("Blocks: %lld Free: %lld Block size %ld",
4172 (unsigned long long)FSData->f_blocks,
4173 (unsigned long long)FSData->f_bfree,
4174 FSData->f_bsize));
4175 }
4176 }
4177 cifs_buf_release(pSMB);
4178
4179 if (rc == -EAGAIN)
4180 goto oldQFSInfoRetry;
4181
4182 return rc;
4183}
4184
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185int
Steve French737b7582005-04-28 22:41:06 -07004186CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187{
4188/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4189 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4190 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4191 FILE_SYSTEM_INFO *response_data;
4192 int rc = 0;
4193 int bytes_returned = 0;
4194 __u16 params, byte_count;
4195
4196 cFYI(1, ("In QFSInfo"));
4197QFSInfoRetry:
4198 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4199 (void **) &pSMBr);
4200 if (rc)
4201 return rc;
4202
4203 params = 2; /* level */
4204 pSMB->TotalDataCount = 0;
4205 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004206 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 pSMB->MaxSetupCount = 0;
4208 pSMB->Reserved = 0;
4209 pSMB->Flags = 0;
4210 pSMB->Timeout = 0;
4211 pSMB->Reserved2 = 0;
4212 byte_count = params + 1 /* pad */ ;
4213 pSMB->TotalParameterCount = cpu_to_le16(params);
4214 pSMB->ParameterCount = pSMB->TotalParameterCount;
4215 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004216 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 pSMB->DataCount = 0;
4218 pSMB->DataOffset = 0;
4219 pSMB->SetupCount = 1;
4220 pSMB->Reserved3 = 0;
4221 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4222 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4223 pSMB->hdr.smb_buf_length += byte_count;
4224 pSMB->ByteCount = cpu_to_le16(byte_count);
4225
4226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4227 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4228 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004229 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004231 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232
Steve French20962432005-09-21 22:05:57 -07004233 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 rc = -EIO; /* bad smb */
4235 else {
4236 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
4238 response_data =
4239 (FILE_SYSTEM_INFO
4240 *) (((char *) &pSMBr->hdr.Protocol) +
4241 data_offset);
4242 FSData->f_bsize =
4243 le32_to_cpu(response_data->BytesPerSector) *
4244 le32_to_cpu(response_data->
4245 SectorsPerAllocationUnit);
4246 FSData->f_blocks =
4247 le64_to_cpu(response_data->TotalAllocationUnits);
4248 FSData->f_bfree = FSData->f_bavail =
4249 le64_to_cpu(response_data->FreeAllocationUnits);
4250 cFYI(1,
4251 ("Blocks: %lld Free: %lld Block size %ld",
4252 (unsigned long long)FSData->f_blocks,
4253 (unsigned long long)FSData->f_bfree,
4254 FSData->f_bsize));
4255 }
4256 }
4257 cifs_buf_release(pSMB);
4258
4259 if (rc == -EAGAIN)
4260 goto QFSInfoRetry;
4261
4262 return rc;
4263}
4264
4265int
Steve French737b7582005-04-28 22:41:06 -07004266CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267{
4268/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4269 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4270 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4271 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4272 int rc = 0;
4273 int bytes_returned = 0;
4274 __u16 params, byte_count;
4275
4276 cFYI(1, ("In QFSAttributeInfo"));
4277QFSAttributeRetry:
4278 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4279 (void **) &pSMBr);
4280 if (rc)
4281 return rc;
4282
4283 params = 2; /* level */
4284 pSMB->TotalDataCount = 0;
4285 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004286 /* BB find exact max SMB PDU from sess structure BB */
4287 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 pSMB->MaxSetupCount = 0;
4289 pSMB->Reserved = 0;
4290 pSMB->Flags = 0;
4291 pSMB->Timeout = 0;
4292 pSMB->Reserved2 = 0;
4293 byte_count = params + 1 /* pad */ ;
4294 pSMB->TotalParameterCount = cpu_to_le16(params);
4295 pSMB->ParameterCount = pSMB->TotalParameterCount;
4296 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004297 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 pSMB->DataCount = 0;
4299 pSMB->DataOffset = 0;
4300 pSMB->SetupCount = 1;
4301 pSMB->Reserved3 = 0;
4302 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4303 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4304 pSMB->hdr.smb_buf_length += byte_count;
4305 pSMB->ByteCount = cpu_to_le16(byte_count);
4306
4307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4309 if (rc) {
4310 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4311 } else { /* decode response */
4312 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4313
Steve French50c2f752007-07-13 00:33:32 +00004314 if (rc || (pSMBr->ByteCount < 13)) {
4315 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 rc = -EIO; /* bad smb */
4317 } else {
4318 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4319 response_data =
4320 (FILE_SYSTEM_ATTRIBUTE_INFO
4321 *) (((char *) &pSMBr->hdr.Protocol) +
4322 data_offset);
4323 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004324 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 }
4326 }
4327 cifs_buf_release(pSMB);
4328
4329 if (rc == -EAGAIN)
4330 goto QFSAttributeRetry;
4331
4332 return rc;
4333}
4334
4335int
Steve French737b7582005-04-28 22:41:06 -07004336CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337{
4338/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4339 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4340 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4341 FILE_SYSTEM_DEVICE_INFO *response_data;
4342 int rc = 0;
4343 int bytes_returned = 0;
4344 __u16 params, byte_count;
4345
4346 cFYI(1, ("In QFSDeviceInfo"));
4347QFSDeviceRetry:
4348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4349 (void **) &pSMBr);
4350 if (rc)
4351 return rc;
4352
4353 params = 2; /* level */
4354 pSMB->TotalDataCount = 0;
4355 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004356 /* BB find exact max SMB PDU from sess structure BB */
4357 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 pSMB->MaxSetupCount = 0;
4359 pSMB->Reserved = 0;
4360 pSMB->Flags = 0;
4361 pSMB->Timeout = 0;
4362 pSMB->Reserved2 = 0;
4363 byte_count = params + 1 /* pad */ ;
4364 pSMB->TotalParameterCount = cpu_to_le16(params);
4365 pSMB->ParameterCount = pSMB->TotalParameterCount;
4366 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004367 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368
4369 pSMB->DataCount = 0;
4370 pSMB->DataOffset = 0;
4371 pSMB->SetupCount = 1;
4372 pSMB->Reserved3 = 0;
4373 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4374 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4375 pSMB->hdr.smb_buf_length += byte_count;
4376 pSMB->ByteCount = cpu_to_le16(byte_count);
4377
4378 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4379 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4380 if (rc) {
4381 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4382 } else { /* decode response */
4383 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4384
Steve French630f3f0c2007-10-25 21:17:17 +00004385 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 rc = -EIO; /* bad smb */
4387 else {
4388 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4389 response_data =
Steve French737b7582005-04-28 22:41:06 -07004390 (FILE_SYSTEM_DEVICE_INFO *)
4391 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 data_offset);
4393 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004394 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 }
4396 }
4397 cifs_buf_release(pSMB);
4398
4399 if (rc == -EAGAIN)
4400 goto QFSDeviceRetry;
4401
4402 return rc;
4403}
4404
4405int
Steve French737b7582005-04-28 22:41:06 -07004406CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407{
4408/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4409 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4410 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4411 FILE_SYSTEM_UNIX_INFO *response_data;
4412 int rc = 0;
4413 int bytes_returned = 0;
4414 __u16 params, byte_count;
4415
4416 cFYI(1, ("In QFSUnixInfo"));
4417QFSUnixRetry:
4418 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4419 (void **) &pSMBr);
4420 if (rc)
4421 return rc;
4422
4423 params = 2; /* level */
4424 pSMB->TotalDataCount = 0;
4425 pSMB->DataCount = 0;
4426 pSMB->DataOffset = 0;
4427 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004428 /* BB find exact max SMB PDU from sess structure BB */
4429 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 pSMB->MaxSetupCount = 0;
4431 pSMB->Reserved = 0;
4432 pSMB->Flags = 0;
4433 pSMB->Timeout = 0;
4434 pSMB->Reserved2 = 0;
4435 byte_count = params + 1 /* pad */ ;
4436 pSMB->ParameterCount = cpu_to_le16(params);
4437 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004438 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4439 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 pSMB->SetupCount = 1;
4441 pSMB->Reserved3 = 0;
4442 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4443 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4444 pSMB->hdr.smb_buf_length += byte_count;
4445 pSMB->ByteCount = cpu_to_le16(byte_count);
4446
4447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4449 if (rc) {
4450 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4451 } else { /* decode response */
4452 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4453
4454 if (rc || (pSMBr->ByteCount < 13)) {
4455 rc = -EIO; /* bad smb */
4456 } else {
4457 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4458 response_data =
4459 (FILE_SYSTEM_UNIX_INFO
4460 *) (((char *) &pSMBr->hdr.Protocol) +
4461 data_offset);
4462 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004463 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 }
4465 }
4466 cifs_buf_release(pSMB);
4467
4468 if (rc == -EAGAIN)
4469 goto QFSUnixRetry;
4470
4471
4472 return rc;
4473}
4474
Jeremy Allisonac670552005-06-22 17:26:35 -07004475int
Steve French45abc6e2005-06-23 13:42:03 -05004476CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004477{
4478/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4479 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4480 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4481 int rc = 0;
4482 int bytes_returned = 0;
4483 __u16 params, param_offset, offset, byte_count;
4484
4485 cFYI(1, ("In SETFSUnixInfo"));
4486SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004487 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004488 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4489 (void **) &pSMBr);
4490 if (rc)
4491 return rc;
4492
4493 params = 4; /* 2 bytes zero followed by info level. */
4494 pSMB->MaxSetupCount = 0;
4495 pSMB->Reserved = 0;
4496 pSMB->Flags = 0;
4497 pSMB->Timeout = 0;
4498 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004499 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4500 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004501 offset = param_offset + params;
4502
4503 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004504 /* BB find exact max SMB PDU from sess structure BB */
4505 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004506 pSMB->SetupCount = 1;
4507 pSMB->Reserved3 = 0;
4508 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4509 byte_count = 1 /* pad */ + params + 12;
4510
4511 pSMB->DataCount = cpu_to_le16(12);
4512 pSMB->ParameterCount = cpu_to_le16(params);
4513 pSMB->TotalDataCount = pSMB->DataCount;
4514 pSMB->TotalParameterCount = pSMB->ParameterCount;
4515 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4516 pSMB->DataOffset = cpu_to_le16(offset);
4517
4518 /* Params. */
4519 pSMB->FileNum = 0;
4520 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4521
4522 /* Data. */
4523 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4524 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4525 pSMB->ClientUnixCap = cpu_to_le64(cap);
4526
4527 pSMB->hdr.smb_buf_length += byte_count;
4528 pSMB->ByteCount = cpu_to_le16(byte_count);
4529
4530 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4531 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4532 if (rc) {
4533 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4534 } else { /* decode response */
4535 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004536 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004537 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004538 }
4539 cifs_buf_release(pSMB);
4540
4541 if (rc == -EAGAIN)
4542 goto SETFSUnixRetry;
4543
4544 return rc;
4545}
4546
4547
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
4549int
4550CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004551 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552{
4553/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4554 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4555 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4556 FILE_SYSTEM_POSIX_INFO *response_data;
4557 int rc = 0;
4558 int bytes_returned = 0;
4559 __u16 params, byte_count;
4560
4561 cFYI(1, ("In QFSPosixInfo"));
4562QFSPosixRetry:
4563 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4564 (void **) &pSMBr);
4565 if (rc)
4566 return rc;
4567
4568 params = 2; /* level */
4569 pSMB->TotalDataCount = 0;
4570 pSMB->DataCount = 0;
4571 pSMB->DataOffset = 0;
4572 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004573 /* BB find exact max SMB PDU from sess structure BB */
4574 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 pSMB->MaxSetupCount = 0;
4576 pSMB->Reserved = 0;
4577 pSMB->Flags = 0;
4578 pSMB->Timeout = 0;
4579 pSMB->Reserved2 = 0;
4580 byte_count = params + 1 /* pad */ ;
4581 pSMB->ParameterCount = cpu_to_le16(params);
4582 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004583 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4584 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 pSMB->SetupCount = 1;
4586 pSMB->Reserved3 = 0;
4587 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4588 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4589 pSMB->hdr.smb_buf_length += byte_count;
4590 pSMB->ByteCount = cpu_to_le16(byte_count);
4591
4592 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4593 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4594 if (rc) {
4595 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4596 } else { /* decode response */
4597 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4598
4599 if (rc || (pSMBr->ByteCount < 13)) {
4600 rc = -EIO; /* bad smb */
4601 } else {
4602 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4603 response_data =
4604 (FILE_SYSTEM_POSIX_INFO
4605 *) (((char *) &pSMBr->hdr.Protocol) +
4606 data_offset);
4607 FSData->f_bsize =
4608 le32_to_cpu(response_data->BlockSize);
4609 FSData->f_blocks =
4610 le64_to_cpu(response_data->TotalBlocks);
4611 FSData->f_bfree =
4612 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004613 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 FSData->f_bavail = FSData->f_bfree;
4615 } else {
4616 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004617 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 }
Steve French790fe572007-07-07 19:25:05 +00004619 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004621 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004622 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004624 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 }
4626 }
4627 cifs_buf_release(pSMB);
4628
4629 if (rc == -EAGAIN)
4630 goto QFSPosixRetry;
4631
4632 return rc;
4633}
4634
4635
Steve French50c2f752007-07-13 00:33:32 +00004636/* We can not use write of zero bytes trick to
4637 set file size due to need for large file support. Also note that
4638 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 routine which is only needed to work around a sharing violation bug
4640 in Samba which this routine can run into */
4641
4642int
4643CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004644 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004645 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646{
4647 struct smb_com_transaction2_spi_req *pSMB = NULL;
4648 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4649 struct file_end_of_file_info *parm_data;
4650 int name_len;
4651 int rc = 0;
4652 int bytes_returned = 0;
4653 __u16 params, byte_count, data_count, param_offset, offset;
4654
4655 cFYI(1, ("In SetEOF"));
4656SetEOFRetry:
4657 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4658 (void **) &pSMBr);
4659 if (rc)
4660 return rc;
4661
4662 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4663 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004664 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004665 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 name_len++; /* trailing null */
4667 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004668 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 name_len = strnlen(fileName, PATH_MAX);
4670 name_len++; /* trailing null */
4671 strncpy(pSMB->FileName, fileName, name_len);
4672 }
4673 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004674 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004676 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 pSMB->MaxSetupCount = 0;
4678 pSMB->Reserved = 0;
4679 pSMB->Flags = 0;
4680 pSMB->Timeout = 0;
4681 pSMB->Reserved2 = 0;
4682 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004683 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004685 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004686 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4687 pSMB->InformationLevel =
4688 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4689 else
4690 pSMB->InformationLevel =
4691 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4692 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4694 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004695 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 else
4697 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004698 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 }
4700
4701 parm_data =
4702 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4703 offset);
4704 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4705 pSMB->DataOffset = cpu_to_le16(offset);
4706 pSMB->SetupCount = 1;
4707 pSMB->Reserved3 = 0;
4708 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4709 byte_count = 3 /* pad */ + params + data_count;
4710 pSMB->DataCount = cpu_to_le16(data_count);
4711 pSMB->TotalDataCount = pSMB->DataCount;
4712 pSMB->ParameterCount = cpu_to_le16(params);
4713 pSMB->TotalParameterCount = pSMB->ParameterCount;
4714 pSMB->Reserved4 = 0;
4715 pSMB->hdr.smb_buf_length += byte_count;
4716 parm_data->FileSize = cpu_to_le64(size);
4717 pSMB->ByteCount = cpu_to_le16(byte_count);
4718 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4719 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004720 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
4723 cifs_buf_release(pSMB);
4724
4725 if (rc == -EAGAIN)
4726 goto SetEOFRetry;
4727
4728 return rc;
4729}
4730
4731int
Steve French50c2f752007-07-13 00:33:32 +00004732CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004733 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734{
4735 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 char *data_offset;
4737 struct file_end_of_file_info *parm_data;
4738 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 __u16 params, param_offset, offset, byte_count, count;
4740
4741 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4742 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004743 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4744
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 if (rc)
4746 return rc;
4747
4748 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4749 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004750
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 params = 6;
4752 pSMB->MaxSetupCount = 0;
4753 pSMB->Reserved = 0;
4754 pSMB->Flags = 0;
4755 pSMB->Timeout = 0;
4756 pSMB->Reserved2 = 0;
4757 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4758 offset = param_offset + params;
4759
Steve French50c2f752007-07-13 00:33:32 +00004760 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
4762 count = sizeof(struct file_end_of_file_info);
4763 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004764 /* BB find exact max SMB PDU from sess structure BB */
4765 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 pSMB->SetupCount = 1;
4767 pSMB->Reserved3 = 0;
4768 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4769 byte_count = 3 /* pad */ + params + count;
4770 pSMB->DataCount = cpu_to_le16(count);
4771 pSMB->ParameterCount = cpu_to_le16(params);
4772 pSMB->TotalDataCount = pSMB->DataCount;
4773 pSMB->TotalParameterCount = pSMB->ParameterCount;
4774 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4775 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004776 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4777 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 pSMB->DataOffset = cpu_to_le16(offset);
4779 parm_data->FileSize = cpu_to_le64(size);
4780 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004781 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4783 pSMB->InformationLevel =
4784 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4785 else
4786 pSMB->InformationLevel =
4787 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004788 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4790 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004791 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 else
4793 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004794 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 }
4796 pSMB->Reserved4 = 0;
4797 pSMB->hdr.smb_buf_length += byte_count;
4798 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004799 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 if (rc) {
4801 cFYI(1,
4802 ("Send error in SetFileInfo (SetFileSize) = %d",
4803 rc));
4804 }
4805
Steve French50c2f752007-07-13 00:33:32 +00004806 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 since file handle passed in no longer valid */
4808
4809 return rc;
4810}
4811
Steve French50c2f752007-07-13 00:33:32 +00004812/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 an open handle, rather than by pathname - this is awkward due to
4814 potential access conflicts on the open, but it is unavoidable for these
4815 old servers since the only other choice is to go from 100 nanosecond DCE
4816 time and resort to the original setpathinfo level which takes the ancient
4817 DOS time format with 2 second granularity */
4818int
Steve French50c2f752007-07-13 00:33:32 +00004819CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4820 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821{
4822 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 char *data_offset;
4824 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 __u16 params, param_offset, offset, byte_count, count;
4826
4827 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004828 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4829
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 if (rc)
4831 return rc;
4832
4833 /* At this point there is no need to override the current pid
4834 with the pid of the opener, but that could change if we someday
4835 use an existing handle (rather than opening one on the fly) */
4836 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4837 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004838
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 params = 6;
4840 pSMB->MaxSetupCount = 0;
4841 pSMB->Reserved = 0;
4842 pSMB->Flags = 0;
4843 pSMB->Timeout = 0;
4844 pSMB->Reserved2 = 0;
4845 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4846 offset = param_offset + params;
4847
Steve French50c2f752007-07-13 00:33:32 +00004848 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849
Steve French26f57362007-08-30 22:09:15 +00004850 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004852 /* BB find max SMB PDU from sess */
4853 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 pSMB->SetupCount = 1;
4855 pSMB->Reserved3 = 0;
4856 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4857 byte_count = 3 /* pad */ + params + count;
4858 pSMB->DataCount = cpu_to_le16(count);
4859 pSMB->ParameterCount = cpu_to_le16(params);
4860 pSMB->TotalDataCount = pSMB->DataCount;
4861 pSMB->TotalParameterCount = pSMB->ParameterCount;
4862 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4863 pSMB->DataOffset = cpu_to_le16(offset);
4864 pSMB->Fid = fid;
4865 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4866 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4867 else
4868 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4869 pSMB->Reserved4 = 0;
4870 pSMB->hdr.smb_buf_length += byte_count;
4871 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004872 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004873 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004874 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004875 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876
Steve French50c2f752007-07-13 00:33:32 +00004877 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 since file handle passed in no longer valid */
4879
4880 return rc;
4881}
4882
4883
4884int
4885CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004886 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004887 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888{
4889 TRANSACTION2_SPI_REQ *pSMB = NULL;
4890 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4891 int name_len;
4892 int rc = 0;
4893 int bytes_returned = 0;
4894 char *data_offset;
4895 __u16 params, param_offset, offset, byte_count, count;
4896
4897 cFYI(1, ("In SetTimes"));
4898
4899SetTimesRetry:
4900 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4901 (void **) &pSMBr);
4902 if (rc)
4903 return rc;
4904
4905 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4906 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004907 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004908 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 name_len++; /* trailing null */
4910 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004911 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 name_len = strnlen(fileName, PATH_MAX);
4913 name_len++; /* trailing null */
4914 strncpy(pSMB->FileName, fileName, name_len);
4915 }
4916
4917 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004918 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004920 /* BB find max SMB PDU from sess structure BB */
4921 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 pSMB->MaxSetupCount = 0;
4923 pSMB->Reserved = 0;
4924 pSMB->Flags = 0;
4925 pSMB->Timeout = 0;
4926 pSMB->Reserved2 = 0;
4927 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004928 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 offset = param_offset + params;
4930 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4931 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4932 pSMB->DataOffset = cpu_to_le16(offset);
4933 pSMB->SetupCount = 1;
4934 pSMB->Reserved3 = 0;
4935 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4936 byte_count = 3 /* pad */ + params + count;
4937
4938 pSMB->DataCount = cpu_to_le16(count);
4939 pSMB->ParameterCount = cpu_to_le16(params);
4940 pSMB->TotalDataCount = pSMB->DataCount;
4941 pSMB->TotalParameterCount = pSMB->ParameterCount;
4942 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4943 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4944 else
4945 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4946 pSMB->Reserved4 = 0;
4947 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004948 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 pSMB->ByteCount = cpu_to_le16(byte_count);
4950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004952 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954
4955 cifs_buf_release(pSMB);
4956
4957 if (rc == -EAGAIN)
4958 goto SetTimesRetry;
4959
4960 return rc;
4961}
4962
4963/* Can not be used to set time stamps yet (due to old DOS time format) */
4964/* Can be used to set attributes */
4965#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4966 handling it anyway and NT4 was what we thought it would be needed for
4967 Do not delete it until we prove whether needed for Win9x though */
4968int
4969CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4970 __u16 dos_attrs, const struct nls_table *nls_codepage)
4971{
4972 SETATTR_REQ *pSMB = NULL;
4973 SETATTR_RSP *pSMBr = NULL;
4974 int rc = 0;
4975 int bytes_returned;
4976 int name_len;
4977
4978 cFYI(1, ("In SetAttrLegacy"));
4979
4980SetAttrLgcyRetry:
4981 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4982 (void **) &pSMBr);
4983 if (rc)
4984 return rc;
4985
4986 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4987 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004988 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 PATH_MAX, nls_codepage);
4990 name_len++; /* trailing null */
4991 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004992 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 name_len = strnlen(fileName, PATH_MAX);
4994 name_len++; /* trailing null */
4995 strncpy(pSMB->fileName, fileName, name_len);
4996 }
4997 pSMB->attr = cpu_to_le16(dos_attrs);
4998 pSMB->BufferFormat = 0x04;
4999 pSMB->hdr.smb_buf_length += name_len + 1;
5000 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5001 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5002 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005003 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005
5006 cifs_buf_release(pSMB);
5007
5008 if (rc == -EAGAIN)
5009 goto SetAttrLgcyRetry;
5010
5011 return rc;
5012}
5013#endif /* temporarily unneeded SetAttr legacy function */
5014
5015int
5016CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00005017 char *fileName, __u64 mode, __u64 uid, __u64 gid,
5018 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07005019 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020{
5021 TRANSACTION2_SPI_REQ *pSMB = NULL;
5022 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5023 int name_len;
5024 int rc = 0;
5025 int bytes_returned = 0;
5026 FILE_UNIX_BASIC_INFO *data_offset;
5027 __u16 params, param_offset, offset, count, byte_count;
5028
5029 cFYI(1, ("In SetUID/GID/Mode"));
5030setPermsRetry:
5031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5032 (void **) &pSMBr);
5033 if (rc)
5034 return rc;
5035
5036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5037 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005038 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005039 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 name_len++; /* trailing null */
5041 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005042 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 name_len = strnlen(fileName, PATH_MAX);
5044 name_len++; /* trailing null */
5045 strncpy(pSMB->FileName, fileName, name_len);
5046 }
5047
5048 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005049 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005051 /* BB find max SMB PDU from sess structure BB */
5052 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 pSMB->MaxSetupCount = 0;
5054 pSMB->Reserved = 0;
5055 pSMB->Flags = 0;
5056 pSMB->Timeout = 0;
5057 pSMB->Reserved2 = 0;
5058 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005059 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 offset = param_offset + params;
5061 data_offset =
5062 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5063 offset);
5064 memset(data_offset, 0, count);
5065 pSMB->DataOffset = cpu_to_le16(offset);
5066 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5067 pSMB->SetupCount = 1;
5068 pSMB->Reserved3 = 0;
5069 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5070 byte_count = 3 /* pad */ + params + count;
5071 pSMB->ParameterCount = cpu_to_le16(params);
5072 pSMB->DataCount = cpu_to_le16(count);
5073 pSMB->TotalParameterCount = pSMB->ParameterCount;
5074 pSMB->TotalDataCount = pSMB->DataCount;
5075 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5076 pSMB->Reserved4 = 0;
5077 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005078 /* Samba server ignores set of file size to zero due to bugs in some
5079 older clients, but we should be precise - we use SetFileSize to
5080 set file size and do not want to truncate file size to zero
5081 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005082 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005083 data_offset->EndOfFile = NO_CHANGE_64;
5084 data_offset->NumOfBytes = NO_CHANGE_64;
5085 data_offset->LastStatusChange = NO_CHANGE_64;
5086 data_offset->LastAccessTime = NO_CHANGE_64;
5087 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 data_offset->Uid = cpu_to_le64(uid);
5089 data_offset->Gid = cpu_to_le64(gid);
5090 /* better to leave device as zero when it is */
5091 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5092 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5093 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005094
Steve French790fe572007-07-07 19:25:05 +00005095 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005097 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005099 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005101 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005103 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005105 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005107 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5109
5110
5111 pSMB->ByteCount = cpu_to_le16(byte_count);
5112 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5113 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005114 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116
Steve French0d817bc2008-05-22 02:02:03 +00005117 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 if (rc == -EAGAIN)
5119 goto setPermsRetry;
5120 return rc;
5121}
5122
Steve French50c2f752007-07-13 00:33:32 +00005123int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005124 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005125 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005126 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127{
5128 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005129 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5130 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005131 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 int bytes_returned;
5133
Steve French50c2f752007-07-13 00:33:32 +00005134 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005136 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 if (rc)
5138 return rc;
5139
5140 pSMB->TotalParameterCount = 0 ;
5141 pSMB->TotalDataCount = 0;
5142 pSMB->MaxParameterCount = cpu_to_le32(2);
5143 /* BB find exact data count max from sess structure BB */
5144 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005145/* BB VERIFY verify which is correct for above BB */
5146 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5147 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5148
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 pSMB->MaxSetupCount = 4;
5150 pSMB->Reserved = 0;
5151 pSMB->ParameterOffset = 0;
5152 pSMB->DataCount = 0;
5153 pSMB->DataOffset = 0;
5154 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5155 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5156 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005157 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5159 pSMB->Reserved2 = 0;
5160 pSMB->CompletionFilter = cpu_to_le32(filter);
5161 pSMB->Fid = netfid; /* file handle always le */
5162 pSMB->ByteCount = 0;
5163
5164 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005165 (struct smb_hdr *)pSMBr, &bytes_returned,
5166 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 if (rc) {
5168 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005169 } else {
5170 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005171 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005172 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005173 sizeof(struct dir_notify_req),
5174 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005175 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005176 dnotify_req->Pid = pSMB->hdr.Pid;
5177 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5178 dnotify_req->Mid = pSMB->hdr.Mid;
5179 dnotify_req->Tid = pSMB->hdr.Tid;
5180 dnotify_req->Uid = pSMB->hdr.Uid;
5181 dnotify_req->netfid = netfid;
5182 dnotify_req->pfile = pfile;
5183 dnotify_req->filter = filter;
5184 dnotify_req->multishot = multishot;
5185 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005186 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005187 &GlobalDnotifyReqList);
5188 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005189 } else
Steve French47c786e2005-10-11 20:03:18 -07005190 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 }
5192 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005193 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194}
5195#ifdef CONFIG_CIFS_XATTR
5196ssize_t
5197CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5198 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005199 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005200 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201{
5202 /* BB assumes one setup word */
5203 TRANSACTION2_QPI_REQ *pSMB = NULL;
5204 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5205 int rc = 0;
5206 int bytes_returned;
5207 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005208 struct fea *temp_fea;
5209 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 __u16 params, byte_count;
5211
5212 cFYI(1, ("In Query All EAs path %s", searchName));
5213QAllEAsRetry:
5214 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5215 (void **) &pSMBr);
5216 if (rc)
5217 return rc;
5218
5219 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5220 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005221 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005222 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 name_len++; /* trailing null */
5224 name_len *= 2;
5225 } else { /* BB improve the check for buffer overruns BB */
5226 name_len = strnlen(searchName, PATH_MAX);
5227 name_len++; /* trailing null */
5228 strncpy(pSMB->FileName, searchName, name_len);
5229 }
5230
Steve French50c2f752007-07-13 00:33:32 +00005231 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 pSMB->TotalDataCount = 0;
5233 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005234 /* BB find exact max SMB PDU from sess structure BB */
5235 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 pSMB->MaxSetupCount = 0;
5237 pSMB->Reserved = 0;
5238 pSMB->Flags = 0;
5239 pSMB->Timeout = 0;
5240 pSMB->Reserved2 = 0;
5241 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005242 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 pSMB->DataCount = 0;
5244 pSMB->DataOffset = 0;
5245 pSMB->SetupCount = 1;
5246 pSMB->Reserved3 = 0;
5247 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5248 byte_count = params + 1 /* pad */ ;
5249 pSMB->TotalParameterCount = cpu_to_le16(params);
5250 pSMB->ParameterCount = pSMB->TotalParameterCount;
5251 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5252 pSMB->Reserved4 = 0;
5253 pSMB->hdr.smb_buf_length += byte_count;
5254 pSMB->ByteCount = cpu_to_le16(byte_count);
5255
5256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5258 if (rc) {
5259 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5260 } else { /* decode response */
5261 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5262
5263 /* BB also check enough total bytes returned */
5264 /* BB we need to improve the validity checking
5265 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005266 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 rc = -EIO; /* bad smb */
5268 /* else if (pFindData){
5269 memcpy((char *) pFindData,
5270 (char *) &pSMBr->hdr.Protocol +
5271 data_offset, kl);
5272 }*/ else {
5273 /* check that length of list is not more than bcc */
5274 /* check that each entry does not go beyond length
5275 of list */
5276 /* check that each element of each entry does not
5277 go beyond end of list */
5278 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005279 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 rc = 0;
5281 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005282 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 ea_response_data = (struct fealist *)
5284 (((char *) &pSMBr->hdr.Protocol) +
5285 data_offset);
5286 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005287 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005288 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005290 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 } else {
5292 /* account for ea list len */
5293 name_len -= 4;
5294 temp_fea = ea_response_data->list;
5295 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005296 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 __u16 value_len;
5298 name_len -= 4;
5299 temp_ptr += 4;
5300 rc += temp_fea->name_len;
5301 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005302 rc = rc + 5 + 1;
5303 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005304 memcpy(EAData, "user.", 5);
5305 EAData += 5;
5306 memcpy(EAData, temp_ptr,
5307 temp_fea->name_len);
5308 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 /* null terminate name */
5310 *EAData = 0;
5311 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005312 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 /* skip copy - calc size only */
5314 } else {
5315 /* stop before overrun buffer */
5316 rc = -ERANGE;
5317 break;
5318 }
5319 name_len -= temp_fea->name_len;
5320 temp_ptr += temp_fea->name_len;
5321 /* account for trailing null */
5322 name_len--;
5323 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005324 value_len =
5325 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 name_len -= value_len;
5327 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005328 /* BB check that temp_ptr is still
5329 within the SMB BB*/
5330
5331 /* no trailing null to account for
5332 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 /* go on to next EA */
5334 temp_fea = (struct fea *)temp_ptr;
5335 }
5336 }
5337 }
5338 }
Steve French0d817bc2008-05-22 02:02:03 +00005339 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 if (rc == -EAGAIN)
5341 goto QAllEAsRetry;
5342
5343 return (ssize_t)rc;
5344}
5345
Steve French50c2f752007-07-13 00:33:32 +00005346ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5347 const unsigned char *searchName, const unsigned char *ea_name,
5348 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005349 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350{
5351 TRANSACTION2_QPI_REQ *pSMB = NULL;
5352 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5353 int rc = 0;
5354 int bytes_returned;
5355 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005356 struct fea *temp_fea;
5357 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 __u16 params, byte_count;
5359
5360 cFYI(1, ("In Query EA path %s", searchName));
5361QEARetry:
5362 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5363 (void **) &pSMBr);
5364 if (rc)
5365 return rc;
5366
5367 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5368 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005369 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005370 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 name_len++; /* trailing null */
5372 name_len *= 2;
5373 } else { /* BB improve the check for buffer overruns BB */
5374 name_len = strnlen(searchName, PATH_MAX);
5375 name_len++; /* trailing null */
5376 strncpy(pSMB->FileName, searchName, name_len);
5377 }
5378
Steve French50c2f752007-07-13 00:33:32 +00005379 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 pSMB->TotalDataCount = 0;
5381 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005382 /* BB find exact max SMB PDU from sess structure BB */
5383 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 pSMB->MaxSetupCount = 0;
5385 pSMB->Reserved = 0;
5386 pSMB->Flags = 0;
5387 pSMB->Timeout = 0;
5388 pSMB->Reserved2 = 0;
5389 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005390 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 pSMB->DataCount = 0;
5392 pSMB->DataOffset = 0;
5393 pSMB->SetupCount = 1;
5394 pSMB->Reserved3 = 0;
5395 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5396 byte_count = params + 1 /* pad */ ;
5397 pSMB->TotalParameterCount = cpu_to_le16(params);
5398 pSMB->ParameterCount = pSMB->TotalParameterCount;
5399 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5400 pSMB->Reserved4 = 0;
5401 pSMB->hdr.smb_buf_length += byte_count;
5402 pSMB->ByteCount = cpu_to_le16(byte_count);
5403
5404 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5405 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5406 if (rc) {
5407 cFYI(1, ("Send error in Query EA = %d", rc));
5408 } else { /* decode response */
5409 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5410
5411 /* BB also check enough total bytes returned */
5412 /* BB we need to improve the validity checking
5413 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005414 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 rc = -EIO; /* bad smb */
5416 /* else if (pFindData){
5417 memcpy((char *) pFindData,
5418 (char *) &pSMBr->hdr.Protocol +
5419 data_offset, kl);
5420 }*/ else {
5421 /* check that length of list is not more than bcc */
5422 /* check that each entry does not go beyond length
5423 of list */
5424 /* check that each element of each entry does not
5425 go beyond end of list */
5426 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005427 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 rc = -ENODATA;
5429 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005430 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 ea_response_data = (struct fealist *)
5432 (((char *) &pSMBr->hdr.Protocol) +
5433 data_offset);
5434 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005435 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005436 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005438 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 } else {
5440 /* account for ea list len */
5441 name_len -= 4;
5442 temp_fea = ea_response_data->list;
5443 temp_ptr = (char *)temp_fea;
5444 /* loop through checking if we have a matching
5445 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005446 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 __u16 value_len;
5448 name_len -= 4;
5449 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005450 value_len =
5451 le16_to_cpu(temp_fea->value_len);
5452 /* BB validate that value_len falls within SMB,
5453 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005454 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 temp_fea->name_len) == 0) {
5456 /* found a match */
5457 rc = value_len;
5458 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005459 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 memcpy(ea_value,
5461 temp_fea->name+temp_fea->name_len+1,
5462 rc);
Steve French50c2f752007-07-13 00:33:32 +00005463 /* ea values, unlike ea
5464 names, are not null
5465 terminated */
Steve French790fe572007-07-07 19:25:05 +00005466 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 /* skip copy - calc size only */
5468 } else {
Steve French50c2f752007-07-13 00:33:32 +00005469 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 rc = -ERANGE;
5471 }
5472 break;
5473 }
5474 name_len -= temp_fea->name_len;
5475 temp_ptr += temp_fea->name_len;
5476 /* account for trailing null */
5477 name_len--;
5478 temp_ptr++;
5479 name_len -= value_len;
5480 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005481 /* No trailing null to account for in
5482 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 temp_fea = (struct fea *)temp_ptr;
5484 }
Steve French50c2f752007-07-13 00:33:32 +00005485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 }
5487 }
Steve French0d817bc2008-05-22 02:02:03 +00005488 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 if (rc == -EAGAIN)
5490 goto QEARetry;
5491
5492 return (ssize_t)rc;
5493}
5494
5495int
5496CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005497 const char *ea_name, const void *ea_value,
5498 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5499 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500{
5501 struct smb_com_transaction2_spi_req *pSMB = NULL;
5502 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5503 struct fealist *parm_data;
5504 int name_len;
5505 int rc = 0;
5506 int bytes_returned = 0;
5507 __u16 params, param_offset, byte_count, offset, count;
5508
5509 cFYI(1, ("In SetEA"));
5510SetEARetry:
5511 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5512 (void **) &pSMBr);
5513 if (rc)
5514 return rc;
5515
5516 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5517 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005518 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005519 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 name_len++; /* trailing null */
5521 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005522 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 name_len = strnlen(fileName, PATH_MAX);
5524 name_len++; /* trailing null */
5525 strncpy(pSMB->FileName, fileName, name_len);
5526 }
5527
5528 params = 6 + name_len;
5529
5530 /* done calculating parms using name_len of file name,
5531 now use name_len to calculate length of ea name
5532 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005533 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 name_len = 0;
5535 else
Steve French50c2f752007-07-13 00:33:32 +00005536 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005538 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005540 /* BB find max SMB PDU from sess */
5541 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 pSMB->MaxSetupCount = 0;
5543 pSMB->Reserved = 0;
5544 pSMB->Flags = 0;
5545 pSMB->Timeout = 0;
5546 pSMB->Reserved2 = 0;
5547 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005548 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 offset = param_offset + params;
5550 pSMB->InformationLevel =
5551 cpu_to_le16(SMB_SET_FILE_EA);
5552
5553 parm_data =
5554 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5555 offset);
5556 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5557 pSMB->DataOffset = cpu_to_le16(offset);
5558 pSMB->SetupCount = 1;
5559 pSMB->Reserved3 = 0;
5560 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5561 byte_count = 3 /* pad */ + params + count;
5562 pSMB->DataCount = cpu_to_le16(count);
5563 parm_data->list_len = cpu_to_le32(count);
5564 parm_data->list[0].EA_flags = 0;
5565 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005566 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005568 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005569 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 parm_data->list[0].name[name_len] = 0;
5571 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5572 /* caller ensures that ea_value_len is less than 64K but
5573 we need to ensure that it fits within the smb */
5574
Steve French50c2f752007-07-13 00:33:32 +00005575 /*BB add length check to see if it would fit in
5576 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005577 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5578 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005579 memcpy(parm_data->list[0].name+name_len+1,
5580 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581
5582 pSMB->TotalDataCount = pSMB->DataCount;
5583 pSMB->ParameterCount = cpu_to_le16(params);
5584 pSMB->TotalParameterCount = pSMB->ParameterCount;
5585 pSMB->Reserved4 = 0;
5586 pSMB->hdr.smb_buf_length += byte_count;
5587 pSMB->ByteCount = cpu_to_le16(byte_count);
5588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005590 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592
5593 cifs_buf_release(pSMB);
5594
5595 if (rc == -EAGAIN)
5596 goto SetEARetry;
5597
5598 return rc;
5599}
5600
5601#endif