blob: 824df142f288125f7ddfbe710c17da42c98094f9 [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 Frenchad8b15f2008-08-08 21:10:16 +0000131 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700134 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
135 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Steve Frenchad7a2922008-02-07 23:25:02 +0000138/* Allocate and return pointer to an SMB request buffer, and set basic
139 SMB information in the SMB header. If the return code is zero, this
140 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int
142small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000143 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
145 int rc = 0;
146
147 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
148 check for tcp and smb session status done differently
149 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000150 if (tcon) {
151 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800152 /* only tree disconnect, open, and write,
153 (and ulogoff which does not have tcon)
154 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000155 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000156 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800157 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000158 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800159 smb_command));
160 return -ENODEV;
161 }
162 }
Steve French790fe572007-07-07 19:25:05 +0000163 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000164 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000166 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700167 reconnect, should be greater than cifs socket
168 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000169 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000170 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000172 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000173 CifsGood), 10 * HZ);
174 if (tcon->ses->server->tcpStatus ==
175 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000177 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000179 cFYI(1, ("gave up waiting on "
180 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700182 } /* else "hard" mount - keep retrying
183 until process is killed or server
184 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 } else /* TCP session is reestablished now */
186 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 }
Steve French50c2f752007-07-13 00:33:32 +0000188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 nls_codepage = load_nls_default();
190 /* need to prevent multiple threads trying to
191 simultaneously reconnect the same SMB session */
192 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000193 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000194 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700195 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000196 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000198 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000199 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700201 /* BB FIXME add code to check if wsize needs
202 update due to negotiated smb buffer size
203 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000204 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000206 /* tell server Unix caps we support */
207 if (tcon->ses->capabilities & CAP_UNIX)
208 reset_cifs_unix_caps(
209 0 /* no xid */,
210 tcon,
211 NULL /* we do not know sb */,
212 NULL /* no vol info */);
213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000216 /* Removed call to reopen open files here.
217 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700218 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Steve French50c2f752007-07-13 00:33:32 +0000220 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700221 know whether we can continue or not without
222 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000223 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 case SMB_COM_READ_ANDX:
225 case SMB_COM_WRITE_ANDX:
226 case SMB_COM_CLOSE:
227 case SMB_COM_FIND_CLOSE2:
228 case SMB_COM_LOCKING_ANDX: {
229 unload_nls(nls_codepage);
230 return -EAGAIN;
231 }
232 }
233 } else {
234 up(&tcon->ses->sesSem);
235 }
236 unload_nls(nls_codepage);
237
238 } else {
239 return -EIO;
240 }
241 }
Steve French790fe572007-07-07 19:25:05 +0000242 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 return rc;
244
245 *request_buf = cifs_small_buf_get();
246 if (*request_buf == NULL) {
247 /* BB should we add a retry in here if not a writepage? */
248 return -ENOMEM;
249 }
250
Steve French63135e02007-07-17 17:34:02 +0000251 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000252 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Steve French790fe572007-07-07 19:25:05 +0000254 if (tcon != NULL)
255 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000258}
259
Steve French12b3b8f2006-02-09 21:12:47 +0000260int
Steve French50c2f752007-07-13 00:33:32 +0000261small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000262 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000263{
264 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000265 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000266
Steve French5815449d2006-02-14 01:36:20 +0000267 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000268 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000269 return rc;
270
Steve French04fdabe2006-02-10 05:52:50 +0000271 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000272 buffer->Mid = GetNextMid(ses->server);
273 if (ses->capabilities & CAP_UNICODE)
274 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000275 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000276 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
277
278 /* uid, tid can stay at zero as set in header assemble */
279
Steve French50c2f752007-07-13 00:33:32 +0000280 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000281 this function is used after 1st of session setup requests */
282
283 return rc;
284}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286/* If the return code is zero, this function must fill in request_buf pointer */
287static int
288smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
289 void **request_buf /* returned */ ,
290 void **response_buf /* returned */ )
291{
292 int rc = 0;
293
294 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
295 check for tcp and smb session status done differently
296 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000297 if (tcon) {
Steve Frenchbfb59822008-11-18 16:33:48 +0000298 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800299 /* only tree disconnect, open, and write,
300 (and ulogoff which does not have tcon)
301 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000302 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800303 (smb_command != SMB_COM_OPEN_ANDX) &&
304 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000305 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800306 smb_command));
307 return -ENODEV;
308 }
309 }
310
Steve French790fe572007-07-07 19:25:05 +0000311 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000312 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700314 /* Give Demultiplex thread up to 10 seconds to
315 reconnect, should be greater than cifs socket
316 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000317 while (tcon->ses->server->tcpStatus ==
318 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000320 (tcon->ses->server->tcpStatus ==
321 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000322 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700323 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000325 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000327 cFYI(1, ("gave up waiting on "
328 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700330 } /* else "hard" mount - keep retrying
331 until process is killed or server
332 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 } else /* TCP session is reestablished now */
334 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 nls_codepage = load_nls_default();
337 /* need to prevent multiple threads trying to
338 simultaneously reconnect the same SMB session */
339 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000340 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000341 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700342 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000343 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700345 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
346 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700348 /* BB FIXME add code to check if wsize needs
349 update due to negotiated smb buffer size
350 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000351 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000353 /* tell server Unix caps we support */
354 if (tcon->ses->capabilities & CAP_UNIX)
355 reset_cifs_unix_caps(
356 0 /* no xid */,
357 tcon,
358 NULL /* do not know sb */,
359 NULL /* no vol info */);
360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000363 /* Removed call to reopen open files here.
364 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700365 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Steve French50c2f752007-07-13 00:33:32 +0000367 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700368 know whether we can continue or not without
369 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000370 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 case SMB_COM_READ_ANDX:
372 case SMB_COM_WRITE_ANDX:
373 case SMB_COM_CLOSE:
374 case SMB_COM_FIND_CLOSE2:
375 case SMB_COM_LOCKING_ANDX: {
376 unload_nls(nls_codepage);
377 return -EAGAIN;
378 }
379 }
380 } else {
381 up(&tcon->ses->sesSem);
382 }
383 unload_nls(nls_codepage);
384
385 } else {
386 return -EIO;
387 }
388 }
Steve French790fe572007-07-07 19:25:05 +0000389 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 return rc;
391
392 *request_buf = cifs_buf_get();
393 if (*request_buf == NULL) {
394 /* BB should we add a retry in here if not a writepage? */
395 return -ENOMEM;
396 }
397 /* Although the original thought was we needed the response buf for */
398 /* potential retries of smb operations it turns out we can determine */
399 /* from the mid flags when the request buffer can be resent without */
400 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000401 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000402 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000405 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Steve French790fe572007-07-07 19:25:05 +0000407 if (tcon != NULL)
408 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 return rc;
411}
412
Steve French50c2f752007-07-13 00:33:32 +0000413static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414{
415 int rc = -EINVAL;
416 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000417 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 /* check for plausible wct, bcc and t2 data and parm sizes */
420 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000421 if (pSMB->hdr.WordCount >= 10) {
422 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
424 /* check that bcc is at least as big as parms + data */
425 /* check that bcc is less than negotiated smb buffer */
426 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000427 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000428 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000429 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000431 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700432 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000434 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000435 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
437 return 0;
438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
440 }
441 }
Steve French50c2f752007-07-13 00:33:32 +0000442 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 sizeof(struct smb_t2_rsp) + 16);
444 return rc;
445}
446int
447CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
448{
449 NEGOTIATE_REQ *pSMB;
450 NEGOTIATE_RSP *pSMBr;
451 int rc = 0;
452 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000453 int i;
Steve French50c2f752007-07-13 00:33:32 +0000454 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000456 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100457 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Steve French790fe572007-07-07 19:25:05 +0000459 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 server = ses->server;
461 else {
462 rc = -EIO;
463 return rc;
464 }
465 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
466 (void **) &pSMB, (void **) &pSMBr);
467 if (rc)
468 return rc;
Steve French750d1152006-06-27 06:28:30 +0000469
470 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000471 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000472 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000473 else /* if override flags set only sign/seal OR them with global auth */
474 secFlags = extended_security | ses->overrideSecFlg;
475
Steve French762e5ab2007-06-28 18:41:42 +0000476 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000477
Steve French1982c342005-08-17 12:38:22 -0700478 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000479 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000480
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000481 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000482 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000483 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
484 cFYI(1, ("Kerberos only mechanism, enable extended security"));
485 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
486 }
Steve French50c2f752007-07-13 00:33:32 +0000487
Steve French39798772006-05-31 22:40:51 +0000488 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000489 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000490 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
491 count += strlen(protocols[i].name) + 1;
492 /* null at end of source and target buffers anyway */
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 pSMB->hdr.smb_buf_length += count;
495 pSMB->ByteCount = cpu_to_le16(count);
496
497 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000499 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000500 goto neg_err_exit;
501
Al Viro733f99a2006-10-14 16:48:26 +0100502 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000503 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000504 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000505 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000506 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000507 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000508 could not negotiate a common dialect */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000511#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000512 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100513 && ((dialect == LANMAN_PROT)
514 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000515 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000516 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000517
Steve French790fe572007-07-07 19:25:05 +0000518 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000519 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000520 server->secType = LANMAN;
521 else {
522 cERROR(1, ("mount failed weak security disabled"
523 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000524 rc = -EOPNOTSUPP;
525 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000526 }
Steve French254e55e2006-06-04 05:53:15 +0000527 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
528 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
529 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000530 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000531 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
532 /* even though we do not use raw we might as well set this
533 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000534 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000535 server->maxRw = 0xFF00;
536 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
537 } else {
538 server->maxRw = 0;/* we do not need to use raw anyway */
539 server->capabilities = CAP_MPX_MODE;
540 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000541 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000542 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000543 /* OS/2 often does not set timezone therefore
544 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000545 * Could deviate slightly from the right zone.
546 * Smallest defined timezone difference is 15 minutes
547 * (i.e. Nepal). Rounding up/down is done to match
548 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000549 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000550 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000551 struct timespec ts, utc;
552 utc = CURRENT_TIME;
553 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
554 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000555 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
556 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000557 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000558 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000559 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000560 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000561 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000562 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000563 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000564 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000565 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000566 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000567 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000568 server->timeAdj = (int)tmp;
569 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000570 }
Steve French790fe572007-07-07 19:25:05 +0000571 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000572
Steve French39798772006-05-31 22:40:51 +0000573
Steve French254e55e2006-06-04 05:53:15 +0000574 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000575 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000576
Steve French50c2f752007-07-13 00:33:32 +0000577 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000578 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000579 memcpy(server->cryptKey, rsp->EncryptionKey,
580 CIFS_CRYPTO_KEY_SIZE);
581 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
582 rc = -EIO; /* need cryptkey unless plain text */
583 goto neg_err_exit;
584 }
Steve French39798772006-05-31 22:40:51 +0000585
Steve French790fe572007-07-07 19:25:05 +0000586 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000587 /* we will not end up setting signing flags - as no signing
588 was in LANMAN and server did not return the flags on */
589 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000590#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000591 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000592 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000593 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000594 rc = -EOPNOTSUPP;
595#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000596 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000597 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000598 /* unknown wct */
599 rc = -EOPNOTSUPP;
600 goto neg_err_exit;
601 }
602 /* else wct == 17 NTLM */
603 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000604 if ((server->secMode & SECMODE_USER) == 0)
605 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000606
Steve French790fe572007-07-07 19:25:05 +0000607 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000608#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000609 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000610#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000611 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000612 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000613
Steve French790fe572007-07-07 19:25:05 +0000614 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000615 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000616 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000617 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000618 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000619 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000620 else if (secFlags & CIFSSEC_MAY_KRB5)
621 server->secType = Kerberos;
622 else if (secFlags & CIFSSEC_MAY_LANMAN)
623 server->secType = LANMAN;
624/* #ifdef CONFIG_CIFS_EXPERIMENTAL
625 else if (secFlags & CIFSSEC_MAY_PLNTXT)
626 server->secType = ??
627#endif */
628 else {
629 rc = -EOPNOTSUPP;
630 cERROR(1, ("Invalid security type"));
631 goto neg_err_exit;
632 }
633 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000634
Steve French254e55e2006-06-04 05:53:15 +0000635 /* one byte, so no need to convert this or EncryptionKeyLen from
636 little endian */
637 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
638 /* probably no need to store and check maxvcs */
639 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000641 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000642 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000643 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
644 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000645 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
646 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000647 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
648 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
649 CIFS_CRYPTO_KEY_SIZE);
650 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
651 && (pSMBr->EncryptionKeyLength == 0)) {
652 /* decode security blob */
653 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
654 rc = -EIO; /* no crypt key only if plain text pwd */
655 goto neg_err_exit;
656 }
657
658 /* BB might be helpful to save off the domain of server here */
659
Steve French50c2f752007-07-13 00:33:32 +0000660 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000661 (server->capabilities & CAP_EXTENDED_SECURITY)) {
662 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000663 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000665 goto neg_err_exit;
666 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500667 read_lock(&cifs_tcp_ses_lock);
668 if (server->srv_count > 1) {
669 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000670 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 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500678 } else {
679 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000680 memcpy(server->server_GUID,
681 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500682 }
Jeff Laytone187e442007-10-16 17:10:44 +0000683
684 if (count == 16) {
685 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000686 } else {
687 rc = decode_negTokenInit(pSMBr->u.extended_response.
688 SecurityBlob,
689 count - 16,
690 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000691 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000692 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000693 else
Steve French254e55e2006-06-04 05:53:15 +0000694 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
Steve French254e55e2006-06-04 05:53:15 +0000696 } else
697 server->capabilities &= ~CAP_EXTENDED_SECURITY;
698
Steve French6344a422006-06-12 04:18:35 +0000699#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000700signing_check:
Steve French6344a422006-06-12 04:18:35 +0000701#endif
Steve French762e5ab2007-06-28 18:41:42 +0000702 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
703 /* MUST_SIGN already includes the MAY_SIGN FLAG
704 so if this is zero it means that signing is disabled */
705 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000706 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000707 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000708 "packet signing to be enabled in "
709 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000710 rc = -EOPNOTSUPP;
711 }
Steve French50c2f752007-07-13 00:33:32 +0000712 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000713 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000714 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
715 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000716 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000717 if ((server->secMode &
718 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
719 cERROR(1,
720 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000721 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000722 } else
723 server->secMode |= SECMODE_SIGN_REQUIRED;
724 } else {
725 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000726 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000727 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000728 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
Steve French50c2f752007-07-13 00:33:32 +0000730
731neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700732 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000733
Steve French790fe572007-07-07 19:25:05 +0000734 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return rc;
736}
737
738int
739CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
740{
741 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500745
746 /* BB: do we need to check this? These should never be NULL. */
747 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
748 return -EIO;
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500751 * No need to return error on this operation if tid invalidated and
752 * closed on server already e.g. due to tcp session crashing. Also,
753 * the tcon is no longer on the list, so no need to take lock before
754 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 */
Jeff Laytonf1987b42008-11-15 11:12:47 -0500756 if (tcon->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000757 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Steve French50c2f752007-07-13 00:33:32 +0000759 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700760 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500761 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return rc;
Steve French133672e2007-11-13 22:41:37 +0000763
764 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700766 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Steve French50c2f752007-07-13 00:33:32 +0000768 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500769 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (rc == -EAGAIN)
771 rc = 0;
772
773 return rc;
774}
775
776int
777CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
778{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 LOGOFF_ANDX_REQ *pSMB;
780 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500783
784 /*
785 * BB: do we need to check validity of ses and server? They should
786 * always be valid since we have an active reference. If not, that
787 * should probably be a BUG()
788 */
789 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 return -EIO;
791
Jeff Layton14fbf502008-11-14 13:53:46 -0500792 down(&ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000793 if (ses->need_reconnect)
794 goto session_already_dead; /* no need to send SMBlogoff if uid
795 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
797 if (rc) {
798 up(&ses->sesSem);
799 return rc;
800 }
801
Steve French3b795212008-11-13 19:45:32 +0000802 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700803
Steve French3b795212008-11-13 19:45:32 +0000804 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
806 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 pSMB->hdr.Uid = ses->Suid;
809
810 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000811 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000812session_already_dead:
Steve Frencha59c6582005-08-17 12:12:19 -0700813 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
815 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000816 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 error */
818 if (rc == -EAGAIN)
819 rc = 0;
820 return rc;
821}
822
823int
Steve French2d785a52007-07-15 01:48:57 +0000824CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
825 __u16 type, const struct nls_table *nls_codepage, int remap)
826{
827 TRANSACTION2_SPI_REQ *pSMB = NULL;
828 TRANSACTION2_SPI_RSP *pSMBr = NULL;
829 struct unlink_psx_rq *pRqD;
830 int name_len;
831 int rc = 0;
832 int bytes_returned = 0;
833 __u16 params, param_offset, offset, byte_count;
834
835 cFYI(1, ("In POSIX delete"));
836PsxDelete:
837 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
838 (void **) &pSMBr);
839 if (rc)
840 return rc;
841
842 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
843 name_len =
844 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
845 PATH_MAX, nls_codepage, remap);
846 name_len++; /* trailing null */
847 name_len *= 2;
848 } else { /* BB add path length overrun check */
849 name_len = strnlen(fileName, PATH_MAX);
850 name_len++; /* trailing null */
851 strncpy(pSMB->FileName, fileName, name_len);
852 }
853
854 params = 6 + name_len;
855 pSMB->MaxParameterCount = cpu_to_le16(2);
856 pSMB->MaxDataCount = 0; /* BB double check this with jra */
857 pSMB->MaxSetupCount = 0;
858 pSMB->Reserved = 0;
859 pSMB->Flags = 0;
860 pSMB->Timeout = 0;
861 pSMB->Reserved2 = 0;
862 param_offset = offsetof(struct smb_com_transaction2_spi_req,
863 InformationLevel) - 4;
864 offset = param_offset + params;
865
866 /* Setup pointer to Request Data (inode type) */
867 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
868 pRqD->type = cpu_to_le16(type);
869 pSMB->ParameterOffset = cpu_to_le16(param_offset);
870 pSMB->DataOffset = cpu_to_le16(offset);
871 pSMB->SetupCount = 1;
872 pSMB->Reserved3 = 0;
873 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
874 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
875
876 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
877 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
878 pSMB->ParameterCount = cpu_to_le16(params);
879 pSMB->TotalParameterCount = pSMB->ParameterCount;
880 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
881 pSMB->Reserved4 = 0;
882 pSMB->hdr.smb_buf_length += byte_count;
883 pSMB->ByteCount = cpu_to_le16(byte_count);
884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000886 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000887 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000888 cifs_buf_release(pSMB);
889
890 cifs_stats_inc(&tcon->num_deletes);
891
892 if (rc == -EAGAIN)
893 goto PsxDelete;
894
895 return rc;
896}
897
898int
Steve French737b7582005-04-28 22:41:06 -0700899CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
900 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 DELETE_FILE_REQ *pSMB = NULL;
903 DELETE_FILE_RSP *pSMBr = NULL;
904 int rc = 0;
905 int bytes_returned;
906 int name_len;
907
908DelFileRetry:
909 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
910 (void **) &pSMBr);
911 if (rc)
912 return rc;
913
914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
915 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000916 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700917 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 name_len++; /* trailing null */
919 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700920 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 name_len = strnlen(fileName, PATH_MAX);
922 name_len++; /* trailing null */
923 strncpy(pSMB->fileName, fileName, name_len);
924 }
925 pSMB->SearchAttributes =
926 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
927 pSMB->BufferFormat = 0x04;
928 pSMB->hdr.smb_buf_length += name_len + 1;
929 pSMB->ByteCount = cpu_to_le16(name_len + 1);
930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700932 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000933 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 cifs_buf_release(pSMB);
937 if (rc == -EAGAIN)
938 goto DelFileRetry;
939
940 return rc;
941}
942
943int
Steve French50c2f752007-07-13 00:33:32 +0000944CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700945 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
947 DELETE_DIRECTORY_REQ *pSMB = NULL;
948 DELETE_DIRECTORY_RSP *pSMBr = NULL;
949 int rc = 0;
950 int bytes_returned;
951 int name_len;
952
953 cFYI(1, ("In CIFSSMBRmDir"));
954RmDirRetry:
955 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
956 (void **) &pSMBr);
957 if (rc)
958 return rc;
959
960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700961 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 name_len++; /* trailing null */
964 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700965 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 name_len = strnlen(dirName, PATH_MAX);
967 name_len++; /* trailing null */
968 strncpy(pSMB->DirName, dirName, name_len);
969 }
970
971 pSMB->BufferFormat = 0x04;
972 pSMB->hdr.smb_buf_length += name_len + 1;
973 pSMB->ByteCount = cpu_to_le16(name_len + 1);
974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700976 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000977 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980 cifs_buf_release(pSMB);
981 if (rc == -EAGAIN)
982 goto RmDirRetry;
983 return rc;
984}
985
986int
987CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700988 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
990 int rc = 0;
991 CREATE_DIRECTORY_REQ *pSMB = NULL;
992 CREATE_DIRECTORY_RSP *pSMBr = NULL;
993 int bytes_returned;
994 int name_len;
995
996 cFYI(1, ("In CIFSSMBMkDir"));
997MkDirRetry:
998 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
999 (void **) &pSMBr);
1000 if (rc)
1001 return rc;
1002
1003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001004 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001005 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 name_len++; /* trailing null */
1007 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001008 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 name_len = strnlen(name, PATH_MAX);
1010 name_len++; /* trailing null */
1011 strncpy(pSMB->DirName, name, name_len);
1012 }
1013
1014 pSMB->BufferFormat = 0x04;
1015 pSMB->hdr.smb_buf_length += name_len + 1;
1016 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1017 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1018 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001019 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001020 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07001022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 cifs_buf_release(pSMB);
1024 if (rc == -EAGAIN)
1025 goto MkDirRetry;
1026 return rc;
1027}
1028
Steve French2dd29d32007-04-23 22:07:35 +00001029int
1030CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001031 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001032 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001033 const struct nls_table *nls_codepage, int remap)
1034{
1035 TRANSACTION2_SPI_REQ *pSMB = NULL;
1036 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1037 int name_len;
1038 int rc = 0;
1039 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001040 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001041 OPEN_PSX_REQ *pdata;
1042 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001043
1044 cFYI(1, ("In POSIX Create"));
1045PsxCreat:
1046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1047 (void **) &pSMBr);
1048 if (rc)
1049 return rc;
1050
1051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1052 name_len =
1053 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1054 PATH_MAX, nls_codepage, remap);
1055 name_len++; /* trailing null */
1056 name_len *= 2;
1057 } else { /* BB improve the check for buffer overruns BB */
1058 name_len = strnlen(name, PATH_MAX);
1059 name_len++; /* trailing null */
1060 strncpy(pSMB->FileName, name, name_len);
1061 }
1062
1063 params = 6 + name_len;
1064 count = sizeof(OPEN_PSX_REQ);
1065 pSMB->MaxParameterCount = cpu_to_le16(2);
1066 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1067 pSMB->MaxSetupCount = 0;
1068 pSMB->Reserved = 0;
1069 pSMB->Flags = 0;
1070 pSMB->Timeout = 0;
1071 pSMB->Reserved2 = 0;
1072 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001073 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001074 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001075 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001076 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001077 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001078 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata->OpenFlags = cpu_to_le32(*pOplock);
1080 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1081 pSMB->DataOffset = cpu_to_le16(offset);
1082 pSMB->SetupCount = 1;
1083 pSMB->Reserved3 = 0;
1084 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1085 byte_count = 3 /* pad */ + params + count;
1086
1087 pSMB->DataCount = cpu_to_le16(count);
1088 pSMB->ParameterCount = cpu_to_le16(params);
1089 pSMB->TotalDataCount = pSMB->DataCount;
1090 pSMB->TotalParameterCount = pSMB->ParameterCount;
1091 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1092 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001093 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001094 pSMB->ByteCount = cpu_to_le16(byte_count);
1095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1097 if (rc) {
1098 cFYI(1, ("Posix create returned %d", rc));
1099 goto psx_create_err;
1100 }
1101
Steve French790fe572007-07-07 19:25:05 +00001102 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1104
1105 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1106 rc = -EIO; /* bad smb */
1107 goto psx_create_err;
1108 }
1109
1110 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001111 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001112 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001113
Steve French2dd29d32007-04-23 22:07:35 +00001114 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001115 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001116 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1117 /* Let caller know file was created so we can set the mode. */
1118 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001119 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001120 *pOplock |= CIFS_CREATE_ACTION;
1121 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001122 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1123 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001124 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001125 } else {
Steve French790fe572007-07-07 19:25:05 +00001126 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001127 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001128 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001129 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001130 goto psx_create_err;
1131 }
Steve French50c2f752007-07-13 00:33:32 +00001132 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001133 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001134 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001135 }
Steve French2dd29d32007-04-23 22:07:35 +00001136
1137psx_create_err:
1138 cifs_buf_release(pSMB);
1139
1140 cifs_stats_inc(&tcon->num_mkdirs);
1141
1142 if (rc == -EAGAIN)
1143 goto PsxCreat;
1144
Steve French50c2f752007-07-13 00:33:32 +00001145 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001146}
1147
Steve Frencha9d02ad2005-08-24 23:06:05 -07001148static __u16 convert_disposition(int disposition)
1149{
1150 __u16 ofun = 0;
1151
1152 switch (disposition) {
1153 case FILE_SUPERSEDE:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1155 break;
1156 case FILE_OPEN:
1157 ofun = SMBOPEN_OAPPEND;
1158 break;
1159 case FILE_CREATE:
1160 ofun = SMBOPEN_OCREATE;
1161 break;
1162 case FILE_OPEN_IF:
1163 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1164 break;
1165 case FILE_OVERWRITE:
1166 ofun = SMBOPEN_OTRUNC;
1167 break;
1168 case FILE_OVERWRITE_IF:
1169 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1170 break;
1171 default:
Steve French790fe572007-07-07 19:25:05 +00001172 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173 ofun = SMBOPEN_OAPPEND; /* regular open */
1174 }
1175 return ofun;
1176}
1177
Jeff Layton35fc37d2008-05-14 10:22:03 -07001178static int
1179access_flags_to_smbopen_mode(const int access_flags)
1180{
1181 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1182
1183 if (masked_flags == GENERIC_READ)
1184 return SMBOPEN_READ;
1185 else if (masked_flags == GENERIC_WRITE)
1186 return SMBOPEN_WRITE;
1187
1188 /* just go for read/write */
1189 return SMBOPEN_READWRITE;
1190}
1191
Steve Frencha9d02ad2005-08-24 23:06:05 -07001192int
1193SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1194 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001195 const int access_flags, const int create_options, __u16 *netfid,
1196 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197 const struct nls_table *nls_codepage, int remap)
1198{
1199 int rc = -EACCES;
1200 OPENX_REQ *pSMB = NULL;
1201 OPENX_RSP *pSMBr = NULL;
1202 int bytes_returned;
1203 int name_len;
1204 __u16 count;
1205
1206OldOpenRetry:
1207 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1208 (void **) &pSMBr);
1209 if (rc)
1210 return rc;
1211
1212 pSMB->AndXCommand = 0xFF; /* none */
1213
1214 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1215 count = 1; /* account for one byte pad to word boundary */
1216 name_len =
1217 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1218 fileName, PATH_MAX, nls_codepage, remap);
1219 name_len++; /* trailing null */
1220 name_len *= 2;
1221 } else { /* BB improve check for buffer overruns BB */
1222 count = 0; /* no pad */
1223 name_len = strnlen(fileName, PATH_MAX);
1224 name_len++; /* trailing null */
1225 strncpy(pSMB->fileName, fileName, name_len);
1226 }
1227 if (*pOplock & REQ_OPLOCK)
1228 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001229 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001231
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001233 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1235 /* set file as system file if special file such
1236 as fifo and server expecting SFU style and
1237 no Unix extensions */
1238
Steve French790fe572007-07-07 19:25:05 +00001239 if (create_options & CREATE_OPTION_SPECIAL)
1240 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001241 else /* BB FIXME BB */
1242 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243
Jeff Layton67750fb2008-05-09 22:28:02 +00001244 if (create_options & CREATE_OPTION_READONLY)
1245 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246
1247 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001248/* pSMB->CreateOptions = cpu_to_le32(create_options &
1249 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001251
1252 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001253 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 count += name_len;
1255 pSMB->hdr.smb_buf_length += count;
1256
1257 pSMB->ByteCount = cpu_to_le16(count);
1258 /* long_op set to 1 to allow for oplock break timeouts */
1259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001260 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 cifs_stats_inc(&tcon->num_opens);
1262 if (rc) {
1263 cFYI(1, ("Error in Open = %d", rc));
1264 } else {
1265 /* BB verify if wct == 15 */
1266
Steve French582d21e2008-05-13 04:54:12 +00001267/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268
1269 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1270 /* Let caller know file was created so we can set the mode. */
1271 /* Do we care about the CreateAction in any other cases? */
1272 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001273/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 *pOplock |= CIFS_CREATE_ACTION; */
1275 /* BB FIXME END */
1276
Steve French790fe572007-07-07 19:25:05 +00001277 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001278 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1279 pfile_info->LastAccessTime = 0; /* BB fixme */
1280 pfile_info->LastWriteTime = 0; /* BB fixme */
1281 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001282 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001283 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001284 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001285 pfile_info->AllocationSize =
1286 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1287 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001288 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001289 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001290 }
1291 }
1292
1293 cifs_buf_release(pSMB);
1294 if (rc == -EAGAIN)
1295 goto OldOpenRetry;
1296 return rc;
1297}
1298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299int
1300CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1301 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001302 const int access_flags, const int create_options, __u16 *netfid,
1303 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001304 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305{
1306 int rc = -EACCES;
1307 OPEN_REQ *pSMB = NULL;
1308 OPEN_RSP *pSMBr = NULL;
1309 int bytes_returned;
1310 int name_len;
1311 __u16 count;
1312
1313openRetry:
1314 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1315 (void **) &pSMBr);
1316 if (rc)
1317 return rc;
1318
1319 pSMB->AndXCommand = 0xFF; /* none */
1320
1321 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1322 count = 1; /* account for one byte pad to word boundary */
1323 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001324 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001325 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 name_len++; /* trailing null */
1327 name_len *= 2;
1328 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001329 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 count = 0; /* no pad */
1331 name_len = strnlen(fileName, PATH_MAX);
1332 name_len++; /* trailing null */
1333 pSMB->NameLength = cpu_to_le16(name_len);
1334 strncpy(pSMB->fileName, fileName, name_len);
1335 }
1336 if (*pOplock & REQ_OPLOCK)
1337 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001338 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1341 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001342 /* set file as system file if special file such
1343 as fifo and server expecting SFU style and
1344 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001345 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001346 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1347 else
1348 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 /* XP does not handle ATTR_POSIX_SEMANTICS */
1351 /* but it helps speed up case sensitive checks for other
1352 servers such as Samba */
1353 if (tcon->ses->capabilities & CAP_UNIX)
1354 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1355
Jeff Layton67750fb2008-05-09 22:28:02 +00001356 if (create_options & CREATE_OPTION_READONLY)
1357 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1358
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1360 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001361 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001362 /* BB Expirement with various impersonation levels and verify */
1363 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 pSMB->SecurityFlags =
1365 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1366
1367 count += name_len;
1368 pSMB->hdr.smb_buf_length += count;
1369
1370 pSMB->ByteCount = cpu_to_le16(count);
1371 /* long_op set to 1 to allow for oplock break timeouts */
1372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001373 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001374 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if (rc) {
1376 cFYI(1, ("Error in Open = %d", rc));
1377 } else {
Steve French09d1db52005-04-28 22:41:08 -07001378 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1380 /* Let caller know file was created so we can set the mode. */
1381 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001382 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001383 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001384 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001385 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1386 36 /* CreationTime to Attributes */);
1387 /* the file_info buf is endian converted by caller */
1388 pfile_info->AllocationSize = pSMBr->AllocationSize;
1389 pfile_info->EndOfFile = pSMBr->EndOfFile;
1390 pfile_info->NumberOfLinks = cpu_to_le32(1);
1391 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001394
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 cifs_buf_release(pSMB);
1396 if (rc == -EAGAIN)
1397 goto openRetry;
1398 return rc;
1399}
1400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401int
Steve French50c2f752007-07-13 00:33:32 +00001402CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1403 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1404 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405{
1406 int rc = -EACCES;
1407 READ_REQ *pSMB = NULL;
1408 READ_RSP *pSMBr = NULL;
1409 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001410 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001411 int resp_buf_type = 0;
1412 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
Steve French790fe572007-07-07 19:25:05 +00001414 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1415 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001416 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001417 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001418 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001419 if ((lseek >> 32) > 0) {
1420 /* can not handle this big offset for old */
1421 return -EIO;
1422 }
1423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
1425 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001426 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 if (rc)
1428 return rc;
1429
1430 /* tcon and ses pointer are checked in smb_init */
1431 if (tcon->ses->server == NULL)
1432 return -ECONNABORTED;
1433
Steve Frenchec637e32005-12-12 20:53:18 -08001434 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 pSMB->Fid = netfid;
1436 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001437 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001438 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001439
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 pSMB->Remaining = 0;
1441 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1442 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001443 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001444 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1445 else {
1446 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001447 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001448 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001449 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001450 }
Steve Frenchec637e32005-12-12 20:53:18 -08001451
1452 iov[0].iov_base = (char *)pSMB;
1453 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001454 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001455 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001456 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001457 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 if (rc) {
1459 cERROR(1, ("Send error in read = %d", rc));
1460 } else {
1461 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1462 data_length = data_length << 16;
1463 data_length += le16_to_cpu(pSMBr->DataLength);
1464 *nbytes = data_length;
1465
1466 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001467 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001469 cFYI(1, ("bad length %d for count %d",
1470 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 rc = -EIO;
1472 *nbytes = 0;
1473 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001474 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001475 le16_to_cpu(pSMBr->DataOffset);
1476/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001477 cERROR(1,("Faulting on read rc = %d",rc));
1478 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001479 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001480 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001481 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 }
1483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484
Steve French4b8f9302006-02-26 16:41:18 +00001485/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001486 if (*buf) {
1487 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001488 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001489 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001490 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001491 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001492 /* return buffer to caller to free */
1493 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001494 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001495 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001496 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001497 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001498 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001499
1500 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 since file handle passed in no longer valid */
1502 return rc;
1503}
1504
Steve Frenchec637e32005-12-12 20:53:18 -08001505
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506int
1507CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1508 const int netfid, const unsigned int count,
1509 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001510 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
1512 int rc = -EACCES;
1513 WRITE_REQ *pSMB = NULL;
1514 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001515 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 __u32 bytes_sent;
1517 __u16 byte_count;
1518
Steve French61de8002008-10-30 20:15:22 +00001519 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001520 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001521 return -ECONNABORTED;
1522
Steve French790fe572007-07-07 19:25:05 +00001523 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001524 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001525 else {
Steve French1c955182005-08-30 20:58:07 -07001526 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001527 if ((offset >> 32) > 0) {
1528 /* can not handle big offset for old srv */
1529 return -EIO;
1530 }
1531 }
Steve French1c955182005-08-30 20:58:07 -07001532
1533 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 (void **) &pSMBr);
1535 if (rc)
1536 return rc;
1537 /* tcon and ses pointer are checked in smb_init */
1538 if (tcon->ses->server == NULL)
1539 return -ECONNABORTED;
1540
1541 pSMB->AndXCommand = 0xFF; /* none */
1542 pSMB->Fid = netfid;
1543 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001544 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001545 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 pSMB->Reserved = 0xFFFFFFFF;
1548 pSMB->WriteMode = 0;
1549 pSMB->Remaining = 0;
1550
Steve French50c2f752007-07-13 00:33:32 +00001551 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 can send more if LARGE_WRITE_X capability returned by the server and if
1553 our buffer is big enough or if we convert to iovecs on socket writes
1554 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001555 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1557 } else {
1558 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1559 & ~0xFF;
1560 }
1561
1562 if (bytes_sent > count)
1563 bytes_sent = count;
1564 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001565 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001566 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001567 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001568 else if (ubuf) {
1569 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 cifs_buf_release(pSMB);
1571 return -EFAULT;
1572 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001573 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 /* No buffer */
1575 cifs_buf_release(pSMB);
1576 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001577 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001578 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001579 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001580 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001581 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1584 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001585 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001586
Steve French790fe572007-07-07 19:25:05 +00001587 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001588 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001589 else { /* old style write has byte count 4 bytes earlier
1590 so 4 bytes pad */
1591 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001592 (struct smb_com_writex_req *)pSMB;
1593 pSMBW->ByteCount = cpu_to_le16(byte_count);
1594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1597 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001598 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 if (rc) {
1600 cFYI(1, ("Send error in write = %d", rc));
1601 *nbytes = 0;
1602 } else {
1603 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1604 *nbytes = (*nbytes) << 16;
1605 *nbytes += le16_to_cpu(pSMBr->Count);
1606 }
1607
1608 cifs_buf_release(pSMB);
1609
Steve French50c2f752007-07-13 00:33:32 +00001610 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 since file handle passed in no longer valid */
1612
1613 return rc;
1614}
1615
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001616int
1617CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001619 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1620 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621{
1622 int rc = -EACCES;
1623 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001624 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001625 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001626 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
Steve French790fe572007-07-07 19:25:05 +00001628 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001629
Steve French4c3130e2008-12-09 00:28:16 +00001630 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001631 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001632 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001633 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001634 if ((offset >> 32) > 0) {
1635 /* can not handle big offset for old srv */
1636 return -EIO;
1637 }
1638 }
Steve French8cc64c62005-10-03 13:49:43 -07001639 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (rc)
1641 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 /* tcon and ses pointer are checked in smb_init */
1643 if (tcon->ses->server == NULL)
1644 return -ECONNABORTED;
1645
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001646 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 pSMB->Fid = netfid;
1648 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001649 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001650 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 pSMB->Reserved = 0xFFFFFFFF;
1652 pSMB->WriteMode = 0;
1653 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001656 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657
Steve French3e844692005-10-03 13:37:24 -07001658 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1659 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001660 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001661 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001662 pSMB->hdr.smb_buf_length += count+1;
1663 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001664 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1665 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001666 pSMB->ByteCount = cpu_to_le16(count + 1);
1667 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001668 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001669 (struct smb_com_writex_req *)pSMB;
1670 pSMBW->ByteCount = cpu_to_le16(count + 5);
1671 }
Steve French3e844692005-10-03 13:37:24 -07001672 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001673 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001674 iov[0].iov_len = smb_hdr_len + 4;
1675 else /* wct == 12 pad bigger by four bytes */
1676 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001677
Steve French3e844692005-10-03 13:37:24 -07001678
Steve Frenchec637e32005-12-12 20:53:18 -08001679 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001680 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001681 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001683 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001685 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001686 /* presumably this can not happen, but best to be safe */
1687 rc = -EIO;
1688 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001689 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001690 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001691 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1692 *nbytes = (*nbytes) << 16;
1693 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Steve French4b8f9302006-02-26 16:41:18 +00001696/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001697 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001698 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001699 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001700 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
Steve French50c2f752007-07-13 00:33:32 +00001702 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 since file handle passed in no longer valid */
1704
1705 return rc;
1706}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001707
1708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709int
1710CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1711 const __u16 smb_file_id, const __u64 len,
1712 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001713 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714{
1715 int rc = 0;
1716 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001717/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 int bytes_returned;
1719 int timeout = 0;
1720 __u16 count;
1721
Steve French4b18f2a2008-04-29 00:06:05 +00001722 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001723 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1724
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 if (rc)
1726 return rc;
1727
Steve French790fe572007-07-07 19:25:05 +00001728 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001729 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001731 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001732 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1734 } else {
1735 pSMB->Timeout = 0;
1736 }
1737
1738 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1739 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1740 pSMB->LockType = lockType;
1741 pSMB->AndXCommand = 0xFF; /* none */
1742 pSMB->Fid = smb_file_id; /* netfid stays le */
1743
Steve French790fe572007-07-07 19:25:05 +00001744 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1746 /* BB where to store pid high? */
1747 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1748 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1749 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1750 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1751 count = sizeof(LOCKING_ANDX_RANGE);
1752 } else {
1753 /* oplock break */
1754 count = 0;
1755 }
1756 pSMB->hdr.smb_buf_length += count;
1757 pSMB->ByteCount = cpu_to_le16(count);
1758
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001759 if (waitFlag) {
1760 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001761 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001762 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001763 } else {
Steve French133672e2007-11-13 22:41:37 +00001764 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1765 timeout);
1766 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001767 }
Steve Frencha4544342005-08-24 13:59:35 -07001768 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001769 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Steve French50c2f752007-07-13 00:33:32 +00001772 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 since file handle passed in no longer valid */
1774 return rc;
1775}
1776
1777int
Steve French08547b02006-02-28 22:39:25 +00001778CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1779 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001780 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001781 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001782{
1783 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1784 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001785 struct cifs_posix_lock *parm_data;
1786 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001787 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001788 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001789 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001790 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001791 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001792
1793 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001794
Steve French790fe572007-07-07 19:25:05 +00001795 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001796 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001797
Steve French08547b02006-02-28 22:39:25 +00001798 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1799
1800 if (rc)
1801 return rc;
1802
1803 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1804
Steve French50c2f752007-07-13 00:33:32 +00001805 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001806 pSMB->MaxSetupCount = 0;
1807 pSMB->Reserved = 0;
1808 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001809 pSMB->Reserved2 = 0;
1810 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1811 offset = param_offset + params;
1812
Steve French08547b02006-02-28 22:39:25 +00001813 count = sizeof(struct cifs_posix_lock);
1814 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001815 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001816 pSMB->SetupCount = 1;
1817 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001818 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1820 else
1821 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1822 byte_count = 3 /* pad */ + params + count;
1823 pSMB->DataCount = cpu_to_le16(count);
1824 pSMB->ParameterCount = cpu_to_le16(params);
1825 pSMB->TotalDataCount = pSMB->DataCount;
1826 pSMB->TotalParameterCount = pSMB->ParameterCount;
1827 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001828 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001829 (((char *) &pSMB->hdr.Protocol) + offset);
1830
1831 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001832 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001833 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001834 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001835 pSMB->Timeout = cpu_to_le32(-1);
1836 } else
1837 pSMB->Timeout = 0;
1838
Steve French08547b02006-02-28 22:39:25 +00001839 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001840 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001841 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001842
1843 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001844 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001845 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1846 pSMB->Reserved4 = 0;
1847 pSMB->hdr.smb_buf_length += byte_count;
1848 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001849 if (waitFlag) {
1850 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1851 (struct smb_hdr *) pSMBr, &bytes_returned);
1852 } else {
Steve French133672e2007-11-13 22:41:37 +00001853 iov[0].iov_base = (char *)pSMB;
1854 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1855 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1856 &resp_buf_type, timeout);
1857 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1858 not try to free it twice below on exit */
1859 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001860 }
1861
Steve French08547b02006-02-28 22:39:25 +00001862 if (rc) {
1863 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001864 } else if (get_flag) {
1865 /* lock structure can be returned on get */
1866 __u16 data_offset;
1867 __u16 data_count;
1868 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001869
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001870 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1871 rc = -EIO; /* bad smb */
1872 goto plk_err_exit;
1873 }
Steve French790fe572007-07-07 19:25:05 +00001874 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001875 rc = -EINVAL;
1876 goto plk_err_exit;
1877 }
1878 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1879 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001880 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001881 rc = -EIO;
1882 goto plk_err_exit;
1883 }
1884 parm_data = (struct cifs_posix_lock *)
1885 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001886 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001887 pLockData->fl_type = F_UNLCK;
1888 }
Steve French50c2f752007-07-13 00:33:32 +00001889
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001890plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001891 if (pSMB)
1892 cifs_small_buf_release(pSMB);
1893
Steve French133672e2007-11-13 22:41:37 +00001894 if (resp_buf_type == CIFS_SMALL_BUFFER)
1895 cifs_small_buf_release(iov[0].iov_base);
1896 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1897 cifs_buf_release(iov[0].iov_base);
1898
Steve French08547b02006-02-28 22:39:25 +00001899 /* Note: On -EAGAIN error only caller can retry on handle based calls
1900 since file handle passed in no longer valid */
1901
1902 return rc;
1903}
1904
1905
1906int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1908{
1909 int rc = 0;
1910 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 cFYI(1, ("In CIFSSMBClose"));
1912
1913/* do not retry on dead session on close */
1914 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001915 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 return 0;
1917 if (rc)
1918 return rc;
1919
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001921 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001923 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001924 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001926 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 /* EINTR is expected when user ctl-c to kill app */
1928 cERROR(1, ("Send error in Close = %d", rc));
1929 }
1930 }
1931
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001933 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 rc = 0;
1935
1936 return rc;
1937}
1938
1939int
1940CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1941 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001942 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
1944 int rc = 0;
1945 RENAME_REQ *pSMB = NULL;
1946 RENAME_RSP *pSMBr = NULL;
1947 int bytes_returned;
1948 int name_len, name_len2;
1949 __u16 count;
1950
1951 cFYI(1, ("In CIFSSMBRename"));
1952renameRetry:
1953 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1954 (void **) &pSMBr);
1955 if (rc)
1956 return rc;
1957
1958 pSMB->BufferFormat = 0x04;
1959 pSMB->SearchAttributes =
1960 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1961 ATTR_DIRECTORY);
1962
1963 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1964 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001965 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001966 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 name_len++; /* trailing null */
1968 name_len *= 2;
1969 pSMB->OldFileName[name_len] = 0x04; /* pad */
1970 /* protocol requires ASCII signature byte on Unicode string */
1971 pSMB->OldFileName[name_len + 1] = 0x00;
1972 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001973 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001974 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1976 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001977 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 name_len = strnlen(fromName, PATH_MAX);
1979 name_len++; /* trailing null */
1980 strncpy(pSMB->OldFileName, fromName, name_len);
1981 name_len2 = strnlen(toName, PATH_MAX);
1982 name_len2++; /* trailing null */
1983 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1984 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1985 name_len2++; /* trailing null */
1986 name_len2++; /* signature byte */
1987 }
1988
1989 count = 1 /* 1st signature byte */ + name_len + name_len2;
1990 pSMB->hdr.smb_buf_length += count;
1991 pSMB->ByteCount = cpu_to_le16(count);
1992
1993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001995 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001996 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 cifs_buf_release(pSMB);
2000
2001 if (rc == -EAGAIN)
2002 goto renameRetry;
2003
2004 return rc;
2005}
2006
Steve French50c2f752007-07-13 00:33:32 +00002007int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002008 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002009 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010{
2011 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2012 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002013 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 char *data_offset;
2015 char dummy_string[30];
2016 int rc = 0;
2017 int bytes_returned = 0;
2018 int len_of_str;
2019 __u16 params, param_offset, offset, count, byte_count;
2020
2021 cFYI(1, ("Rename to File by handle"));
2022 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2023 (void **) &pSMBr);
2024 if (rc)
2025 return rc;
2026
2027 params = 6;
2028 pSMB->MaxSetupCount = 0;
2029 pSMB->Reserved = 0;
2030 pSMB->Flags = 0;
2031 pSMB->Timeout = 0;
2032 pSMB->Reserved2 = 0;
2033 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2034 offset = param_offset + params;
2035
2036 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2037 rename_info = (struct set_file_rename *) data_offset;
2038 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002039 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 pSMB->SetupCount = 1;
2041 pSMB->Reserved3 = 0;
2042 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2043 byte_count = 3 /* pad */ + params;
2044 pSMB->ParameterCount = cpu_to_le16(params);
2045 pSMB->TotalParameterCount = pSMB->ParameterCount;
2046 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2047 pSMB->DataOffset = cpu_to_le16(offset);
2048 /* construct random name ".cifs_tmp<inodenum><mid>" */
2049 rename_info->overwrite = cpu_to_le32(1);
2050 rename_info->root_fid = 0;
2051 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002052 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002053 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2054 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002055 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002057 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002058 target_name, PATH_MAX, nls_codepage,
2059 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 }
2061 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002062 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 byte_count += count;
2064 pSMB->DataCount = cpu_to_le16(count);
2065 pSMB->TotalDataCount = pSMB->DataCount;
2066 pSMB->Fid = netfid;
2067 pSMB->InformationLevel =
2068 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2069 pSMB->Reserved4 = 0;
2070 pSMB->hdr.smb_buf_length += byte_count;
2071 pSMB->ByteCount = cpu_to_le16(byte_count);
2072 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002074 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002075 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002076 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002077
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 cifs_buf_release(pSMB);
2079
2080 /* Note: On -EAGAIN error only caller can retry on handle based calls
2081 since file handle passed in no longer valid */
2082
2083 return rc;
2084}
2085
2086int
Steve French50c2f752007-07-13 00:33:32 +00002087CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2088 const __u16 target_tid, const char *toName, const int flags,
2089 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090{
2091 int rc = 0;
2092 COPY_REQ *pSMB = NULL;
2093 COPY_RSP *pSMBr = NULL;
2094 int bytes_returned;
2095 int name_len, name_len2;
2096 __u16 count;
2097
2098 cFYI(1, ("In CIFSSMBCopy"));
2099copyRetry:
2100 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2101 (void **) &pSMBr);
2102 if (rc)
2103 return rc;
2104
2105 pSMB->BufferFormat = 0x04;
2106 pSMB->Tid2 = target_tid;
2107
2108 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2109
2110 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002111 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002112 fromName, PATH_MAX, nls_codepage,
2113 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 name_len++; /* trailing null */
2115 name_len *= 2;
2116 pSMB->OldFileName[name_len] = 0x04; /* pad */
2117 /* protocol requires ASCII signature byte on Unicode string */
2118 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002119 name_len2 =
2120 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002121 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2123 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002124 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 name_len = strnlen(fromName, PATH_MAX);
2126 name_len++; /* trailing null */
2127 strncpy(pSMB->OldFileName, fromName, name_len);
2128 name_len2 = strnlen(toName, PATH_MAX);
2129 name_len2++; /* trailing null */
2130 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2131 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2132 name_len2++; /* trailing null */
2133 name_len2++; /* signature byte */
2134 }
2135
2136 count = 1 /* 1st signature byte */ + name_len + name_len2;
2137 pSMB->hdr.smb_buf_length += count;
2138 pSMB->ByteCount = cpu_to_le16(count);
2139
2140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2141 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2142 if (rc) {
2143 cFYI(1, ("Send error in copy = %d with %d files copied",
2144 rc, le16_to_cpu(pSMBr->CopyCount)));
2145 }
Steve French0d817bc2008-05-22 02:02:03 +00002146 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147
2148 if (rc == -EAGAIN)
2149 goto copyRetry;
2150
2151 return rc;
2152}
2153
2154int
2155CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2156 const char *fromName, const char *toName,
2157 const struct nls_table *nls_codepage)
2158{
2159 TRANSACTION2_SPI_REQ *pSMB = NULL;
2160 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2161 char *data_offset;
2162 int name_len;
2163 int name_len_target;
2164 int rc = 0;
2165 int bytes_returned = 0;
2166 __u16 params, param_offset, offset, byte_count;
2167
2168 cFYI(1, ("In Symlink Unix style"));
2169createSymLinkRetry:
2170 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2171 (void **) &pSMBr);
2172 if (rc)
2173 return rc;
2174
2175 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2176 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002177 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 /* find define for this maxpathcomponent */
2179 , nls_codepage);
2180 name_len++; /* trailing null */
2181 name_len *= 2;
2182
Steve French50c2f752007-07-13 00:33:32 +00002183 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 name_len = strnlen(fromName, PATH_MAX);
2185 name_len++; /* trailing null */
2186 strncpy(pSMB->FileName, fromName, name_len);
2187 }
2188 params = 6 + name_len;
2189 pSMB->MaxSetupCount = 0;
2190 pSMB->Reserved = 0;
2191 pSMB->Flags = 0;
2192 pSMB->Timeout = 0;
2193 pSMB->Reserved2 = 0;
2194 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002195 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 offset = param_offset + params;
2197
2198 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2199 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2200 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002201 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 /* find define for this maxpathcomponent */
2203 , nls_codepage);
2204 name_len_target++; /* trailing null */
2205 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002206 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 name_len_target = strnlen(toName, PATH_MAX);
2208 name_len_target++; /* trailing null */
2209 strncpy(data_offset, toName, name_len_target);
2210 }
2211
2212 pSMB->MaxParameterCount = cpu_to_le16(2);
2213 /* BB find exact max on data count below from sess */
2214 pSMB->MaxDataCount = cpu_to_le16(1000);
2215 pSMB->SetupCount = 1;
2216 pSMB->Reserved3 = 0;
2217 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2218 byte_count = 3 /* pad */ + params + name_len_target;
2219 pSMB->DataCount = cpu_to_le16(name_len_target);
2220 pSMB->ParameterCount = cpu_to_le16(params);
2221 pSMB->TotalDataCount = pSMB->DataCount;
2222 pSMB->TotalParameterCount = pSMB->ParameterCount;
2223 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2224 pSMB->DataOffset = cpu_to_le16(offset);
2225 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2226 pSMB->Reserved4 = 0;
2227 pSMB->hdr.smb_buf_length += byte_count;
2228 pSMB->ByteCount = cpu_to_le16(byte_count);
2229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002231 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002232 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002233 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Steve French0d817bc2008-05-22 02:02:03 +00002235 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
2237 if (rc == -EAGAIN)
2238 goto createSymLinkRetry;
2239
2240 return rc;
2241}
2242
2243int
2244CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2245 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002246 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247{
2248 TRANSACTION2_SPI_REQ *pSMB = NULL;
2249 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2250 char *data_offset;
2251 int name_len;
2252 int name_len_target;
2253 int rc = 0;
2254 int bytes_returned = 0;
2255 __u16 params, param_offset, offset, byte_count;
2256
2257 cFYI(1, ("In Create Hard link Unix style"));
2258createHardLinkRetry:
2259 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2260 (void **) &pSMBr);
2261 if (rc)
2262 return rc;
2263
2264 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002265 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002266 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 name_len++; /* trailing null */
2268 name_len *= 2;
2269
Steve French50c2f752007-07-13 00:33:32 +00002270 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 name_len = strnlen(toName, PATH_MAX);
2272 name_len++; /* trailing null */
2273 strncpy(pSMB->FileName, toName, name_len);
2274 }
2275 params = 6 + name_len;
2276 pSMB->MaxSetupCount = 0;
2277 pSMB->Reserved = 0;
2278 pSMB->Flags = 0;
2279 pSMB->Timeout = 0;
2280 pSMB->Reserved2 = 0;
2281 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002282 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 offset = param_offset + params;
2284
2285 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2286 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2287 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002288 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002289 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 name_len_target++; /* trailing null */
2291 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002292 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 name_len_target = strnlen(fromName, PATH_MAX);
2294 name_len_target++; /* trailing null */
2295 strncpy(data_offset, fromName, name_len_target);
2296 }
2297
2298 pSMB->MaxParameterCount = cpu_to_le16(2);
2299 /* BB find exact max on data count below from sess*/
2300 pSMB->MaxDataCount = cpu_to_le16(1000);
2301 pSMB->SetupCount = 1;
2302 pSMB->Reserved3 = 0;
2303 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2304 byte_count = 3 /* pad */ + params + name_len_target;
2305 pSMB->ParameterCount = cpu_to_le16(params);
2306 pSMB->TotalParameterCount = pSMB->ParameterCount;
2307 pSMB->DataCount = cpu_to_le16(name_len_target);
2308 pSMB->TotalDataCount = pSMB->DataCount;
2309 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2310 pSMB->DataOffset = cpu_to_le16(offset);
2311 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2312 pSMB->Reserved4 = 0;
2313 pSMB->hdr.smb_buf_length += byte_count;
2314 pSMB->ByteCount = cpu_to_le16(byte_count);
2315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002317 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002318 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
2321 cifs_buf_release(pSMB);
2322 if (rc == -EAGAIN)
2323 goto createHardLinkRetry;
2324
2325 return rc;
2326}
2327
2328int
2329CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2330 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002331 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332{
2333 int rc = 0;
2334 NT_RENAME_REQ *pSMB = NULL;
2335 RENAME_RSP *pSMBr = NULL;
2336 int bytes_returned;
2337 int name_len, name_len2;
2338 __u16 count;
2339
2340 cFYI(1, ("In CIFSCreateHardLink"));
2341winCreateHardLinkRetry:
2342
2343 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2344 (void **) &pSMBr);
2345 if (rc)
2346 return rc;
2347
2348 pSMB->SearchAttributes =
2349 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2350 ATTR_DIRECTORY);
2351 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2352 pSMB->ClusterCount = 0;
2353
2354 pSMB->BufferFormat = 0x04;
2355
2356 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2357 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002358 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002359 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 name_len++; /* trailing null */
2361 name_len *= 2;
2362 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002363 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002365 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002366 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2368 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002369 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 name_len = strnlen(fromName, PATH_MAX);
2371 name_len++; /* trailing null */
2372 strncpy(pSMB->OldFileName, fromName, name_len);
2373 name_len2 = strnlen(toName, PATH_MAX);
2374 name_len2++; /* trailing null */
2375 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2376 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2377 name_len2++; /* trailing null */
2378 name_len2++; /* signature byte */
2379 }
2380
2381 count = 1 /* string type byte */ + name_len + name_len2;
2382 pSMB->hdr.smb_buf_length += count;
2383 pSMB->ByteCount = cpu_to_le16(count);
2384
2385 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2386 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002387 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002388 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002390
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 cifs_buf_release(pSMB);
2392 if (rc == -EAGAIN)
2393 goto winCreateHardLinkRetry;
2394
2395 return rc;
2396}
2397
2398int
2399CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2400 const unsigned char *searchName,
2401 char *symlinkinfo, const int buflen,
2402 const struct nls_table *nls_codepage)
2403{
2404/* SMB_QUERY_FILE_UNIX_LINK */
2405 TRANSACTION2_QPI_REQ *pSMB = NULL;
2406 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2407 int rc = 0;
2408 int bytes_returned;
2409 int name_len;
2410 __u16 params, byte_count;
2411
2412 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2413
2414querySymLinkRetry:
2415 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2416 (void **) &pSMBr);
2417 if (rc)
2418 return rc;
2419
2420 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2421 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002422 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2423 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 name_len++; /* trailing null */
2425 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002426 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 name_len = strnlen(searchName, PATH_MAX);
2428 name_len++; /* trailing null */
2429 strncpy(pSMB->FileName, searchName, name_len);
2430 }
2431
2432 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2433 pSMB->TotalDataCount = 0;
2434 pSMB->MaxParameterCount = cpu_to_le16(2);
2435 /* BB find exact max data count below from sess structure BB */
2436 pSMB->MaxDataCount = cpu_to_le16(4000);
2437 pSMB->MaxSetupCount = 0;
2438 pSMB->Reserved = 0;
2439 pSMB->Flags = 0;
2440 pSMB->Timeout = 0;
2441 pSMB->Reserved2 = 0;
2442 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002443 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 pSMB->DataCount = 0;
2445 pSMB->DataOffset = 0;
2446 pSMB->SetupCount = 1;
2447 pSMB->Reserved3 = 0;
2448 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2449 byte_count = params + 1 /* pad */ ;
2450 pSMB->TotalParameterCount = cpu_to_le16(params);
2451 pSMB->ParameterCount = pSMB->TotalParameterCount;
2452 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2453 pSMB->Reserved4 = 0;
2454 pSMB->hdr.smb_buf_length += byte_count;
2455 pSMB->ByteCount = cpu_to_le16(byte_count);
2456
2457 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2458 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2459 if (rc) {
2460 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2461 } else {
2462 /* decode response */
2463
2464 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2465 if (rc || (pSMBr->ByteCount < 2))
2466 /* BB also check enough total bytes returned */
2467 rc = -EIO; /* bad smb */
2468 else {
2469 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2470 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2471
2472 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2473 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002474 &pSMBr->hdr.Protocol + data_offset),
2475 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002476 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002478 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2479 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 name_len, nls_codepage);
2481 } else {
2482 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002483 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 data_offset,
2485 min_t(const int, buflen, count));
2486 }
2487 symlinkinfo[buflen] = 0;
2488 /* just in case so calling code does not go off the end of buffer */
2489 }
2490 }
2491 cifs_buf_release(pSMB);
2492 if (rc == -EAGAIN)
2493 goto querySymLinkRetry;
2494 return rc;
2495}
2496
Parag Warudkarc9489772007-10-23 18:09:48 +00002497#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002498/* Initialize NT TRANSACT SMB into small smb request buffer.
2499 This assumes that all NT TRANSACTS that we init here have
2500 total parm and data under about 400 bytes (to fit in small cifs
2501 buffer size), which is the case so far, it easily fits. NB:
2502 Setup words themselves and ByteCount
2503 MaxSetupCount (size of returned setup area) and
2504 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002505static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002506smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002507 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002508 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002509{
2510 int rc;
2511 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002512 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002513
2514 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2515 (void **)&pSMB);
2516 if (rc)
2517 return rc;
2518 *ret_buf = (void *)pSMB;
2519 pSMB->Reserved = 0;
2520 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2521 pSMB->TotalDataCount = 0;
2522 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2523 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2524 pSMB->ParameterCount = pSMB->TotalParameterCount;
2525 pSMB->DataCount = pSMB->TotalDataCount;
2526 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2527 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2528 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2529 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2530 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2531 pSMB->SubCommand = cpu_to_le16(sub_command);
2532 return 0;
2533}
2534
2535static int
Steve French50c2f752007-07-13 00:33:32 +00002536validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002537 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002538{
Steve French50c2f752007-07-13 00:33:32 +00002539 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002540 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002541 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002542
Steve French630f3f02007-10-25 21:17:17 +00002543 *pdatalen = 0;
2544 *pparmlen = 0;
2545
Steve French790fe572007-07-07 19:25:05 +00002546 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002547 return -EINVAL;
2548
2549 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2550
2551 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002552 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002553 (char *)&pSMBr->ByteCount;
2554
Steve French0a4b92c2006-01-12 15:44:21 -08002555 data_offset = le32_to_cpu(pSMBr->DataOffset);
2556 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002557 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002558 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2559
2560 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2561 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2562
2563 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002564 if (*ppparm > end_of_smb) {
2565 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002566 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002567 } else if (parm_count + *ppparm > end_of_smb) {
2568 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002569 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002570 } else if (*ppdata > end_of_smb) {
2571 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002572 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002573 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002574 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002575 *ppdata, data_count, (data_count + *ppdata),
2576 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002577 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002578 } else if (parm_count + data_count > pSMBr->ByteCount) {
2579 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002580 return -EINVAL;
2581 }
Steve French630f3f02007-10-25 21:17:17 +00002582 *pdatalen = data_count;
2583 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002584 return 0;
2585}
Parag Warudkarc9489772007-10-23 18:09:48 +00002586#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002587
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588int
2589CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2590 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002591 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 const struct nls_table *nls_codepage)
2593{
2594 int rc = 0;
2595 int bytes_returned;
2596 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002597 struct smb_com_transaction_ioctl_req *pSMB;
2598 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599
2600 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2601 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2602 (void **) &pSMBr);
2603 if (rc)
2604 return rc;
2605
2606 pSMB->TotalParameterCount = 0 ;
2607 pSMB->TotalDataCount = 0;
2608 pSMB->MaxParameterCount = cpu_to_le32(2);
2609 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002610 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2611 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 pSMB->MaxSetupCount = 4;
2613 pSMB->Reserved = 0;
2614 pSMB->ParameterOffset = 0;
2615 pSMB->DataCount = 0;
2616 pSMB->DataOffset = 0;
2617 pSMB->SetupCount = 4;
2618 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2619 pSMB->ParameterCount = pSMB->TotalParameterCount;
2620 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2621 pSMB->IsFsctl = 1; /* FSCTL */
2622 pSMB->IsRootFlag = 0;
2623 pSMB->Fid = fid; /* file handle always le */
2624 pSMB->ByteCount = 0;
2625
2626 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2627 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2628 if (rc) {
2629 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2630 } else { /* decode response */
2631 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2632 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2633 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2634 /* BB also check enough total bytes returned */
2635 rc = -EIO; /* bad smb */
2636 else {
Steve French790fe572007-07-07 19:25:05 +00002637 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002638 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002639 pSMBr->ByteCount +
2640 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
Steve French50c2f752007-07-13 00:33:32 +00002642 struct reparse_data *reparse_buf =
2643 (struct reparse_data *)
2644 ((char *)&pSMBr->hdr.Protocol
2645 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002646 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 rc = -EIO;
2648 goto qreparse_out;
2649 }
Steve French790fe572007-07-07 19:25:05 +00002650 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 reparse_buf->TargetNameOffset +
2652 reparse_buf->TargetNameLen) >
2653 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002654 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 rc = -EIO;
2656 goto qreparse_out;
2657 }
Steve French50c2f752007-07-13 00:33:32 +00002658
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2660 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002661 (reparse_buf->LinkNamesBuf +
2662 reparse_buf->TargetNameOffset),
2663 min(buflen/2,
2664 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002666 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 reparse_buf->TargetNameOffset),
2668 name_len, nls_codepage);
2669 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002670 strncpy(symlinkinfo,
2671 reparse_buf->LinkNamesBuf +
2672 reparse_buf->TargetNameOffset,
2673 min_t(const int, buflen,
2674 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 }
2676 } else {
2677 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002678 cFYI(1, ("Invalid return data count on "
2679 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 }
2681 symlinkinfo[buflen] = 0; /* just in case so the caller
2682 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002683 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 }
2685 }
2686qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002687 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688
2689 /* Note: On -EAGAIN error only caller can retry on handle based calls
2690 since file handle passed in no longer valid */
2691
2692 return rc;
2693}
2694
2695#ifdef CONFIG_CIFS_POSIX
2696
2697/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002698static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2699 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
2701 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002702 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2703 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2704 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2706
2707 return;
2708}
2709
2710/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002711static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2712 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713{
2714 int size = 0;
2715 int i;
2716 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002717 struct cifs_posix_ace *pACE;
2718 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2719 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720
2721 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2722 return -EOPNOTSUPP;
2723
Steve French790fe572007-07-07 19:25:05 +00002724 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 count = le16_to_cpu(cifs_acl->access_entry_count);
2726 pACE = &cifs_acl->ace_array[0];
2727 size = sizeof(struct cifs_posix_acl);
2728 size += sizeof(struct cifs_posix_ace) * count;
2729 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002730 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002731 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2732 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 return -EINVAL;
2734 }
Steve French790fe572007-07-07 19:25:05 +00002735 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 count = le16_to_cpu(cifs_acl->access_entry_count);
2737 size = sizeof(struct cifs_posix_acl);
2738 size += sizeof(struct cifs_posix_ace) * count;
2739/* skip past access ACEs to get to default ACEs */
2740 pACE = &cifs_acl->ace_array[count];
2741 count = le16_to_cpu(cifs_acl->default_entry_count);
2742 size += sizeof(struct cifs_posix_ace) * count;
2743 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002744 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 return -EINVAL;
2746 } else {
2747 /* illegal type */
2748 return -EINVAL;
2749 }
2750
2751 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002752 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002753 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002754 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 return -ERANGE;
2756 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002757 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002758 for (i = 0; i < count ; i++) {
2759 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2760 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 }
2762 }
2763 return size;
2764}
2765
Steve French50c2f752007-07-13 00:33:32 +00002766static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2767 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768{
2769 __u16 rc = 0; /* 0 = ACL converted ok */
2770
Steve Frenchff7feac2005-11-15 16:45:16 -08002771 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2772 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002774 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 /* Probably no need to le convert -1 on any arch but can not hurt */
2776 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002777 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002778 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002779 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 return rc;
2781}
2782
2783/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002784static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2785 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786{
2787 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002788 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2789 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 int count;
2791 int i;
2792
Steve French790fe572007-07-07 19:25:05 +00002793 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 return 0;
2795
2796 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002797 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002798 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002799 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002800 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002801 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002802 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 return 0;
2804 }
2805 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002806 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002807 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002808 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002809 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 else {
Steve French50c2f752007-07-13 00:33:32 +00002811 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 return 0;
2813 }
Steve French50c2f752007-07-13 00:33:32 +00002814 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2816 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002817 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 /* ACE not converted */
2819 break;
2820 }
2821 }
Steve French790fe572007-07-07 19:25:05 +00002822 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2824 rc += sizeof(struct cifs_posix_acl);
2825 /* BB add check to make sure ACL does not overflow SMB */
2826 }
2827 return rc;
2828}
2829
2830int
2831CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002832 const unsigned char *searchName,
2833 char *acl_inf, const int buflen, const int acl_type,
2834 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835{
2836/* SMB_QUERY_POSIX_ACL */
2837 TRANSACTION2_QPI_REQ *pSMB = NULL;
2838 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2839 int rc = 0;
2840 int bytes_returned;
2841 int name_len;
2842 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002843
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2845
2846queryAclRetry:
2847 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2848 (void **) &pSMBr);
2849 if (rc)
2850 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002851
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2853 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002854 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002855 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 name_len++; /* trailing null */
2857 name_len *= 2;
2858 pSMB->FileName[name_len] = 0;
2859 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002860 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 name_len = strnlen(searchName, PATH_MAX);
2862 name_len++; /* trailing null */
2863 strncpy(pSMB->FileName, searchName, name_len);
2864 }
2865
2866 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2867 pSMB->TotalDataCount = 0;
2868 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002869 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 pSMB->MaxDataCount = cpu_to_le16(4000);
2871 pSMB->MaxSetupCount = 0;
2872 pSMB->Reserved = 0;
2873 pSMB->Flags = 0;
2874 pSMB->Timeout = 0;
2875 pSMB->Reserved2 = 0;
2876 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002877 offsetof(struct smb_com_transaction2_qpi_req,
2878 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 pSMB->DataCount = 0;
2880 pSMB->DataOffset = 0;
2881 pSMB->SetupCount = 1;
2882 pSMB->Reserved3 = 0;
2883 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2884 byte_count = params + 1 /* pad */ ;
2885 pSMB->TotalParameterCount = cpu_to_le16(params);
2886 pSMB->ParameterCount = pSMB->TotalParameterCount;
2887 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2888 pSMB->Reserved4 = 0;
2889 pSMB->hdr.smb_buf_length += byte_count;
2890 pSMB->ByteCount = cpu_to_le16(byte_count);
2891
2892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002894 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 if (rc) {
2896 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2897 } else {
2898 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002899
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2901 if (rc || (pSMBr->ByteCount < 2))
2902 /* BB also check enough total bytes returned */
2903 rc = -EIO; /* bad smb */
2904 else {
2905 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2906 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2907 rc = cifs_copy_posix_acl(acl_inf,
2908 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002909 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 }
2911 }
2912 cifs_buf_release(pSMB);
2913 if (rc == -EAGAIN)
2914 goto queryAclRetry;
2915 return rc;
2916}
2917
2918int
2919CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002920 const unsigned char *fileName,
2921 const char *local_acl, const int buflen,
2922 const int acl_type,
2923 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924{
2925 struct smb_com_transaction2_spi_req *pSMB = NULL;
2926 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2927 char *parm_data;
2928 int name_len;
2929 int rc = 0;
2930 int bytes_returned = 0;
2931 __u16 params, byte_count, data_count, param_offset, offset;
2932
2933 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2934setAclRetry:
2935 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002936 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 if (rc)
2938 return rc;
2939 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2940 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002941 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002942 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 name_len++; /* trailing null */
2944 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002945 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 name_len = strnlen(fileName, PATH_MAX);
2947 name_len++; /* trailing null */
2948 strncpy(pSMB->FileName, fileName, name_len);
2949 }
2950 params = 6 + name_len;
2951 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002952 /* BB find max SMB size from sess */
2953 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 pSMB->MaxSetupCount = 0;
2955 pSMB->Reserved = 0;
2956 pSMB->Flags = 0;
2957 pSMB->Timeout = 0;
2958 pSMB->Reserved2 = 0;
2959 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002960 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 offset = param_offset + params;
2962 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2963 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2964
2965 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002966 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
Steve French790fe572007-07-07 19:25:05 +00002968 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 rc = -EOPNOTSUPP;
2970 goto setACLerrorExit;
2971 }
2972 pSMB->DataOffset = cpu_to_le16(offset);
2973 pSMB->SetupCount = 1;
2974 pSMB->Reserved3 = 0;
2975 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2976 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2977 byte_count = 3 /* pad */ + params + data_count;
2978 pSMB->DataCount = cpu_to_le16(data_count);
2979 pSMB->TotalDataCount = pSMB->DataCount;
2980 pSMB->ParameterCount = cpu_to_le16(params);
2981 pSMB->TotalParameterCount = pSMB->ParameterCount;
2982 pSMB->Reserved4 = 0;
2983 pSMB->hdr.smb_buf_length += byte_count;
2984 pSMB->ByteCount = cpu_to_le16(byte_count);
2985 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002986 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002987 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989
2990setACLerrorExit:
2991 cifs_buf_release(pSMB);
2992 if (rc == -EAGAIN)
2993 goto setAclRetry;
2994 return rc;
2995}
2996
Steve Frenchf654bac2005-04-28 22:41:04 -07002997/* BB fix tabs in this function FIXME BB */
2998int
2999CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003000 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003001{
Steve French50c2f752007-07-13 00:33:32 +00003002 int rc = 0;
3003 struct smb_t2_qfi_req *pSMB = NULL;
3004 struct smb_t2_qfi_rsp *pSMBr = NULL;
3005 int bytes_returned;
3006 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003007
Steve French790fe572007-07-07 19:25:05 +00003008 cFYI(1, ("In GetExtAttr"));
3009 if (tcon == NULL)
3010 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003011
3012GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003013 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3014 (void **) &pSMBr);
3015 if (rc)
3016 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003017
Steve Frenchad7a2922008-02-07 23:25:02 +00003018 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003019 pSMB->t2.TotalDataCount = 0;
3020 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3021 /* BB find exact max data count below from sess structure BB */
3022 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3023 pSMB->t2.MaxSetupCount = 0;
3024 pSMB->t2.Reserved = 0;
3025 pSMB->t2.Flags = 0;
3026 pSMB->t2.Timeout = 0;
3027 pSMB->t2.Reserved2 = 0;
3028 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3029 Fid) - 4);
3030 pSMB->t2.DataCount = 0;
3031 pSMB->t2.DataOffset = 0;
3032 pSMB->t2.SetupCount = 1;
3033 pSMB->t2.Reserved3 = 0;
3034 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3035 byte_count = params + 1 /* pad */ ;
3036 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3037 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3038 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3039 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003040 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003041 pSMB->hdr.smb_buf_length += byte_count;
3042 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003043
Steve French790fe572007-07-07 19:25:05 +00003044 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3045 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3046 if (rc) {
3047 cFYI(1, ("error %d in GetExtAttr", rc));
3048 } else {
3049 /* decode response */
3050 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3051 if (rc || (pSMBr->ByteCount < 2))
3052 /* BB also check enough total bytes returned */
3053 /* If rc should we check for EOPNOSUPP and
3054 disable the srvino flag? or in caller? */
3055 rc = -EIO; /* bad smb */
3056 else {
3057 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3058 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3059 struct file_chattr_info *pfinfo;
3060 /* BB Do we need a cast or hash here ? */
3061 if (count != 16) {
3062 cFYI(1, ("Illegal size ret in GetExtAttr"));
3063 rc = -EIO;
3064 goto GetExtAttrOut;
3065 }
3066 pfinfo = (struct file_chattr_info *)
3067 (data_offset + (char *) &pSMBr->hdr.Protocol);
3068 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003069 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003070 }
3071 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003072GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003073 cifs_buf_release(pSMB);
3074 if (rc == -EAGAIN)
3075 goto GetExtAttrRetry;
3076 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003077}
3078
Steve Frenchf654bac2005-04-28 22:41:04 -07003079#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
Steve French297647c2007-10-12 04:11:59 +00003081#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003082/* Get Security Descriptor (by handle) from remote server for a file or dir */
3083int
3084CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003085 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003086{
3087 int rc = 0;
3088 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003089 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003090 struct kvec iov[1];
3091
3092 cFYI(1, ("GetCifsACL"));
3093
Steve French630f3f02007-10-25 21:17:17 +00003094 *pbuflen = 0;
3095 *acl_inf = NULL;
3096
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003097 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003098 8 /* parm len */, tcon, (void **) &pSMB);
3099 if (rc)
3100 return rc;
3101
3102 pSMB->MaxParameterCount = cpu_to_le32(4);
3103 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3104 pSMB->MaxSetupCount = 0;
3105 pSMB->Fid = fid; /* file handle always le */
3106 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3107 CIFS_ACL_DACL);
3108 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3109 pSMB->hdr.smb_buf_length += 11;
3110 iov[0].iov_base = (char *)pSMB;
3111 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3112
Steve Frencha761ac52007-10-18 21:45:27 +00003113 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003114 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003115 cifs_stats_inc(&tcon->num_acl_get);
3116 if (rc) {
3117 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3118 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003119 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003120 __u32 parm_len;
3121 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003122 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003123 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003124
3125/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003126 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003127 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003128 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003129 goto qsec_out;
3130 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3131
Steve French630f3f02007-10-25 21:17:17 +00003132 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003133
3134 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3135 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003136 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003137 goto qsec_out;
3138 }
3139
3140/* BB check that data area is minimum length and as big as acl_len */
3141
Steve Frenchaf6f4612007-10-16 18:40:37 +00003142 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003143 if (acl_len != *pbuflen) {
3144 cERROR(1, ("acl length %d does not match %d",
3145 acl_len, *pbuflen));
3146 if (*pbuflen > acl_len)
3147 *pbuflen = acl_len;
3148 }
Steve French0a4b92c2006-01-12 15:44:21 -08003149
Steve French630f3f02007-10-25 21:17:17 +00003150 /* check if buffer is big enough for the acl
3151 header followed by the smallest SID */
3152 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3153 (*pbuflen >= 64 * 1024)) {
3154 cERROR(1, ("bad acl length %d", *pbuflen));
3155 rc = -EINVAL;
3156 *pbuflen = 0;
3157 } else {
3158 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3159 if (*acl_inf == NULL) {
3160 *pbuflen = 0;
3161 rc = -ENOMEM;
3162 }
3163 memcpy(*acl_inf, pdata, *pbuflen);
3164 }
Steve French0a4b92c2006-01-12 15:44:21 -08003165 }
3166qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003167 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003168 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003169 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003170 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003171/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003172 return rc;
3173}
Steve French97837582007-12-31 07:47:21 +00003174
3175int
3176CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3177 struct cifs_ntsd *pntsd, __u32 acllen)
3178{
3179 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3180 int rc = 0;
3181 int bytes_returned = 0;
3182 SET_SEC_DESC_REQ *pSMB = NULL;
3183 NTRANSACT_RSP *pSMBr = NULL;
3184
3185setCifsAclRetry:
3186 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3187 (void **) &pSMBr);
3188 if (rc)
3189 return (rc);
3190
3191 pSMB->MaxSetupCount = 0;
3192 pSMB->Reserved = 0;
3193
3194 param_count = 8;
3195 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3196 data_count = acllen;
3197 data_offset = param_offset + param_count;
3198 byte_count = 3 /* pad */ + param_count;
3199
3200 pSMB->DataCount = cpu_to_le32(data_count);
3201 pSMB->TotalDataCount = pSMB->DataCount;
3202 pSMB->MaxParameterCount = cpu_to_le32(4);
3203 pSMB->MaxDataCount = cpu_to_le32(16384);
3204 pSMB->ParameterCount = cpu_to_le32(param_count);
3205 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3206 pSMB->TotalParameterCount = pSMB->ParameterCount;
3207 pSMB->DataOffset = cpu_to_le32(data_offset);
3208 pSMB->SetupCount = 0;
3209 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3210 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3211
3212 pSMB->Fid = fid; /* file handle always le */
3213 pSMB->Reserved2 = 0;
3214 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3215
3216 if (pntsd && acllen) {
3217 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3218 (char *) pntsd,
3219 acllen);
3220 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3221
3222 } else
3223 pSMB->hdr.smb_buf_length += byte_count;
3224
3225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3227
3228 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3229 if (rc)
3230 cFYI(1, ("Set CIFS ACL returned %d", rc));
3231 cifs_buf_release(pSMB);
3232
3233 if (rc == -EAGAIN)
3234 goto setCifsAclRetry;
3235
3236 return (rc);
3237}
3238
Steve French297647c2007-10-12 04:11:59 +00003239#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003240
Steve French6b8edfe2005-08-23 20:26:03 -07003241/* Legacy Query Path Information call for lookup to old servers such
3242 as Win9x/WinME */
3243int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003244 const unsigned char *searchName,
3245 FILE_ALL_INFO *pFinfo,
3246 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003247{
Steve Frenchad7a2922008-02-07 23:25:02 +00003248 QUERY_INFORMATION_REQ *pSMB;
3249 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003250 int rc = 0;
3251 int bytes_returned;
3252 int name_len;
3253
Steve French50c2f752007-07-13 00:33:32 +00003254 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003255QInfRetry:
3256 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003257 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003258 if (rc)
3259 return rc;
3260
3261 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3262 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003263 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3264 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003265 name_len++; /* trailing null */
3266 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003267 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003268 name_len = strnlen(searchName, PATH_MAX);
3269 name_len++; /* trailing null */
3270 strncpy(pSMB->FileName, searchName, name_len);
3271 }
3272 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003273 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003274 pSMB->hdr.smb_buf_length += (__u16) name_len;
3275 pSMB->ByteCount = cpu_to_le16(name_len);
3276
3277 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003278 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003279 if (rc) {
3280 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003281 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003282 struct timespec ts;
3283 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003284
3285 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003286 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003287 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003288 ts.tv_nsec = 0;
3289 ts.tv_sec = time;
3290 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003291 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003292 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3293 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003294 pFinfo->AllocationSize =
3295 cpu_to_le64(le32_to_cpu(pSMBr->size));
3296 pFinfo->EndOfFile = pFinfo->AllocationSize;
3297 pFinfo->Attributes =
3298 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003299 } else
3300 rc = -EIO; /* bad buffer passed in */
3301
3302 cifs_buf_release(pSMB);
3303
3304 if (rc == -EAGAIN)
3305 goto QInfRetry;
3306
3307 return rc;
3308}
3309
3310
3311
3312
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313int
3314CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3315 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003316 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003317 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003318 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319{
3320/* level 263 SMB_QUERY_FILE_ALL_INFO */
3321 TRANSACTION2_QPI_REQ *pSMB = NULL;
3322 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3323 int rc = 0;
3324 int bytes_returned;
3325 int name_len;
3326 __u16 params, byte_count;
3327
3328/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3329QPathInfoRetry:
3330 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3331 (void **) &pSMBr);
3332 if (rc)
3333 return rc;
3334
3335 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3336 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003337 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003338 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 name_len++; /* trailing null */
3340 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003341 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 name_len = strnlen(searchName, PATH_MAX);
3343 name_len++; /* trailing null */
3344 strncpy(pSMB->FileName, searchName, name_len);
3345 }
3346
Steve French50c2f752007-07-13 00:33:32 +00003347 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 pSMB->TotalDataCount = 0;
3349 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003350 /* BB find exact max SMB PDU from sess structure BB */
3351 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 pSMB->MaxSetupCount = 0;
3353 pSMB->Reserved = 0;
3354 pSMB->Flags = 0;
3355 pSMB->Timeout = 0;
3356 pSMB->Reserved2 = 0;
3357 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003358 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 pSMB->DataCount = 0;
3360 pSMB->DataOffset = 0;
3361 pSMB->SetupCount = 1;
3362 pSMB->Reserved3 = 0;
3363 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3364 byte_count = params + 1 /* pad */ ;
3365 pSMB->TotalParameterCount = cpu_to_le16(params);
3366 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003367 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003368 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3369 else
3370 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 pSMB->Reserved4 = 0;
3372 pSMB->hdr.smb_buf_length += byte_count;
3373 pSMB->ByteCount = cpu_to_le16(byte_count);
3374
3375 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3376 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3377 if (rc) {
3378 cFYI(1, ("Send error in QPathInfo = %d", rc));
3379 } else { /* decode response */
3380 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3381
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003382 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3383 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003384 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003386 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003387 rc = -EIO; /* 24 or 26 expected but we do not read
3388 last field */
3389 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003390 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003392
3393 /* On legacy responses we do not read the last field,
3394 EAsize, fortunately since it varies by subdialect and
3395 also note it differs on Set vs. Get, ie two bytes or 4
3396 bytes depending but we don't care here */
3397 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003398 size = sizeof(FILE_INFO_STANDARD);
3399 else
3400 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 memcpy((char *) pFindData,
3402 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003403 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 } else
3405 rc = -ENOMEM;
3406 }
3407 cifs_buf_release(pSMB);
3408 if (rc == -EAGAIN)
3409 goto QPathInfoRetry;
3410
3411 return rc;
3412}
3413
3414int
3415CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3416 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003417 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003418 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419{
3420/* SMB_QUERY_FILE_UNIX_BASIC */
3421 TRANSACTION2_QPI_REQ *pSMB = NULL;
3422 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3423 int rc = 0;
3424 int bytes_returned = 0;
3425 int name_len;
3426 __u16 params, byte_count;
3427
3428 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3429UnixQPathInfoRetry:
3430 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3431 (void **) &pSMBr);
3432 if (rc)
3433 return rc;
3434
3435 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3436 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003437 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003438 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 name_len++; /* trailing null */
3440 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003441 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 name_len = strnlen(searchName, PATH_MAX);
3443 name_len++; /* trailing null */
3444 strncpy(pSMB->FileName, searchName, name_len);
3445 }
3446
Steve French50c2f752007-07-13 00:33:32 +00003447 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 pSMB->TotalDataCount = 0;
3449 pSMB->MaxParameterCount = cpu_to_le16(2);
3450 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003451 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 pSMB->MaxSetupCount = 0;
3453 pSMB->Reserved = 0;
3454 pSMB->Flags = 0;
3455 pSMB->Timeout = 0;
3456 pSMB->Reserved2 = 0;
3457 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003458 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 pSMB->DataCount = 0;
3460 pSMB->DataOffset = 0;
3461 pSMB->SetupCount = 1;
3462 pSMB->Reserved3 = 0;
3463 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3464 byte_count = params + 1 /* pad */ ;
3465 pSMB->TotalParameterCount = cpu_to_le16(params);
3466 pSMB->ParameterCount = pSMB->TotalParameterCount;
3467 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3468 pSMB->Reserved4 = 0;
3469 pSMB->hdr.smb_buf_length += byte_count;
3470 pSMB->ByteCount = cpu_to_le16(byte_count);
3471
3472 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3473 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3474 if (rc) {
3475 cFYI(1, ("Send error in QPathInfo = %d", rc));
3476 } else { /* decode response */
3477 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3478
3479 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003480 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3481 "Unix Extensions can be disabled on mount "
3482 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 rc = -EIO; /* bad smb */
3484 } else {
3485 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3486 memcpy((char *) pFindData,
3487 (char *) &pSMBr->hdr.Protocol +
3488 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003489 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 }
3491 }
3492 cifs_buf_release(pSMB);
3493 if (rc == -EAGAIN)
3494 goto UnixQPathInfoRetry;
3495
3496 return rc;
3497}
3498
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499/* xid, tcon, searchName and codepage are input parms, rest are returned */
3500int
3501CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003502 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003504 __u16 *pnetfid,
3505 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506{
3507/* level 257 SMB_ */
3508 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3509 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003510 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 int rc = 0;
3512 int bytes_returned = 0;
3513 int name_len;
3514 __u16 params, byte_count;
3515
Steve French50c2f752007-07-13 00:33:32 +00003516 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
3518findFirstRetry:
3519 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3520 (void **) &pSMBr);
3521 if (rc)
3522 return rc;
3523
3524 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3525 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003526 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003527 PATH_MAX, nls_codepage, remap);
3528 /* We can not add the asterik earlier in case
3529 it got remapped to 0xF03A as if it were part of the
3530 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003532 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003533 pSMB->FileName[name_len+1] = 0;
3534 pSMB->FileName[name_len+2] = '*';
3535 pSMB->FileName[name_len+3] = 0;
3536 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3538 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003539 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 } else { /* BB add check for overrun of SMB buf BB */
3541 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003543 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 free buffer exit; BB */
3545 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003546 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003547 pSMB->FileName[name_len+1] = '*';
3548 pSMB->FileName[name_len+2] = 0;
3549 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 }
3551
3552 params = 12 + name_len /* includes null */ ;
3553 pSMB->TotalDataCount = 0; /* no EAs */
3554 pSMB->MaxParameterCount = cpu_to_le16(10);
3555 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3556 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3557 pSMB->MaxSetupCount = 0;
3558 pSMB->Reserved = 0;
3559 pSMB->Flags = 0;
3560 pSMB->Timeout = 0;
3561 pSMB->Reserved2 = 0;
3562 byte_count = params + 1 /* pad */ ;
3563 pSMB->TotalParameterCount = cpu_to_le16(params);
3564 pSMB->ParameterCount = pSMB->TotalParameterCount;
3565 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003566 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3567 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 pSMB->DataCount = 0;
3569 pSMB->DataOffset = 0;
3570 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3571 pSMB->Reserved3 = 0;
3572 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3573 pSMB->SearchAttributes =
3574 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3575 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003576 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3577 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 CIFS_SEARCH_RETURN_RESUME);
3579 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3580
3581 /* BB what should we set StorageType to? Does it matter? BB */
3582 pSMB->SearchStorageType = 0;
3583 pSMB->hdr.smb_buf_length += byte_count;
3584 pSMB->ByteCount = cpu_to_le16(byte_count);
3585
3586 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3587 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003588 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589
Steve French88274812006-03-09 22:21:45 +00003590 if (rc) {/* BB add logic to retry regular search if Unix search
3591 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 /* BB Add code to handle unsupported level rc */
3593 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003594
Steve French88274812006-03-09 22:21:45 +00003595 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 /* BB eventually could optimize out free and realloc of buf */
3598 /* for this case */
3599 if (rc == -EAGAIN)
3600 goto findFirstRetry;
3601 } else { /* decode response */
3602 /* BB remember to free buffer if error BB */
3603 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003604 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003605 unsigned int lnoff;
3606
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003608 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 else
Steve French4b18f2a2008-04-29 00:06:05 +00003610 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
3612 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003613 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003614 psrch_inf->srch_entries_start =
3615 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3618 le16_to_cpu(pSMBr->t2.ParameterOffset));
3619
Steve French790fe572007-07-07 19:25:05 +00003620 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003621 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 else
Steve French4b18f2a2008-04-29 00:06:05 +00003623 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624
Steve French50c2f752007-07-13 00:33:32 +00003625 psrch_inf->entries_in_buffer =
3626 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003627 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003629 lnoff = le16_to_cpu(parms->LastNameOffset);
3630 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3631 lnoff) {
3632 cERROR(1, ("ignoring corrupt resume name"));
3633 psrch_inf->last_entry = NULL;
3634 return rc;
3635 }
3636
Steve French0752f152008-10-07 20:03:33 +00003637 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003638 lnoff;
3639
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 *pnetfid = parms->SearchHandle;
3641 } else {
3642 cifs_buf_release(pSMB);
3643 }
3644 }
3645
3646 return rc;
3647}
3648
3649int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003650 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651{
3652 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3653 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003654 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 char *response_data;
3656 int rc = 0;
3657 int bytes_returned, name_len;
3658 __u16 params, byte_count;
3659
3660 cFYI(1, ("In FindNext"));
3661
Steve French4b18f2a2008-04-29 00:06:05 +00003662 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 return -ENOENT;
3664
3665 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3666 (void **) &pSMBr);
3667 if (rc)
3668 return rc;
3669
Steve French50c2f752007-07-13 00:33:32 +00003670 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 byte_count = 0;
3672 pSMB->TotalDataCount = 0; /* no EAs */
3673 pSMB->MaxParameterCount = cpu_to_le16(8);
3674 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003675 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3676 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 pSMB->MaxSetupCount = 0;
3678 pSMB->Reserved = 0;
3679 pSMB->Flags = 0;
3680 pSMB->Timeout = 0;
3681 pSMB->Reserved2 = 0;
3682 pSMB->ParameterOffset = cpu_to_le16(
3683 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3684 pSMB->DataCount = 0;
3685 pSMB->DataOffset = 0;
3686 pSMB->SetupCount = 1;
3687 pSMB->Reserved3 = 0;
3688 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3689 pSMB->SearchHandle = searchHandle; /* always kept as le */
3690 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003691 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3693 pSMB->ResumeKey = psrch_inf->resume_key;
3694 pSMB->SearchFlags =
3695 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3696
3697 name_len = psrch_inf->resume_name_len;
3698 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003699 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3701 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003702 /* 14 byte parm len above enough for 2 byte null terminator */
3703 pSMB->ResumeFileName[name_len] = 0;
3704 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 } else {
3706 rc = -EINVAL;
3707 goto FNext2_err_exit;
3708 }
3709 byte_count = params + 1 /* pad */ ;
3710 pSMB->TotalParameterCount = cpu_to_le16(params);
3711 pSMB->ParameterCount = pSMB->TotalParameterCount;
3712 pSMB->hdr.smb_buf_length += byte_count;
3713 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003714
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3716 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003717 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 if (rc) {
3719 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003720 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003721 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003722 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 } else
3724 cFYI(1, ("FindNext returned = %d", rc));
3725 } else { /* decode response */
3726 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003727
Steve French790fe572007-07-07 19:25:05 +00003728 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003729 unsigned int lnoff;
3730
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 /* BB fixme add lock for file (srch_info) struct here */
3732 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003733 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 else
Steve French4b18f2a2008-04-29 00:06:05 +00003735 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 response_data = (char *) &pSMBr->hdr.Protocol +
3737 le16_to_cpu(pSMBr->t2.ParameterOffset);
3738 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3739 response_data = (char *)&pSMBr->hdr.Protocol +
3740 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003741 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003742 cifs_small_buf_release(
3743 psrch_inf->ntwrk_buf_start);
3744 else
3745 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 psrch_inf->srch_entries_start = response_data;
3747 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003748 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003749 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003750 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 else
Steve French4b18f2a2008-04-29 00:06:05 +00003752 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003753 psrch_inf->entries_in_buffer =
3754 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 psrch_inf->index_of_last_entry +=
3756 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003757 lnoff = le16_to_cpu(parms->LastNameOffset);
3758 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3759 lnoff) {
3760 cERROR(1, ("ignoring corrupt resume name"));
3761 psrch_inf->last_entry = NULL;
3762 return rc;
3763 } else
3764 psrch_inf->last_entry =
3765 psrch_inf->srch_entries_start + lnoff;
3766
Steve French50c2f752007-07-13 00:33:32 +00003767/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3768 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
3770 /* BB fixme add unlock here */
3771 }
3772
3773 }
3774
3775 /* BB On error, should we leave previous search buf (and count and
3776 last entry fields) intact or free the previous one? */
3777
3778 /* Note: On -EAGAIN error only caller can retry on handle based calls
3779 since file handle passed in no longer valid */
3780FNext2_err_exit:
3781 if (rc != 0)
3782 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 return rc;
3784}
3785
3786int
Steve French50c2f752007-07-13 00:33:32 +00003787CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3788 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789{
3790 int rc = 0;
3791 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792
3793 cFYI(1, ("In CIFSSMBFindClose"));
3794 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3795
3796 /* no sense returning error if session restarted
3797 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003798 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 return 0;
3800 if (rc)
3801 return rc;
3802
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 pSMB->FileID = searchHandle;
3804 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003805 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003806 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003808
Steve Frencha4544342005-08-24 13:59:35 -07003809 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
3811 /* Since session is dead, search handle closed on server already */
3812 if (rc == -EAGAIN)
3813 rc = 0;
3814
3815 return rc;
3816}
3817
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818int
3819CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003820 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003821 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003822 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823{
3824 int rc = 0;
3825 TRANSACTION2_QPI_REQ *pSMB = NULL;
3826 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3827 int name_len, bytes_returned;
3828 __u16 params, byte_count;
3829
Steve French50c2f752007-07-13 00:33:32 +00003830 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003831 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003832 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
3834GetInodeNumberRetry:
3835 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003836 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 if (rc)
3838 return rc;
3839
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3841 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003842 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003843 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 name_len++; /* trailing null */
3845 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003846 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 name_len = strnlen(searchName, PATH_MAX);
3848 name_len++; /* trailing null */
3849 strncpy(pSMB->FileName, searchName, name_len);
3850 }
3851
3852 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3853 pSMB->TotalDataCount = 0;
3854 pSMB->MaxParameterCount = cpu_to_le16(2);
3855 /* BB find exact max data count below from sess structure BB */
3856 pSMB->MaxDataCount = cpu_to_le16(4000);
3857 pSMB->MaxSetupCount = 0;
3858 pSMB->Reserved = 0;
3859 pSMB->Flags = 0;
3860 pSMB->Timeout = 0;
3861 pSMB->Reserved2 = 0;
3862 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003863 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 pSMB->DataCount = 0;
3865 pSMB->DataOffset = 0;
3866 pSMB->SetupCount = 1;
3867 pSMB->Reserved3 = 0;
3868 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3869 byte_count = params + 1 /* pad */ ;
3870 pSMB->TotalParameterCount = cpu_to_le16(params);
3871 pSMB->ParameterCount = pSMB->TotalParameterCount;
3872 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3873 pSMB->Reserved4 = 0;
3874 pSMB->hdr.smb_buf_length += byte_count;
3875 pSMB->ByteCount = cpu_to_le16(byte_count);
3876
3877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3879 if (rc) {
3880 cFYI(1, ("error %d in QueryInternalInfo", rc));
3881 } else {
3882 /* decode response */
3883 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3884 if (rc || (pSMBr->ByteCount < 2))
3885 /* BB also check enough total bytes returned */
3886 /* If rc should we check for EOPNOSUPP and
3887 disable the srvino flag? or in caller? */
3888 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003889 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3891 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003892 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003894 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3896 rc = -EIO;
3897 goto GetInodeNumOut;
3898 }
3899 pfinfo = (struct file_internal_info *)
3900 (data_offset + (char *) &pSMBr->hdr.Protocol);
3901 *inode_number = pfinfo->UniqueId;
3902 }
3903 }
3904GetInodeNumOut:
3905 cifs_buf_release(pSMB);
3906 if (rc == -EAGAIN)
3907 goto GetInodeNumberRetry;
3908 return rc;
3909}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910
Igor Mammedov2c556082008-10-23 13:58:42 +04003911/* computes length of UCS string converted to host codepage
3912 * @src: UCS string
3913 * @maxlen: length of the input string in UCS characters
3914 * (not in bytes)
3915 *
3916 * return: size of input string in host codepage
3917 */
3918static int hostlen_fromUCS(const __le16 *src, const int maxlen,
3919 const struct nls_table *nls_codepage) {
3920 int i;
3921 int hostlen = 0;
3922 char to[4];
3923 int charlen;
3924 for (i = 0; (i < maxlen) && src[i]; ++i) {
3925 charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
3926 to, NLS_MAX_CHARSET_SIZE);
3927 hostlen += charlen > 0 ? charlen : 1;
3928 }
3929 return hostlen;
3930}
3931
Igor Mammedovfec45852008-05-16 13:06:30 +04003932/* parses DFS refferal V3 structure
3933 * caller is responsible for freeing target_nodes
3934 * returns:
3935 * on success - 0
3936 * on failure - errno
3937 */
3938static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003939parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003940 unsigned int *num_of_nodes,
3941 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003942 const struct nls_table *nls_codepage, int remap,
3943 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003944{
3945 int i, rc = 0;
3946 char *data_end;
3947 bool is_unicode;
3948 struct dfs_referral_level_3 *ref;
3949
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003950 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3951 is_unicode = true;
3952 else
3953 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003954 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3955
3956 if (*num_of_nodes < 1) {
3957 cERROR(1, ("num_referrals: must be at least > 0,"
3958 "but we get num_referrals = %d\n", *num_of_nodes));
3959 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003960 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003961 }
3962
3963 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003964 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003965 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003966 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003967 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003968 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003969 }
3970
3971 /* get the upper boundary of the resp buffer */
3972 data_end = (char *)(&(pSMBr->PathConsumed)) +
3973 le16_to_cpu(pSMBr->t2.DataCount);
3974
3975 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3976 *num_of_nodes,
3977 le16_to_cpu(pSMBr->DFSFlags)));
3978
3979 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3980 *num_of_nodes, GFP_KERNEL);
3981 if (*target_nodes == NULL) {
3982 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3983 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003984 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003985 }
3986
3987 /* collect neccessary data from referrals */
3988 for (i = 0; i < *num_of_nodes; i++) {
3989 char *temp;
3990 int max_len;
3991 struct dfs_info3_param *node = (*target_nodes)+i;
3992
3993 node->flags = le16_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003994 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003995 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3996 GFP_KERNEL);
Igor Mammedov2c556082008-10-23 13:58:42 +04003997 cifsConvertToUCS((__le16 *) tmp, searchName,
3998 PATH_MAX, nls_codepage, remap);
3999 node->path_consumed = hostlen_fromUCS(tmp,
4000 le16_to_cpu(pSMBr->PathConsumed)/2,
4001 nls_codepage);
4002 kfree(tmp);
4003 } else
4004 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4005
Igor Mammedovfec45852008-05-16 13:06:30 +04004006 node->server_type = le16_to_cpu(ref->ServerType);
4007 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4008
4009 /* copy DfsPath */
4010 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4011 max_len = data_end - temp;
4012 rc = cifs_strncpy_to_host(&(node->path_name), temp,
4013 max_len, is_unicode, nls_codepage);
4014 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00004015 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004016
4017 /* copy link target UNC */
4018 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4019 max_len = data_end - temp;
4020 rc = cifs_strncpy_to_host(&(node->node_name), temp,
4021 max_len, is_unicode, nls_codepage);
4022 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00004023 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004024
Al Viro1d92cfd2008-06-02 10:59:02 +01004025 ref += le16_to_cpu(ref->Size);
Igor Mammedovfec45852008-05-16 13:06:30 +04004026 }
4027
Steve Frencha1fe78f2008-05-16 18:48:38 +00004028parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004029 if (rc) {
4030 free_dfs_info_array(*target_nodes, *num_of_nodes);
4031 *target_nodes = NULL;
4032 *num_of_nodes = 0;
4033 }
4034 return rc;
4035}
4036
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037int
4038CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4039 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004040 struct dfs_info3_param **target_nodes,
4041 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004042 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043{
4044/* TRANS2_GET_DFS_REFERRAL */
4045 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4046 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 int rc = 0;
4048 int bytes_returned;
4049 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004051 *num_of_nodes = 0;
4052 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053
4054 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4055 if (ses == NULL)
4056 return -ENODEV;
4057getDFSRetry:
4058 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4059 (void **) &pSMBr);
4060 if (rc)
4061 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004062
4063 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004064 but should never be null here anyway */
4065 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 pSMB->hdr.Tid = ses->ipc_tid;
4067 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004068 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004070 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072
4073 if (ses->capabilities & CAP_UNICODE) {
4074 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4075 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004076 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004077 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 name_len++; /* trailing null */
4079 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004080 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 name_len = strnlen(searchName, PATH_MAX);
4082 name_len++; /* trailing null */
4083 strncpy(pSMB->RequestFileName, searchName, name_len);
4084 }
4085
Steve French790fe572007-07-07 19:25:05 +00004086 if (ses->server) {
4087 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004088 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4089 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4090 }
4091
Steve French50c2f752007-07-13 00:33:32 +00004092 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004093
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 params = 2 /* level */ + name_len /*includes null */ ;
4095 pSMB->TotalDataCount = 0;
4096 pSMB->DataCount = 0;
4097 pSMB->DataOffset = 0;
4098 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004099 /* BB find exact max SMB PDU from sess structure BB */
4100 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 pSMB->MaxSetupCount = 0;
4102 pSMB->Reserved = 0;
4103 pSMB->Flags = 0;
4104 pSMB->Timeout = 0;
4105 pSMB->Reserved2 = 0;
4106 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004107 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 pSMB->SetupCount = 1;
4109 pSMB->Reserved3 = 0;
4110 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4111 byte_count = params + 3 /* pad */ ;
4112 pSMB->ParameterCount = cpu_to_le16(params);
4113 pSMB->TotalParameterCount = pSMB->ParameterCount;
4114 pSMB->MaxReferralLevel = cpu_to_le16(3);
4115 pSMB->hdr.smb_buf_length += byte_count;
4116 pSMB->ByteCount = cpu_to_le16(byte_count);
4117
4118 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4120 if (rc) {
4121 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004122 goto GetDFSRefExit;
4123 }
4124 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004126 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004127 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004128 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004129 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004131
4132 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4133 pSMBr->ByteCount,
4134 le16_to_cpu(pSMBr->t2.DataOffset)));
4135
4136 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004137 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004138 target_nodes, nls_codepage, remap,
4139 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004140
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004142 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143
4144 if (rc == -EAGAIN)
4145 goto getDFSRetry;
4146
4147 return rc;
4148}
4149
Steve French20962432005-09-21 22:05:57 -07004150/* Query File System Info such as free space to old servers such as Win 9x */
4151int
4152SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4153{
4154/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4155 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4156 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4157 FILE_SYSTEM_ALLOC_INFO *response_data;
4158 int rc = 0;
4159 int bytes_returned = 0;
4160 __u16 params, byte_count;
4161
4162 cFYI(1, ("OldQFSInfo"));
4163oldQFSInfoRetry:
4164 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4165 (void **) &pSMBr);
4166 if (rc)
4167 return rc;
Steve French20962432005-09-21 22:05:57 -07004168
4169 params = 2; /* level */
4170 pSMB->TotalDataCount = 0;
4171 pSMB->MaxParameterCount = cpu_to_le16(2);
4172 pSMB->MaxDataCount = cpu_to_le16(1000);
4173 pSMB->MaxSetupCount = 0;
4174 pSMB->Reserved = 0;
4175 pSMB->Flags = 0;
4176 pSMB->Timeout = 0;
4177 pSMB->Reserved2 = 0;
4178 byte_count = params + 1 /* pad */ ;
4179 pSMB->TotalParameterCount = cpu_to_le16(params);
4180 pSMB->ParameterCount = pSMB->TotalParameterCount;
4181 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4182 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4183 pSMB->DataCount = 0;
4184 pSMB->DataOffset = 0;
4185 pSMB->SetupCount = 1;
4186 pSMB->Reserved3 = 0;
4187 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4188 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4189 pSMB->hdr.smb_buf_length += byte_count;
4190 pSMB->ByteCount = cpu_to_le16(byte_count);
4191
4192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4194 if (rc) {
4195 cFYI(1, ("Send error in QFSInfo = %d", rc));
4196 } else { /* decode response */
4197 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4198
4199 if (rc || (pSMBr->ByteCount < 18))
4200 rc = -EIO; /* bad smb */
4201 else {
4202 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004203 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004204 pSMBr->ByteCount, data_offset));
4205
Steve French50c2f752007-07-13 00:33:32 +00004206 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004207 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4208 FSData->f_bsize =
4209 le16_to_cpu(response_data->BytesPerSector) *
4210 le32_to_cpu(response_data->
4211 SectorsPerAllocationUnit);
4212 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004213 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004214 FSData->f_bfree = FSData->f_bavail =
4215 le32_to_cpu(response_data->FreeAllocationUnits);
4216 cFYI(1,
4217 ("Blocks: %lld Free: %lld Block size %ld",
4218 (unsigned long long)FSData->f_blocks,
4219 (unsigned long long)FSData->f_bfree,
4220 FSData->f_bsize));
4221 }
4222 }
4223 cifs_buf_release(pSMB);
4224
4225 if (rc == -EAGAIN)
4226 goto oldQFSInfoRetry;
4227
4228 return rc;
4229}
4230
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231int
Steve French737b7582005-04-28 22:41:06 -07004232CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233{
4234/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4235 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4236 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4237 FILE_SYSTEM_INFO *response_data;
4238 int rc = 0;
4239 int bytes_returned = 0;
4240 __u16 params, byte_count;
4241
4242 cFYI(1, ("In QFSInfo"));
4243QFSInfoRetry:
4244 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4245 (void **) &pSMBr);
4246 if (rc)
4247 return rc;
4248
4249 params = 2; /* level */
4250 pSMB->TotalDataCount = 0;
4251 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004252 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 pSMB->MaxSetupCount = 0;
4254 pSMB->Reserved = 0;
4255 pSMB->Flags = 0;
4256 pSMB->Timeout = 0;
4257 pSMB->Reserved2 = 0;
4258 byte_count = params + 1 /* pad */ ;
4259 pSMB->TotalParameterCount = cpu_to_le16(params);
4260 pSMB->ParameterCount = pSMB->TotalParameterCount;
4261 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004262 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 pSMB->DataCount = 0;
4264 pSMB->DataOffset = 0;
4265 pSMB->SetupCount = 1;
4266 pSMB->Reserved3 = 0;
4267 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4268 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4269 pSMB->hdr.smb_buf_length += byte_count;
4270 pSMB->ByteCount = cpu_to_le16(byte_count);
4271
4272 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4273 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4274 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004275 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004277 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278
Steve French20962432005-09-21 22:05:57 -07004279 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 rc = -EIO; /* bad smb */
4281 else {
4282 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
4284 response_data =
4285 (FILE_SYSTEM_INFO
4286 *) (((char *) &pSMBr->hdr.Protocol) +
4287 data_offset);
4288 FSData->f_bsize =
4289 le32_to_cpu(response_data->BytesPerSector) *
4290 le32_to_cpu(response_data->
4291 SectorsPerAllocationUnit);
4292 FSData->f_blocks =
4293 le64_to_cpu(response_data->TotalAllocationUnits);
4294 FSData->f_bfree = FSData->f_bavail =
4295 le64_to_cpu(response_data->FreeAllocationUnits);
4296 cFYI(1,
4297 ("Blocks: %lld Free: %lld Block size %ld",
4298 (unsigned long long)FSData->f_blocks,
4299 (unsigned long long)FSData->f_bfree,
4300 FSData->f_bsize));
4301 }
4302 }
4303 cifs_buf_release(pSMB);
4304
4305 if (rc == -EAGAIN)
4306 goto QFSInfoRetry;
4307
4308 return rc;
4309}
4310
4311int
Steve French737b7582005-04-28 22:41:06 -07004312CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313{
4314/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4315 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4316 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4317 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4318 int rc = 0;
4319 int bytes_returned = 0;
4320 __u16 params, byte_count;
4321
4322 cFYI(1, ("In QFSAttributeInfo"));
4323QFSAttributeRetry:
4324 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4325 (void **) &pSMBr);
4326 if (rc)
4327 return rc;
4328
4329 params = 2; /* level */
4330 pSMB->TotalDataCount = 0;
4331 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004332 /* BB find exact max SMB PDU from sess structure BB */
4333 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 pSMB->MaxSetupCount = 0;
4335 pSMB->Reserved = 0;
4336 pSMB->Flags = 0;
4337 pSMB->Timeout = 0;
4338 pSMB->Reserved2 = 0;
4339 byte_count = params + 1 /* pad */ ;
4340 pSMB->TotalParameterCount = cpu_to_le16(params);
4341 pSMB->ParameterCount = pSMB->TotalParameterCount;
4342 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004343 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 pSMB->DataCount = 0;
4345 pSMB->DataOffset = 0;
4346 pSMB->SetupCount = 1;
4347 pSMB->Reserved3 = 0;
4348 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4349 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4350 pSMB->hdr.smb_buf_length += byte_count;
4351 pSMB->ByteCount = cpu_to_le16(byte_count);
4352
4353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4355 if (rc) {
4356 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4357 } else { /* decode response */
4358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4359
Steve French50c2f752007-07-13 00:33:32 +00004360 if (rc || (pSMBr->ByteCount < 13)) {
4361 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 rc = -EIO; /* bad smb */
4363 } else {
4364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4365 response_data =
4366 (FILE_SYSTEM_ATTRIBUTE_INFO
4367 *) (((char *) &pSMBr->hdr.Protocol) +
4368 data_offset);
4369 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004370 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 }
4372 }
4373 cifs_buf_release(pSMB);
4374
4375 if (rc == -EAGAIN)
4376 goto QFSAttributeRetry;
4377
4378 return rc;
4379}
4380
4381int
Steve French737b7582005-04-28 22:41:06 -07004382CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383{
4384/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4385 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4386 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4387 FILE_SYSTEM_DEVICE_INFO *response_data;
4388 int rc = 0;
4389 int bytes_returned = 0;
4390 __u16 params, byte_count;
4391
4392 cFYI(1, ("In QFSDeviceInfo"));
4393QFSDeviceRetry:
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4398
4399 params = 2; /* level */
4400 pSMB->TotalDataCount = 0;
4401 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004402 /* BB find exact max SMB PDU from sess structure BB */
4403 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 pSMB->MaxSetupCount = 0;
4405 pSMB->Reserved = 0;
4406 pSMB->Flags = 0;
4407 pSMB->Timeout = 0;
4408 pSMB->Reserved2 = 0;
4409 byte_count = params + 1 /* pad */ ;
4410 pSMB->TotalParameterCount = cpu_to_le16(params);
4411 pSMB->ParameterCount = pSMB->TotalParameterCount;
4412 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004413 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414
4415 pSMB->DataCount = 0;
4416 pSMB->DataOffset = 0;
4417 pSMB->SetupCount = 1;
4418 pSMB->Reserved3 = 0;
4419 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4420 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4421 pSMB->hdr.smb_buf_length += byte_count;
4422 pSMB->ByteCount = cpu_to_le16(byte_count);
4423
4424 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4425 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4426 if (rc) {
4427 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4428 } else { /* decode response */
4429 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4430
Steve French630f3f02007-10-25 21:17:17 +00004431 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 rc = -EIO; /* bad smb */
4433 else {
4434 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4435 response_data =
Steve French737b7582005-04-28 22:41:06 -07004436 (FILE_SYSTEM_DEVICE_INFO *)
4437 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 data_offset);
4439 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004440 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 }
4442 }
4443 cifs_buf_release(pSMB);
4444
4445 if (rc == -EAGAIN)
4446 goto QFSDeviceRetry;
4447
4448 return rc;
4449}
4450
4451int
Steve French737b7582005-04-28 22:41:06 -07004452CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453{
4454/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4455 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4456 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4457 FILE_SYSTEM_UNIX_INFO *response_data;
4458 int rc = 0;
4459 int bytes_returned = 0;
4460 __u16 params, byte_count;
4461
4462 cFYI(1, ("In QFSUnixInfo"));
4463QFSUnixRetry:
4464 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4465 (void **) &pSMBr);
4466 if (rc)
4467 return rc;
4468
4469 params = 2; /* level */
4470 pSMB->TotalDataCount = 0;
4471 pSMB->DataCount = 0;
4472 pSMB->DataOffset = 0;
4473 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004474 /* BB find exact max SMB PDU from sess structure BB */
4475 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 pSMB->MaxSetupCount = 0;
4477 pSMB->Reserved = 0;
4478 pSMB->Flags = 0;
4479 pSMB->Timeout = 0;
4480 pSMB->Reserved2 = 0;
4481 byte_count = params + 1 /* pad */ ;
4482 pSMB->ParameterCount = cpu_to_le16(params);
4483 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004484 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4485 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 pSMB->SetupCount = 1;
4487 pSMB->Reserved3 = 0;
4488 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4489 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4490 pSMB->hdr.smb_buf_length += byte_count;
4491 pSMB->ByteCount = cpu_to_le16(byte_count);
4492
4493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4494 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4495 if (rc) {
4496 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4497 } else { /* decode response */
4498 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4499
4500 if (rc || (pSMBr->ByteCount < 13)) {
4501 rc = -EIO; /* bad smb */
4502 } else {
4503 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4504 response_data =
4505 (FILE_SYSTEM_UNIX_INFO
4506 *) (((char *) &pSMBr->hdr.Protocol) +
4507 data_offset);
4508 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004509 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 }
4511 }
4512 cifs_buf_release(pSMB);
4513
4514 if (rc == -EAGAIN)
4515 goto QFSUnixRetry;
4516
4517
4518 return rc;
4519}
4520
Jeremy Allisonac670552005-06-22 17:26:35 -07004521int
Steve French45abc6e2005-06-23 13:42:03 -05004522CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004523{
4524/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4525 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4526 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4527 int rc = 0;
4528 int bytes_returned = 0;
4529 __u16 params, param_offset, offset, byte_count;
4530
4531 cFYI(1, ("In SETFSUnixInfo"));
4532SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004533 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4535 (void **) &pSMBr);
4536 if (rc)
4537 return rc;
4538
4539 params = 4; /* 2 bytes zero followed by info level. */
4540 pSMB->MaxSetupCount = 0;
4541 pSMB->Reserved = 0;
4542 pSMB->Flags = 0;
4543 pSMB->Timeout = 0;
4544 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004545 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4546 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004547 offset = param_offset + params;
4548
4549 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004550 /* BB find exact max SMB PDU from sess structure BB */
4551 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004552 pSMB->SetupCount = 1;
4553 pSMB->Reserved3 = 0;
4554 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4555 byte_count = 1 /* pad */ + params + 12;
4556
4557 pSMB->DataCount = cpu_to_le16(12);
4558 pSMB->ParameterCount = cpu_to_le16(params);
4559 pSMB->TotalDataCount = pSMB->DataCount;
4560 pSMB->TotalParameterCount = pSMB->ParameterCount;
4561 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4562 pSMB->DataOffset = cpu_to_le16(offset);
4563
4564 /* Params. */
4565 pSMB->FileNum = 0;
4566 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4567
4568 /* Data. */
4569 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4570 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4571 pSMB->ClientUnixCap = cpu_to_le64(cap);
4572
4573 pSMB->hdr.smb_buf_length += byte_count;
4574 pSMB->ByteCount = cpu_to_le16(byte_count);
4575
4576 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4577 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4578 if (rc) {
4579 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4580 } else { /* decode response */
4581 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004582 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004583 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004584 }
4585 cifs_buf_release(pSMB);
4586
4587 if (rc == -EAGAIN)
4588 goto SETFSUnixRetry;
4589
4590 return rc;
4591}
4592
4593
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594
4595int
4596CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004597 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598{
4599/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4600 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4601 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4602 FILE_SYSTEM_POSIX_INFO *response_data;
4603 int rc = 0;
4604 int bytes_returned = 0;
4605 __u16 params, byte_count;
4606
4607 cFYI(1, ("In QFSPosixInfo"));
4608QFSPosixRetry:
4609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4610 (void **) &pSMBr);
4611 if (rc)
4612 return rc;
4613
4614 params = 2; /* level */
4615 pSMB->TotalDataCount = 0;
4616 pSMB->DataCount = 0;
4617 pSMB->DataOffset = 0;
4618 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004619 /* BB find exact max SMB PDU from sess structure BB */
4620 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 pSMB->MaxSetupCount = 0;
4622 pSMB->Reserved = 0;
4623 pSMB->Flags = 0;
4624 pSMB->Timeout = 0;
4625 pSMB->Reserved2 = 0;
4626 byte_count = params + 1 /* pad */ ;
4627 pSMB->ParameterCount = cpu_to_le16(params);
4628 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004629 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4630 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 pSMB->SetupCount = 1;
4632 pSMB->Reserved3 = 0;
4633 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4634 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4635 pSMB->hdr.smb_buf_length += byte_count;
4636 pSMB->ByteCount = cpu_to_le16(byte_count);
4637
4638 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4639 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4640 if (rc) {
4641 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4642 } else { /* decode response */
4643 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4644
4645 if (rc || (pSMBr->ByteCount < 13)) {
4646 rc = -EIO; /* bad smb */
4647 } else {
4648 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4649 response_data =
4650 (FILE_SYSTEM_POSIX_INFO
4651 *) (((char *) &pSMBr->hdr.Protocol) +
4652 data_offset);
4653 FSData->f_bsize =
4654 le32_to_cpu(response_data->BlockSize);
4655 FSData->f_blocks =
4656 le64_to_cpu(response_data->TotalBlocks);
4657 FSData->f_bfree =
4658 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004659 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 FSData->f_bavail = FSData->f_bfree;
4661 } else {
4662 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004663 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 }
Steve French790fe572007-07-07 19:25:05 +00004665 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004667 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004668 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004670 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 }
4672 }
4673 cifs_buf_release(pSMB);
4674
4675 if (rc == -EAGAIN)
4676 goto QFSPosixRetry;
4677
4678 return rc;
4679}
4680
4681
Steve French50c2f752007-07-13 00:33:32 +00004682/* We can not use write of zero bytes trick to
4683 set file size due to need for large file support. Also note that
4684 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 routine which is only needed to work around a sharing violation bug
4686 in Samba which this routine can run into */
4687
4688int
4689CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004690 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004691 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692{
4693 struct smb_com_transaction2_spi_req *pSMB = NULL;
4694 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4695 struct file_end_of_file_info *parm_data;
4696 int name_len;
4697 int rc = 0;
4698 int bytes_returned = 0;
4699 __u16 params, byte_count, data_count, param_offset, offset;
4700
4701 cFYI(1, ("In SetEOF"));
4702SetEOFRetry:
4703 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4704 (void **) &pSMBr);
4705 if (rc)
4706 return rc;
4707
4708 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4709 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004710 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004711 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 name_len++; /* trailing null */
4713 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004714 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 name_len = strnlen(fileName, PATH_MAX);
4716 name_len++; /* trailing null */
4717 strncpy(pSMB->FileName, fileName, name_len);
4718 }
4719 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004720 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004722 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 pSMB->MaxSetupCount = 0;
4724 pSMB->Reserved = 0;
4725 pSMB->Flags = 0;
4726 pSMB->Timeout = 0;
4727 pSMB->Reserved2 = 0;
4728 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004729 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004731 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004732 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733 pSMB->InformationLevel =
4734 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4735 else
4736 pSMB->InformationLevel =
4737 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4738 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4740 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004741 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 else
4743 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004744 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 }
4746
4747 parm_data =
4748 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4749 offset);
4750 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4751 pSMB->DataOffset = cpu_to_le16(offset);
4752 pSMB->SetupCount = 1;
4753 pSMB->Reserved3 = 0;
4754 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4755 byte_count = 3 /* pad */ + params + data_count;
4756 pSMB->DataCount = cpu_to_le16(data_count);
4757 pSMB->TotalDataCount = pSMB->DataCount;
4758 pSMB->ParameterCount = cpu_to_le16(params);
4759 pSMB->TotalParameterCount = pSMB->ParameterCount;
4760 pSMB->Reserved4 = 0;
4761 pSMB->hdr.smb_buf_length += byte_count;
4762 parm_data->FileSize = cpu_to_le64(size);
4763 pSMB->ByteCount = cpu_to_le16(byte_count);
4764 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4765 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004766 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
4769 cifs_buf_release(pSMB);
4770
4771 if (rc == -EAGAIN)
4772 goto SetEOFRetry;
4773
4774 return rc;
4775}
4776
4777int
Steve French50c2f752007-07-13 00:33:32 +00004778CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004779 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780{
4781 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 char *data_offset;
4783 struct file_end_of_file_info *parm_data;
4784 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 __u16 params, param_offset, offset, byte_count, count;
4786
4787 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4788 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004789 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4790
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 if (rc)
4792 return rc;
4793
4794 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4795 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004796
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 params = 6;
4798 pSMB->MaxSetupCount = 0;
4799 pSMB->Reserved = 0;
4800 pSMB->Flags = 0;
4801 pSMB->Timeout = 0;
4802 pSMB->Reserved2 = 0;
4803 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4804 offset = param_offset + params;
4805
Steve French50c2f752007-07-13 00:33:32 +00004806 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
4808 count = sizeof(struct file_end_of_file_info);
4809 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004810 /* BB find exact max SMB PDU from sess structure BB */
4811 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 pSMB->SetupCount = 1;
4813 pSMB->Reserved3 = 0;
4814 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4815 byte_count = 3 /* pad */ + params + count;
4816 pSMB->DataCount = cpu_to_le16(count);
4817 pSMB->ParameterCount = cpu_to_le16(params);
4818 pSMB->TotalDataCount = pSMB->DataCount;
4819 pSMB->TotalParameterCount = pSMB->ParameterCount;
4820 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4821 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004822 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4823 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 pSMB->DataOffset = cpu_to_le16(offset);
4825 parm_data->FileSize = cpu_to_le64(size);
4826 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004827 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4829 pSMB->InformationLevel =
4830 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4831 else
4832 pSMB->InformationLevel =
4833 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004834 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4836 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004837 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 else
4839 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004840 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 }
4842 pSMB->Reserved4 = 0;
4843 pSMB->hdr.smb_buf_length += byte_count;
4844 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004845 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 if (rc) {
4847 cFYI(1,
4848 ("Send error in SetFileInfo (SetFileSize) = %d",
4849 rc));
4850 }
4851
Steve French50c2f752007-07-13 00:33:32 +00004852 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 since file handle passed in no longer valid */
4854
4855 return rc;
4856}
4857
Steve French50c2f752007-07-13 00:33:32 +00004858/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 an open handle, rather than by pathname - this is awkward due to
4860 potential access conflicts on the open, but it is unavoidable for these
4861 old servers since the only other choice is to go from 100 nanosecond DCE
4862 time and resort to the original setpathinfo level which takes the ancient
4863 DOS time format with 2 second granularity */
4864int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004865CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4866 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867{
4868 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 char *data_offset;
4870 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 __u16 params, param_offset, offset, byte_count, count;
4872
4873 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004874 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4875
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 if (rc)
4877 return rc;
4878
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004879 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4880 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004881
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 params = 6;
4883 pSMB->MaxSetupCount = 0;
4884 pSMB->Reserved = 0;
4885 pSMB->Flags = 0;
4886 pSMB->Timeout = 0;
4887 pSMB->Reserved2 = 0;
4888 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4889 offset = param_offset + params;
4890
Steve French50c2f752007-07-13 00:33:32 +00004891 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
Steve French26f57362007-08-30 22:09:15 +00004893 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004895 /* BB find max SMB PDU from sess */
4896 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 pSMB->SetupCount = 1;
4898 pSMB->Reserved3 = 0;
4899 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4900 byte_count = 3 /* pad */ + params + count;
4901 pSMB->DataCount = cpu_to_le16(count);
4902 pSMB->ParameterCount = cpu_to_le16(params);
4903 pSMB->TotalDataCount = pSMB->DataCount;
4904 pSMB->TotalParameterCount = pSMB->ParameterCount;
4905 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4906 pSMB->DataOffset = cpu_to_le16(offset);
4907 pSMB->Fid = fid;
4908 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4909 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4910 else
4911 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4912 pSMB->Reserved4 = 0;
4913 pSMB->hdr.smb_buf_length += byte_count;
4914 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004915 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004916 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004917 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004918 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919
Steve French50c2f752007-07-13 00:33:32 +00004920 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 since file handle passed in no longer valid */
4922
4923 return rc;
4924}
4925
Jeff Layton6d22f092008-09-23 11:48:35 -04004926int
4927CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4928 bool delete_file, __u16 fid, __u32 pid_of_opener)
4929{
4930 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4931 char *data_offset;
4932 int rc = 0;
4933 __u16 params, param_offset, offset, byte_count, count;
4934
4935 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4936 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4937
4938 if (rc)
4939 return rc;
4940
4941 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4942 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4943
4944 params = 6;
4945 pSMB->MaxSetupCount = 0;
4946 pSMB->Reserved = 0;
4947 pSMB->Flags = 0;
4948 pSMB->Timeout = 0;
4949 pSMB->Reserved2 = 0;
4950 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4951 offset = param_offset + params;
4952
4953 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4954
4955 count = 1;
4956 pSMB->MaxParameterCount = cpu_to_le16(2);
4957 /* BB find max SMB PDU from sess */
4958 pSMB->MaxDataCount = cpu_to_le16(1000);
4959 pSMB->SetupCount = 1;
4960 pSMB->Reserved3 = 0;
4961 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4962 byte_count = 3 /* pad */ + params + count;
4963 pSMB->DataCount = cpu_to_le16(count);
4964 pSMB->ParameterCount = cpu_to_le16(params);
4965 pSMB->TotalDataCount = pSMB->DataCount;
4966 pSMB->TotalParameterCount = pSMB->ParameterCount;
4967 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4968 pSMB->DataOffset = cpu_to_le16(offset);
4969 pSMB->Fid = fid;
4970 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4971 pSMB->Reserved4 = 0;
4972 pSMB->hdr.smb_buf_length += byte_count;
4973 pSMB->ByteCount = cpu_to_le16(byte_count);
4974 *data_offset = delete_file ? 1 : 0;
4975 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4976 if (rc)
4977 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4978
4979 return rc;
4980}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981
4982int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004983CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4984 const char *fileName, const FILE_BASIC_INFO *data,
4985 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986{
4987 TRANSACTION2_SPI_REQ *pSMB = NULL;
4988 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4989 int name_len;
4990 int rc = 0;
4991 int bytes_returned = 0;
4992 char *data_offset;
4993 __u16 params, param_offset, offset, byte_count, count;
4994
4995 cFYI(1, ("In SetTimes"));
4996
4997SetTimesRetry:
4998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4999 (void **) &pSMBr);
5000 if (rc)
5001 return rc;
5002
5003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5004 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005005 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005006 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 name_len++; /* trailing null */
5008 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005009 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 name_len = strnlen(fileName, PATH_MAX);
5011 name_len++; /* trailing null */
5012 strncpy(pSMB->FileName, fileName, name_len);
5013 }
5014
5015 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005016 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005018 /* BB find max SMB PDU from sess structure BB */
5019 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 pSMB->MaxSetupCount = 0;
5021 pSMB->Reserved = 0;
5022 pSMB->Flags = 0;
5023 pSMB->Timeout = 0;
5024 pSMB->Reserved2 = 0;
5025 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005026 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 offset = param_offset + params;
5028 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5029 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5030 pSMB->DataOffset = cpu_to_le16(offset);
5031 pSMB->SetupCount = 1;
5032 pSMB->Reserved3 = 0;
5033 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5034 byte_count = 3 /* pad */ + params + count;
5035
5036 pSMB->DataCount = cpu_to_le16(count);
5037 pSMB->ParameterCount = cpu_to_le16(params);
5038 pSMB->TotalDataCount = pSMB->DataCount;
5039 pSMB->TotalParameterCount = pSMB->ParameterCount;
5040 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5041 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5042 else
5043 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5044 pSMB->Reserved4 = 0;
5045 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005046 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 pSMB->ByteCount = cpu_to_le16(byte_count);
5048 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5049 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005050 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052
5053 cifs_buf_release(pSMB);
5054
5055 if (rc == -EAGAIN)
5056 goto SetTimesRetry;
5057
5058 return rc;
5059}
5060
5061/* Can not be used to set time stamps yet (due to old DOS time format) */
5062/* Can be used to set attributes */
5063#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5064 handling it anyway and NT4 was what we thought it would be needed for
5065 Do not delete it until we prove whether needed for Win9x though */
5066int
5067CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5068 __u16 dos_attrs, const struct nls_table *nls_codepage)
5069{
5070 SETATTR_REQ *pSMB = NULL;
5071 SETATTR_RSP *pSMBr = NULL;
5072 int rc = 0;
5073 int bytes_returned;
5074 int name_len;
5075
5076 cFYI(1, ("In SetAttrLegacy"));
5077
5078SetAttrLgcyRetry:
5079 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5080 (void **) &pSMBr);
5081 if (rc)
5082 return rc;
5083
5084 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5085 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005086 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 PATH_MAX, nls_codepage);
5088 name_len++; /* trailing null */
5089 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005090 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 name_len = strnlen(fileName, PATH_MAX);
5092 name_len++; /* trailing null */
5093 strncpy(pSMB->fileName, fileName, name_len);
5094 }
5095 pSMB->attr = cpu_to_le16(dos_attrs);
5096 pSMB->BufferFormat = 0x04;
5097 pSMB->hdr.smb_buf_length += name_len + 1;
5098 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005101 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103
5104 cifs_buf_release(pSMB);
5105
5106 if (rc == -EAGAIN)
5107 goto SetAttrLgcyRetry;
5108
5109 return rc;
5110}
5111#endif /* temporarily unneeded SetAttr legacy function */
5112
5113int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005114CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005115 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005116 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117{
5118 TRANSACTION2_SPI_REQ *pSMB = NULL;
5119 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5120 int name_len;
5121 int rc = 0;
5122 int bytes_returned = 0;
5123 FILE_UNIX_BASIC_INFO *data_offset;
5124 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005125 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126
5127 cFYI(1, ("In SetUID/GID/Mode"));
5128setPermsRetry:
5129 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5130 (void **) &pSMBr);
5131 if (rc)
5132 return rc;
5133
5134 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5135 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005136 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005137 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 name_len++; /* trailing null */
5139 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005140 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 name_len = strnlen(fileName, PATH_MAX);
5142 name_len++; /* trailing null */
5143 strncpy(pSMB->FileName, fileName, name_len);
5144 }
5145
5146 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005147 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005149 /* BB find max SMB PDU from sess structure BB */
5150 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 pSMB->MaxSetupCount = 0;
5152 pSMB->Reserved = 0;
5153 pSMB->Flags = 0;
5154 pSMB->Timeout = 0;
5155 pSMB->Reserved2 = 0;
5156 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005157 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 offset = param_offset + params;
5159 data_offset =
5160 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5161 offset);
5162 memset(data_offset, 0, count);
5163 pSMB->DataOffset = cpu_to_le16(offset);
5164 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5165 pSMB->SetupCount = 1;
5166 pSMB->Reserved3 = 0;
5167 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5168 byte_count = 3 /* pad */ + params + count;
5169 pSMB->ParameterCount = cpu_to_le16(params);
5170 pSMB->DataCount = cpu_to_le16(count);
5171 pSMB->TotalParameterCount = pSMB->ParameterCount;
5172 pSMB->TotalDataCount = pSMB->DataCount;
5173 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5174 pSMB->Reserved4 = 0;
5175 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005176 /* Samba server ignores set of file size to zero due to bugs in some
5177 older clients, but we should be precise - we use SetFileSize to
5178 set file size and do not want to truncate file size to zero
5179 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005180 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005181 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5182 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5183 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5184 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5185 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5186 data_offset->Uid = cpu_to_le64(args->uid);
5187 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005189 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5190 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005192
Steve French790fe572007-07-07 19:25:05 +00005193 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005195 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005197 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005199 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005201 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005203 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005205 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5207
5208
5209 pSMB->ByteCount = cpu_to_le16(byte_count);
5210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005212 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214
Steve French0d817bc2008-05-22 02:02:03 +00005215 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 if (rc == -EAGAIN)
5217 goto setPermsRetry;
5218 return rc;
5219}
5220
Steve French50c2f752007-07-13 00:33:32 +00005221int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005222 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005223 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005224 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225{
5226 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005227 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5228 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005229 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 int bytes_returned;
5231
Steve French50c2f752007-07-13 00:33:32 +00005232 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005234 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 if (rc)
5236 return rc;
5237
5238 pSMB->TotalParameterCount = 0 ;
5239 pSMB->TotalDataCount = 0;
5240 pSMB->MaxParameterCount = cpu_to_le32(2);
5241 /* BB find exact data count max from sess structure BB */
5242 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005243/* BB VERIFY verify which is correct for above BB */
5244 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5245 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5246
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 pSMB->MaxSetupCount = 4;
5248 pSMB->Reserved = 0;
5249 pSMB->ParameterOffset = 0;
5250 pSMB->DataCount = 0;
5251 pSMB->DataOffset = 0;
5252 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5253 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5254 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005255 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5257 pSMB->Reserved2 = 0;
5258 pSMB->CompletionFilter = cpu_to_le32(filter);
5259 pSMB->Fid = netfid; /* file handle always le */
5260 pSMB->ByteCount = 0;
5261
5262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005263 (struct smb_hdr *)pSMBr, &bytes_returned,
5264 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 if (rc) {
5266 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005267 } else {
5268 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005269 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005270 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005271 sizeof(struct dir_notify_req),
5272 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005273 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005274 dnotify_req->Pid = pSMB->hdr.Pid;
5275 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5276 dnotify_req->Mid = pSMB->hdr.Mid;
5277 dnotify_req->Tid = pSMB->hdr.Tid;
5278 dnotify_req->Uid = pSMB->hdr.Uid;
5279 dnotify_req->netfid = netfid;
5280 dnotify_req->pfile = pfile;
5281 dnotify_req->filter = filter;
5282 dnotify_req->multishot = multishot;
5283 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005284 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005285 &GlobalDnotifyReqList);
5286 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005287 } else
Steve French47c786e2005-10-11 20:03:18 -07005288 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 }
5290 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005291 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292}
5293#ifdef CONFIG_CIFS_XATTR
5294ssize_t
5295CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5296 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005297 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005298 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299{
5300 /* BB assumes one setup word */
5301 TRANSACTION2_QPI_REQ *pSMB = NULL;
5302 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5303 int rc = 0;
5304 int bytes_returned;
5305 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005306 struct fea *temp_fea;
5307 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 __u16 params, byte_count;
5309
5310 cFYI(1, ("In Query All EAs path %s", searchName));
5311QAllEAsRetry:
5312 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5313 (void **) &pSMBr);
5314 if (rc)
5315 return rc;
5316
5317 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5318 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005319 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005320 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 name_len++; /* trailing null */
5322 name_len *= 2;
5323 } else { /* BB improve the check for buffer overruns BB */
5324 name_len = strnlen(searchName, PATH_MAX);
5325 name_len++; /* trailing null */
5326 strncpy(pSMB->FileName, searchName, name_len);
5327 }
5328
Steve French50c2f752007-07-13 00:33:32 +00005329 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 pSMB->TotalDataCount = 0;
5331 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005332 /* BB find exact max SMB PDU from sess structure BB */
5333 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 pSMB->MaxSetupCount = 0;
5335 pSMB->Reserved = 0;
5336 pSMB->Flags = 0;
5337 pSMB->Timeout = 0;
5338 pSMB->Reserved2 = 0;
5339 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005340 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 pSMB->DataCount = 0;
5342 pSMB->DataOffset = 0;
5343 pSMB->SetupCount = 1;
5344 pSMB->Reserved3 = 0;
5345 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5346 byte_count = params + 1 /* pad */ ;
5347 pSMB->TotalParameterCount = cpu_to_le16(params);
5348 pSMB->ParameterCount = pSMB->TotalParameterCount;
5349 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5350 pSMB->Reserved4 = 0;
5351 pSMB->hdr.smb_buf_length += byte_count;
5352 pSMB->ByteCount = cpu_to_le16(byte_count);
5353
5354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5355 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5356 if (rc) {
5357 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5358 } else { /* decode response */
5359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5360
5361 /* BB also check enough total bytes returned */
5362 /* BB we need to improve the validity checking
5363 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005364 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 rc = -EIO; /* bad smb */
5366 /* else if (pFindData){
5367 memcpy((char *) pFindData,
5368 (char *) &pSMBr->hdr.Protocol +
5369 data_offset, kl);
5370 }*/ else {
5371 /* check that length of list is not more than bcc */
5372 /* check that each entry does not go beyond length
5373 of list */
5374 /* check that each element of each entry does not
5375 go beyond end of list */
5376 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005377 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 rc = 0;
5379 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005380 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 ea_response_data = (struct fealist *)
5382 (((char *) &pSMBr->hdr.Protocol) +
5383 data_offset);
5384 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005385 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005386 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005388 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 } else {
5390 /* account for ea list len */
5391 name_len -= 4;
5392 temp_fea = ea_response_data->list;
5393 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005394 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 __u16 value_len;
5396 name_len -= 4;
5397 temp_ptr += 4;
5398 rc += temp_fea->name_len;
5399 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005400 rc = rc + 5 + 1;
5401 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005402 memcpy(EAData, "user.", 5);
5403 EAData += 5;
5404 memcpy(EAData, temp_ptr,
5405 temp_fea->name_len);
5406 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 /* null terminate name */
5408 *EAData = 0;
5409 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005410 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 /* skip copy - calc size only */
5412 } else {
5413 /* stop before overrun buffer */
5414 rc = -ERANGE;
5415 break;
5416 }
5417 name_len -= temp_fea->name_len;
5418 temp_ptr += temp_fea->name_len;
5419 /* account for trailing null */
5420 name_len--;
5421 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005422 value_len =
5423 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 name_len -= value_len;
5425 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005426 /* BB check that temp_ptr is still
5427 within the SMB BB*/
5428
5429 /* no trailing null to account for
5430 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 /* go on to next EA */
5432 temp_fea = (struct fea *)temp_ptr;
5433 }
5434 }
5435 }
5436 }
Steve French0d817bc2008-05-22 02:02:03 +00005437 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 if (rc == -EAGAIN)
5439 goto QAllEAsRetry;
5440
5441 return (ssize_t)rc;
5442}
5443
Steve French50c2f752007-07-13 00:33:32 +00005444ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5445 const unsigned char *searchName, const unsigned char *ea_name,
5446 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005447 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448{
5449 TRANSACTION2_QPI_REQ *pSMB = NULL;
5450 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5451 int rc = 0;
5452 int bytes_returned;
5453 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005454 struct fea *temp_fea;
5455 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 __u16 params, byte_count;
5457
5458 cFYI(1, ("In Query EA path %s", searchName));
5459QEARetry:
5460 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5461 (void **) &pSMBr);
5462 if (rc)
5463 return rc;
5464
5465 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5466 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005467 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005468 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 name_len++; /* trailing null */
5470 name_len *= 2;
5471 } else { /* BB improve the check for buffer overruns BB */
5472 name_len = strnlen(searchName, PATH_MAX);
5473 name_len++; /* trailing null */
5474 strncpy(pSMB->FileName, searchName, name_len);
5475 }
5476
Steve French50c2f752007-07-13 00:33:32 +00005477 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 pSMB->TotalDataCount = 0;
5479 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005480 /* BB find exact max SMB PDU from sess structure BB */
5481 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 pSMB->MaxSetupCount = 0;
5483 pSMB->Reserved = 0;
5484 pSMB->Flags = 0;
5485 pSMB->Timeout = 0;
5486 pSMB->Reserved2 = 0;
5487 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005488 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 pSMB->DataCount = 0;
5490 pSMB->DataOffset = 0;
5491 pSMB->SetupCount = 1;
5492 pSMB->Reserved3 = 0;
5493 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5494 byte_count = params + 1 /* pad */ ;
5495 pSMB->TotalParameterCount = cpu_to_le16(params);
5496 pSMB->ParameterCount = pSMB->TotalParameterCount;
5497 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5498 pSMB->Reserved4 = 0;
5499 pSMB->hdr.smb_buf_length += byte_count;
5500 pSMB->ByteCount = cpu_to_le16(byte_count);
5501
5502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5504 if (rc) {
5505 cFYI(1, ("Send error in Query EA = %d", rc));
5506 } else { /* decode response */
5507 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5508
5509 /* BB also check enough total bytes returned */
5510 /* BB we need to improve the validity checking
5511 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005512 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 rc = -EIO; /* bad smb */
5514 /* else if (pFindData){
5515 memcpy((char *) pFindData,
5516 (char *) &pSMBr->hdr.Protocol +
5517 data_offset, kl);
5518 }*/ else {
5519 /* check that length of list is not more than bcc */
5520 /* check that each entry does not go beyond length
5521 of list */
5522 /* check that each element of each entry does not
5523 go beyond end of list */
5524 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005525 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 rc = -ENODATA;
5527 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005528 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 ea_response_data = (struct fealist *)
5530 (((char *) &pSMBr->hdr.Protocol) +
5531 data_offset);
5532 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005533 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005534 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005536 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 } else {
5538 /* account for ea list len */
5539 name_len -= 4;
5540 temp_fea = ea_response_data->list;
5541 temp_ptr = (char *)temp_fea;
5542 /* loop through checking if we have a matching
5543 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005544 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 __u16 value_len;
5546 name_len -= 4;
5547 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005548 value_len =
5549 le16_to_cpu(temp_fea->value_len);
5550 /* BB validate that value_len falls within SMB,
5551 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005552 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 temp_fea->name_len) == 0) {
5554 /* found a match */
5555 rc = value_len;
5556 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005557 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 memcpy(ea_value,
5559 temp_fea->name+temp_fea->name_len+1,
5560 rc);
Steve French50c2f752007-07-13 00:33:32 +00005561 /* ea values, unlike ea
5562 names, are not null
5563 terminated */
Steve French790fe572007-07-07 19:25:05 +00005564 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 /* skip copy - calc size only */
5566 } else {
Steve French50c2f752007-07-13 00:33:32 +00005567 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 rc = -ERANGE;
5569 }
5570 break;
5571 }
5572 name_len -= temp_fea->name_len;
5573 temp_ptr += temp_fea->name_len;
5574 /* account for trailing null */
5575 name_len--;
5576 temp_ptr++;
5577 name_len -= value_len;
5578 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005579 /* No trailing null to account for in
5580 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 temp_fea = (struct fea *)temp_ptr;
5582 }
Steve French50c2f752007-07-13 00:33:32 +00005583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 }
5585 }
Steve French0d817bc2008-05-22 02:02:03 +00005586 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 if (rc == -EAGAIN)
5588 goto QEARetry;
5589
5590 return (ssize_t)rc;
5591}
5592
5593int
5594CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005595 const char *ea_name, const void *ea_value,
5596 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5597 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598{
5599 struct smb_com_transaction2_spi_req *pSMB = NULL;
5600 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5601 struct fealist *parm_data;
5602 int name_len;
5603 int rc = 0;
5604 int bytes_returned = 0;
5605 __u16 params, param_offset, byte_count, offset, count;
5606
5607 cFYI(1, ("In SetEA"));
5608SetEARetry:
5609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5610 (void **) &pSMBr);
5611 if (rc)
5612 return rc;
5613
5614 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5615 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005616 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005617 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 name_len++; /* trailing null */
5619 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005620 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 name_len = strnlen(fileName, PATH_MAX);
5622 name_len++; /* trailing null */
5623 strncpy(pSMB->FileName, fileName, name_len);
5624 }
5625
5626 params = 6 + name_len;
5627
5628 /* done calculating parms using name_len of file name,
5629 now use name_len to calculate length of ea name
5630 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005631 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 name_len = 0;
5633 else
Steve French50c2f752007-07-13 00:33:32 +00005634 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005636 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005638 /* BB find max SMB PDU from sess */
5639 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 pSMB->MaxSetupCount = 0;
5641 pSMB->Reserved = 0;
5642 pSMB->Flags = 0;
5643 pSMB->Timeout = 0;
5644 pSMB->Reserved2 = 0;
5645 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005646 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 offset = param_offset + params;
5648 pSMB->InformationLevel =
5649 cpu_to_le16(SMB_SET_FILE_EA);
5650
5651 parm_data =
5652 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5653 offset);
5654 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5655 pSMB->DataOffset = cpu_to_le16(offset);
5656 pSMB->SetupCount = 1;
5657 pSMB->Reserved3 = 0;
5658 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5659 byte_count = 3 /* pad */ + params + count;
5660 pSMB->DataCount = cpu_to_le16(count);
5661 parm_data->list_len = cpu_to_le32(count);
5662 parm_data->list[0].EA_flags = 0;
5663 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005664 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005666 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005667 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 parm_data->list[0].name[name_len] = 0;
5669 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5670 /* caller ensures that ea_value_len is less than 64K but
5671 we need to ensure that it fits within the smb */
5672
Steve French50c2f752007-07-13 00:33:32 +00005673 /*BB add length check to see if it would fit in
5674 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005675 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5676 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005677 memcpy(parm_data->list[0].name+name_len+1,
5678 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679
5680 pSMB->TotalDataCount = pSMB->DataCount;
5681 pSMB->ParameterCount = cpu_to_le16(params);
5682 pSMB->TotalParameterCount = pSMB->ParameterCount;
5683 pSMB->Reserved4 = 0;
5684 pSMB->hdr.smb_buf_length += byte_count;
5685 pSMB->ByteCount = cpu_to_le16(byte_count);
5686 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5687 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005688 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690
5691 cifs_buf_release(pSMB);
5692
5693 if (rc == -EAGAIN)
5694 goto SetEARetry;
5695
5696 return rc;
5697}
5698
5699#endif