blob: 6f4ffe15d68df73f79d822498264bb4958434a3c [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 French790fe572007-07-07 19:25:05 +0000193 if (tcon->ses->status == CifsNeedReconnect)
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 French790fe572007-07-07 19:25:05 +0000196 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
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) {
298 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 French790fe572007-07-07 19:25:05 +0000340 if (tcon->ses->status == CifsNeedReconnect)
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 French790fe572007-07-07 19:25:05 +0000343 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-10-02 05:53:29 +0000566 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000567 } else {
Steve Frenchb815f1e52006-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 Frenchb815f1e52006-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 }
667
668 if (server->socketUseCount.counter > 1) {
669 if (memcmp(server->server_GUID,
670 pSMBr->u.extended_response.
671 GUID, 16) != 0) {
672 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000673 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000674 pSMBr->u.extended_response.GUID,
675 16);
676 }
677 } else
678 memcpy(server->server_GUID,
679 pSMBr->u.extended_response.GUID, 16);
680
681 if (count == 16) {
682 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000683 } else {
684 rc = decode_negTokenInit(pSMBr->u.extended_response.
685 SecurityBlob,
686 count - 16,
687 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000688 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000689 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000690 else
Steve French254e55e2006-06-04 05:53:15 +0000691 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 }
Steve French254e55e2006-06-04 05:53:15 +0000693 } else
694 server->capabilities &= ~CAP_EXTENDED_SECURITY;
695
Steve French6344a422006-06-12 04:18:35 +0000696#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000697signing_check:
Steve French6344a422006-06-12 04:18:35 +0000698#endif
Steve French762e5ab2007-06-28 18:41:42 +0000699 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
700 /* MUST_SIGN already includes the MAY_SIGN FLAG
701 so if this is zero it means that signing is disabled */
702 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000703 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000704 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000705 "packet signing to be enabled in "
706 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000707 rc = -EOPNOTSUPP;
708 }
Steve French50c2f752007-07-13 00:33:32 +0000709 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000710 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000711 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
712 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000713 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000714 if ((server->secMode &
715 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
716 cERROR(1,
717 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000718 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000719 } else
720 server->secMode |= SECMODE_SIGN_REQUIRED;
721 } else {
722 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000723 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000724 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000725 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 }
Steve French50c2f752007-07-13 00:33:32 +0000727
728neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700729 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000730
Steve French790fe572007-07-07 19:25:05 +0000731 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return rc;
733}
734
735int
736CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
737{
738 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 cFYI(1, ("In tree disconnect"));
742 /*
743 * If last user of the connection and
744 * connection alive - disconnect it
745 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000746 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 * to be freed and kernel thread woken up).
748 */
749 if (tcon)
750 down(&tcon->tconSem);
751 else
752 return -EIO;
753
754 atomic_dec(&tcon->useCount);
755 if (atomic_read(&tcon->useCount) > 0) {
756 up(&tcon->tconSem);
757 return -EBUSY;
758 }
759
Steve French50c2f752007-07-13 00:33:32 +0000760 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000762 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000764 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 }
766
Steve French790fe572007-07-07 19:25:05 +0000767 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 up(&tcon->tconSem);
769 return -EIO;
770 }
Steve French50c2f752007-07-13 00:33:32 +0000771 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700772 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (rc) {
774 up(&tcon->tconSem);
775 return rc;
Steve Frenchcd634992005-04-28 22:41:10 -0700776 }
Steve French133672e2007-11-13 22:41:37 +0000777
778 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700780 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 up(&tcon->tconSem);
783
Steve French50c2f752007-07-13 00:33:32 +0000784 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 closed on server already e.g. due to tcp session crashing */
786 if (rc == -EAGAIN)
787 rc = 0;
788
789 return rc;
790}
791
792int
793CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
794{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 LOGOFF_ANDX_REQ *pSMB;
796 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 cFYI(1, ("In SMBLogoff for session disconnect"));
799 if (ses)
800 down(&ses->sesSem);
801 else
802 return -EIO;
803
804 atomic_dec(&ses->inUse);
805 if (atomic_read(&ses->inUse) > 0) {
806 up(&ses->sesSem);
807 return -EBUSY;
808 }
809 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
810 if (rc) {
811 up(&ses->sesSem);
812 return rc;
813 }
814
Steve French790fe572007-07-07 19:25:05 +0000815 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700816 pSMB->hdr.Mid = GetNextMid(ses->server);
817
Steve French790fe572007-07-07 19:25:05 +0000818 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
820 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
821 }
822
823 pSMB->hdr.Uid = ses->Suid;
824
825 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000826 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (ses->server) {
828 atomic_dec(&ses->server->socketUseCount);
829 if (atomic_read(&ses->server->socketUseCount) == 0) {
830 spin_lock(&GlobalMid_Lock);
831 ses->server->tcpStatus = CifsExiting;
832 spin_unlock(&GlobalMid_Lock);
833 rc = -ESHUTDOWN;
834 }
835 }
Steve Frencha59c6582005-08-17 12:12:19 -0700836 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000839 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 error */
841 if (rc == -EAGAIN)
842 rc = 0;
843 return rc;
844}
845
846int
Steve French2d785a52007-07-15 01:48:57 +0000847CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
848 __u16 type, const struct nls_table *nls_codepage, int remap)
849{
850 TRANSACTION2_SPI_REQ *pSMB = NULL;
851 TRANSACTION2_SPI_RSP *pSMBr = NULL;
852 struct unlink_psx_rq *pRqD;
853 int name_len;
854 int rc = 0;
855 int bytes_returned = 0;
856 __u16 params, param_offset, offset, byte_count;
857
858 cFYI(1, ("In POSIX delete"));
859PsxDelete:
860 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
861 (void **) &pSMBr);
862 if (rc)
863 return rc;
864
865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
866 name_len =
867 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
868 PATH_MAX, nls_codepage, remap);
869 name_len++; /* trailing null */
870 name_len *= 2;
871 } else { /* BB add path length overrun check */
872 name_len = strnlen(fileName, PATH_MAX);
873 name_len++; /* trailing null */
874 strncpy(pSMB->FileName, fileName, name_len);
875 }
876
877 params = 6 + name_len;
878 pSMB->MaxParameterCount = cpu_to_le16(2);
879 pSMB->MaxDataCount = 0; /* BB double check this with jra */
880 pSMB->MaxSetupCount = 0;
881 pSMB->Reserved = 0;
882 pSMB->Flags = 0;
883 pSMB->Timeout = 0;
884 pSMB->Reserved2 = 0;
885 param_offset = offsetof(struct smb_com_transaction2_spi_req,
886 InformationLevel) - 4;
887 offset = param_offset + params;
888
889 /* Setup pointer to Request Data (inode type) */
890 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
891 pRqD->type = cpu_to_le16(type);
892 pSMB->ParameterOffset = cpu_to_le16(param_offset);
893 pSMB->DataOffset = cpu_to_le16(offset);
894 pSMB->SetupCount = 1;
895 pSMB->Reserved3 = 0;
896 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
897 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
898
899 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
900 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
901 pSMB->ParameterCount = cpu_to_le16(params);
902 pSMB->TotalParameterCount = pSMB->ParameterCount;
903 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
904 pSMB->Reserved4 = 0;
905 pSMB->hdr.smb_buf_length += byte_count;
906 pSMB->ByteCount = cpu_to_le16(byte_count);
907 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
908 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000909 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000910 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000911 cifs_buf_release(pSMB);
912
913 cifs_stats_inc(&tcon->num_deletes);
914
915 if (rc == -EAGAIN)
916 goto PsxDelete;
917
918 return rc;
919}
920
921int
Steve French737b7582005-04-28 22:41:06 -0700922CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
923 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924{
925 DELETE_FILE_REQ *pSMB = NULL;
926 DELETE_FILE_RSP *pSMBr = NULL;
927 int rc = 0;
928 int bytes_returned;
929 int name_len;
930
931DelFileRetry:
932 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
933 (void **) &pSMBr);
934 if (rc)
935 return rc;
936
937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
938 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000939 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700940 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 name_len++; /* trailing null */
942 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700943 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 name_len = strnlen(fileName, PATH_MAX);
945 name_len++; /* trailing null */
946 strncpy(pSMB->fileName, fileName, name_len);
947 }
948 pSMB->SearchAttributes =
949 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
950 pSMB->BufferFormat = 0x04;
951 pSMB->hdr.smb_buf_length += name_len + 1;
952 pSMB->ByteCount = cpu_to_le16(name_len + 1);
953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700955 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000956 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 cifs_buf_release(pSMB);
960 if (rc == -EAGAIN)
961 goto DelFileRetry;
962
963 return rc;
964}
965
966int
Steve French50c2f752007-07-13 00:33:32 +0000967CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700968 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 DELETE_DIRECTORY_REQ *pSMB = NULL;
971 DELETE_DIRECTORY_RSP *pSMBr = NULL;
972 int rc = 0;
973 int bytes_returned;
974 int name_len;
975
976 cFYI(1, ("In CIFSSMBRmDir"));
977RmDirRetry:
978 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
979 (void **) &pSMBr);
980 if (rc)
981 return rc;
982
983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700984 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
985 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len++; /* trailing null */
987 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700988 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 name_len = strnlen(dirName, PATH_MAX);
990 name_len++; /* trailing null */
991 strncpy(pSMB->DirName, dirName, name_len);
992 }
993
994 pSMB->BufferFormat = 0x04;
995 pSMB->hdr.smb_buf_length += name_len + 1;
996 pSMB->ByteCount = cpu_to_le16(name_len + 1);
997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700999 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001000 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 cifs_buf_release(pSMB);
1004 if (rc == -EAGAIN)
1005 goto RmDirRetry;
1006 return rc;
1007}
1008
1009int
1010CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07001011 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
1013 int rc = 0;
1014 CREATE_DIRECTORY_REQ *pSMB = NULL;
1015 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1016 int bytes_returned;
1017 int name_len;
1018
1019 cFYI(1, ("In CIFSSMBMkDir"));
1020MkDirRetry:
1021 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1022 (void **) &pSMBr);
1023 if (rc)
1024 return rc;
1025
1026 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001027 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001028 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 name_len++; /* trailing null */
1030 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001031 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 name_len = strnlen(name, PATH_MAX);
1033 name_len++; /* trailing null */
1034 strncpy(pSMB->DirName, name, name_len);
1035 }
1036
1037 pSMB->BufferFormat = 0x04;
1038 pSMB->hdr.smb_buf_length += name_len + 1;
1039 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1040 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1041 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001042 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001043 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 cifs_buf_release(pSMB);
1047 if (rc == -EAGAIN)
1048 goto MkDirRetry;
1049 return rc;
1050}
1051
Steve French2dd29d32007-04-23 22:07:35 +00001052int
1053CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001054 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001055 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001056 const struct nls_table *nls_codepage, int remap)
1057{
1058 TRANSACTION2_SPI_REQ *pSMB = NULL;
1059 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1060 int name_len;
1061 int rc = 0;
1062 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001063 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001064 OPEN_PSX_REQ *pdata;
1065 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001066
1067 cFYI(1, ("In POSIX Create"));
1068PsxCreat:
1069 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1070 (void **) &pSMBr);
1071 if (rc)
1072 return rc;
1073
1074 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1075 name_len =
1076 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1077 PATH_MAX, nls_codepage, remap);
1078 name_len++; /* trailing null */
1079 name_len *= 2;
1080 } else { /* BB improve the check for buffer overruns BB */
1081 name_len = strnlen(name, PATH_MAX);
1082 name_len++; /* trailing null */
1083 strncpy(pSMB->FileName, name, name_len);
1084 }
1085
1086 params = 6 + name_len;
1087 count = sizeof(OPEN_PSX_REQ);
1088 pSMB->MaxParameterCount = cpu_to_le16(2);
1089 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1090 pSMB->MaxSetupCount = 0;
1091 pSMB->Reserved = 0;
1092 pSMB->Flags = 0;
1093 pSMB->Timeout = 0;
1094 pSMB->Reserved2 = 0;
1095 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001096 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001097 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001098 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001099 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001100 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001101 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001102 pdata->OpenFlags = cpu_to_le32(*pOplock);
1103 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1104 pSMB->DataOffset = cpu_to_le16(offset);
1105 pSMB->SetupCount = 1;
1106 pSMB->Reserved3 = 0;
1107 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1108 byte_count = 3 /* pad */ + params + count;
1109
1110 pSMB->DataCount = cpu_to_le16(count);
1111 pSMB->ParameterCount = cpu_to_le16(params);
1112 pSMB->TotalDataCount = pSMB->DataCount;
1113 pSMB->TotalParameterCount = pSMB->ParameterCount;
1114 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1115 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001116 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001117 pSMB->ByteCount = cpu_to_le16(byte_count);
1118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1120 if (rc) {
1121 cFYI(1, ("Posix create returned %d", rc));
1122 goto psx_create_err;
1123 }
1124
Steve French790fe572007-07-07 19:25:05 +00001125 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001126 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1127
1128 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1129 rc = -EIO; /* bad smb */
1130 goto psx_create_err;
1131 }
1132
1133 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001134 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001135 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001136
Steve French2dd29d32007-04-23 22:07:35 +00001137 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001138 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001139 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1140 /* Let caller know file was created so we can set the mode. */
1141 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001142 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001143 *pOplock |= CIFS_CREATE_ACTION;
1144 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001145 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1146 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001147 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001148 } else {
Steve French790fe572007-07-07 19:25:05 +00001149 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001150 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001151 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001152 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001153 goto psx_create_err;
1154 }
Steve French50c2f752007-07-13 00:33:32 +00001155 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001156 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001157 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001158 }
Steve French2dd29d32007-04-23 22:07:35 +00001159
1160psx_create_err:
1161 cifs_buf_release(pSMB);
1162
1163 cifs_stats_inc(&tcon->num_mkdirs);
1164
1165 if (rc == -EAGAIN)
1166 goto PsxCreat;
1167
Steve French50c2f752007-07-13 00:33:32 +00001168 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001169}
1170
Steve Frencha9d02ad2005-08-24 23:06:05 -07001171static __u16 convert_disposition(int disposition)
1172{
1173 __u16 ofun = 0;
1174
1175 switch (disposition) {
1176 case FILE_SUPERSEDE:
1177 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1178 break;
1179 case FILE_OPEN:
1180 ofun = SMBOPEN_OAPPEND;
1181 break;
1182 case FILE_CREATE:
1183 ofun = SMBOPEN_OCREATE;
1184 break;
1185 case FILE_OPEN_IF:
1186 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1187 break;
1188 case FILE_OVERWRITE:
1189 ofun = SMBOPEN_OTRUNC;
1190 break;
1191 case FILE_OVERWRITE_IF:
1192 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1193 break;
1194 default:
Steve French790fe572007-07-07 19:25:05 +00001195 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001196 ofun = SMBOPEN_OAPPEND; /* regular open */
1197 }
1198 return ofun;
1199}
1200
Jeff Layton35fc37d2008-05-14 10:22:03 -07001201static int
1202access_flags_to_smbopen_mode(const int access_flags)
1203{
1204 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1205
1206 if (masked_flags == GENERIC_READ)
1207 return SMBOPEN_READ;
1208 else if (masked_flags == GENERIC_WRITE)
1209 return SMBOPEN_WRITE;
1210
1211 /* just go for read/write */
1212 return SMBOPEN_READWRITE;
1213}
1214
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215int
1216SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1217 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001218 const int access_flags, const int create_options, __u16 *netfid,
1219 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 const struct nls_table *nls_codepage, int remap)
1221{
1222 int rc = -EACCES;
1223 OPENX_REQ *pSMB = NULL;
1224 OPENX_RSP *pSMBr = NULL;
1225 int bytes_returned;
1226 int name_len;
1227 __u16 count;
1228
1229OldOpenRetry:
1230 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1231 (void **) &pSMBr);
1232 if (rc)
1233 return rc;
1234
1235 pSMB->AndXCommand = 0xFF; /* none */
1236
1237 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1238 count = 1; /* account for one byte pad to word boundary */
1239 name_len =
1240 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1241 fileName, PATH_MAX, nls_codepage, remap);
1242 name_len++; /* trailing null */
1243 name_len *= 2;
1244 } else { /* BB improve check for buffer overruns BB */
1245 count = 0; /* no pad */
1246 name_len = strnlen(fileName, PATH_MAX);
1247 name_len++; /* trailing null */
1248 strncpy(pSMB->fileName, fileName, name_len);
1249 }
1250 if (*pOplock & REQ_OPLOCK)
1251 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001252 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001254
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001256 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1258 /* set file as system file if special file such
1259 as fifo and server expecting SFU style and
1260 no Unix extensions */
1261
Steve French790fe572007-07-07 19:25:05 +00001262 if (create_options & CREATE_OPTION_SPECIAL)
1263 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001264 else /* BB FIXME BB */
1265 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266
Jeff Layton67750fb2008-05-09 22:28:02 +00001267 if (create_options & CREATE_OPTION_READONLY)
1268 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269
1270 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001271/* pSMB->CreateOptions = cpu_to_le32(create_options &
1272 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001274
1275 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001276 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 count += name_len;
1278 pSMB->hdr.smb_buf_length += count;
1279
1280 pSMB->ByteCount = cpu_to_le16(count);
1281 /* long_op set to 1 to allow for oplock break timeouts */
1282 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001283 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001284 cifs_stats_inc(&tcon->num_opens);
1285 if (rc) {
1286 cFYI(1, ("Error in Open = %d", rc));
1287 } else {
1288 /* BB verify if wct == 15 */
1289
Steve French582d21e2008-05-13 04:54:12 +00001290/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001291
1292 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1293 /* Let caller know file was created so we can set the mode. */
1294 /* Do we care about the CreateAction in any other cases? */
1295 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001296/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001297 *pOplock |= CIFS_CREATE_ACTION; */
1298 /* BB FIXME END */
1299
Steve French790fe572007-07-07 19:25:05 +00001300 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001301 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1302 pfile_info->LastAccessTime = 0; /* BB fixme */
1303 pfile_info->LastWriteTime = 0; /* BB fixme */
1304 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001305 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001306 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001307 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001308 pfile_info->AllocationSize =
1309 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1310 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001311 pfile_info->NumberOfLinks = cpu_to_le32(1);
1312 }
1313 }
1314
1315 cifs_buf_release(pSMB);
1316 if (rc == -EAGAIN)
1317 goto OldOpenRetry;
1318 return rc;
1319}
1320
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321int
1322CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1323 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001324 const int access_flags, const int create_options, __u16 *netfid,
1325 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001326 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327{
1328 int rc = -EACCES;
1329 OPEN_REQ *pSMB = NULL;
1330 OPEN_RSP *pSMBr = NULL;
1331 int bytes_returned;
1332 int name_len;
1333 __u16 count;
1334
1335openRetry:
1336 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1337 (void **) &pSMBr);
1338 if (rc)
1339 return rc;
1340
1341 pSMB->AndXCommand = 0xFF; /* none */
1342
1343 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1344 count = 1; /* account for one byte pad to word boundary */
1345 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001346 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001347 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 name_len++; /* trailing null */
1349 name_len *= 2;
1350 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001351 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 count = 0; /* no pad */
1353 name_len = strnlen(fileName, PATH_MAX);
1354 name_len++; /* trailing null */
1355 pSMB->NameLength = cpu_to_le16(name_len);
1356 strncpy(pSMB->fileName, fileName, name_len);
1357 }
1358 if (*pOplock & REQ_OPLOCK)
1359 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001360 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1363 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001364 /* set file as system file if special file such
1365 as fifo and server expecting SFU style and
1366 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001367 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001368 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1369 else
1370 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 /* XP does not handle ATTR_POSIX_SEMANTICS */
1373 /* but it helps speed up case sensitive checks for other
1374 servers such as Samba */
1375 if (tcon->ses->capabilities & CAP_UNIX)
1376 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1377
Jeff Layton67750fb2008-05-09 22:28:02 +00001378 if (create_options & CREATE_OPTION_READONLY)
1379 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1380
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1382 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001383 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001384 /* BB Expirement with various impersonation levels and verify */
1385 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 pSMB->SecurityFlags =
1387 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1388
1389 count += name_len;
1390 pSMB->hdr.smb_buf_length += count;
1391
1392 pSMB->ByteCount = cpu_to_le16(count);
1393 /* long_op set to 1 to allow for oplock break timeouts */
1394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001395 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001396 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 if (rc) {
1398 cFYI(1, ("Error in Open = %d", rc));
1399 } else {
Steve French09d1db52005-04-28 22:41:08 -07001400 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1402 /* Let caller know file was created so we can set the mode. */
1403 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001404 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001405 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001406 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001407 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 36 /* CreationTime to Attributes */);
1409 /* the file_info buf is endian converted by caller */
1410 pfile_info->AllocationSize = pSMBr->AllocationSize;
1411 pfile_info->EndOfFile = pSMBr->EndOfFile;
1412 pfile_info->NumberOfLinks = cpu_to_le32(1);
1413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 cifs_buf_release(pSMB);
1417 if (rc == -EAGAIN)
1418 goto openRetry;
1419 return rc;
1420}
1421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422int
Steve French50c2f752007-07-13 00:33:32 +00001423CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1424 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1425 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426{
1427 int rc = -EACCES;
1428 READ_REQ *pSMB = NULL;
1429 READ_RSP *pSMBr = NULL;
1430 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001431 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001432 int resp_buf_type = 0;
1433 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Steve French790fe572007-07-07 19:25:05 +00001435 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1436 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001437 wct = 12;
1438 else
1439 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440
1441 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001442 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 if (rc)
1444 return rc;
1445
1446 /* tcon and ses pointer are checked in smb_init */
1447 if (tcon->ses->server == NULL)
1448 return -ECONNABORTED;
1449
Steve Frenchec637e32005-12-12 20:53:18 -08001450 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 pSMB->Fid = netfid;
1452 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001453 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001454 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001455 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001456 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001457
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 pSMB->Remaining = 0;
1459 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1460 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001461 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001462 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1463 else {
1464 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001465 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001466 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001467 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001468 }
Steve Frenchec637e32005-12-12 20:53:18 -08001469
1470 iov[0].iov_base = (char *)pSMB;
1471 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001472 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001473 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001474 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001475 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (rc) {
1477 cERROR(1, ("Send error in read = %d", rc));
1478 } else {
1479 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1480 data_length = data_length << 16;
1481 data_length += le16_to_cpu(pSMBr->DataLength);
1482 *nbytes = data_length;
1483
1484 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001485 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001487 cFYI(1, ("bad length %d for count %d",
1488 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 rc = -EIO;
1490 *nbytes = 0;
1491 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001492 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001493 le16_to_cpu(pSMBr->DataOffset);
1494/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001495 cERROR(1,("Faulting on read rc = %d",rc));
1496 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001497 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001498 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001499 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 }
1501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
Steve French4b8f9302006-02-26 16:41:18 +00001503/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001504 if (*buf) {
1505 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001506 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001507 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001508 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001509 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001510 /* return buffer to caller to free */
1511 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001512 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001513 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001514 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001515 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001516 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001517
1518 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 since file handle passed in no longer valid */
1520 return rc;
1521}
1522
Steve Frenchec637e32005-12-12 20:53:18 -08001523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524int
1525CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1526 const int netfid, const unsigned int count,
1527 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001528 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529{
1530 int rc = -EACCES;
1531 WRITE_REQ *pSMB = NULL;
1532 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001533 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 __u32 bytes_sent;
1535 __u16 byte_count;
1536
1537 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001538 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001539 return -ECONNABORTED;
1540
Steve French790fe572007-07-07 19:25:05 +00001541 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001542 wct = 14;
1543 else
1544 wct = 12;
1545
1546 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 (void **) &pSMBr);
1548 if (rc)
1549 return rc;
1550 /* tcon and ses pointer are checked in smb_init */
1551 if (tcon->ses->server == NULL)
1552 return -ECONNABORTED;
1553
1554 pSMB->AndXCommand = 0xFF; /* none */
1555 pSMB->Fid = netfid;
1556 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001557 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001558 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001559 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001560 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001561
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 pSMB->Reserved = 0xFFFFFFFF;
1563 pSMB->WriteMode = 0;
1564 pSMB->Remaining = 0;
1565
Steve French50c2f752007-07-13 00:33:32 +00001566 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 can send more if LARGE_WRITE_X capability returned by the server and if
1568 our buffer is big enough or if we convert to iovecs on socket writes
1569 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001570 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1572 } else {
1573 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1574 & ~0xFF;
1575 }
1576
1577 if (bytes_sent > count)
1578 bytes_sent = count;
1579 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001580 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001581 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001582 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001583 else if (ubuf) {
1584 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 cifs_buf_release(pSMB);
1586 return -EFAULT;
1587 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001588 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 /* No buffer */
1590 cifs_buf_release(pSMB);
1591 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001592 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001593 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001594 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001595 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001596 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001597
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1599 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001600 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001601
Steve French790fe572007-07-07 19:25:05 +00001602 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001603 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001604 else { /* old style write has byte count 4 bytes earlier
1605 so 4 bytes pad */
1606 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001607 (struct smb_com_writex_req *)pSMB;
1608 pSMBW->ByteCount = cpu_to_le16(byte_count);
1609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
1611 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1612 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001613 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 if (rc) {
1615 cFYI(1, ("Send error in write = %d", rc));
1616 *nbytes = 0;
1617 } else {
1618 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1619 *nbytes = (*nbytes) << 16;
1620 *nbytes += le16_to_cpu(pSMBr->Count);
1621 }
1622
1623 cifs_buf_release(pSMB);
1624
Steve French50c2f752007-07-13 00:33:32 +00001625 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 since file handle passed in no longer valid */
1627
1628 return rc;
1629}
1630
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001631int
1632CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001634 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1635 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636{
1637 int rc = -EACCES;
1638 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001639 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001640 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001641 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Steve French790fe572007-07-07 19:25:05 +00001643 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001644
Steve French790fe572007-07-07 19:25:05 +00001645 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001646 wct = 14;
1647 else
1648 wct = 12;
1649 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 if (rc)
1651 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 /* tcon and ses pointer are checked in smb_init */
1653 if (tcon->ses->server == NULL)
1654 return -ECONNABORTED;
1655
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001656 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 pSMB->Fid = netfid;
1658 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001659 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001660 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001661 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001662 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 pSMB->Reserved = 0xFFFFFFFF;
1664 pSMB->WriteMode = 0;
1665 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001666
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001668 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Steve French3e844692005-10-03 13:37:24 -07001670 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1671 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001672 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001673 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001674 pSMB->hdr.smb_buf_length += count+1;
1675 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001676 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1677 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001678 pSMB->ByteCount = cpu_to_le16(count + 1);
1679 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001680 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001681 (struct smb_com_writex_req *)pSMB;
1682 pSMBW->ByteCount = cpu_to_le16(count + 5);
1683 }
Steve French3e844692005-10-03 13:37:24 -07001684 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001685 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001686 iov[0].iov_len = smb_hdr_len + 4;
1687 else /* wct == 12 pad bigger by four bytes */
1688 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001689
Steve French3e844692005-10-03 13:37:24 -07001690
Steve Frenchec637e32005-12-12 20:53:18 -08001691 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001692 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001693 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001695 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001697 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001698 /* presumably this can not happen, but best to be safe */
1699 rc = -EIO;
1700 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001701 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001702 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001703 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1704 *nbytes = (*nbytes) << 16;
1705 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
Steve French4b8f9302006-02-26 16:41:18 +00001708/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001709 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001710 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001711 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001712 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
Steve French50c2f752007-07-13 00:33:32 +00001714 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 since file handle passed in no longer valid */
1716
1717 return rc;
1718}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001719
1720
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721int
1722CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1723 const __u16 smb_file_id, const __u64 len,
1724 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001725 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726{
1727 int rc = 0;
1728 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001729/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 int bytes_returned;
1731 int timeout = 0;
1732 __u16 count;
1733
Steve French4b18f2a2008-04-29 00:06:05 +00001734 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001735 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 if (rc)
1738 return rc;
1739
Steve French790fe572007-07-07 19:25:05 +00001740 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001741 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001743 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001744 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1746 } else {
1747 pSMB->Timeout = 0;
1748 }
1749
1750 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1751 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1752 pSMB->LockType = lockType;
1753 pSMB->AndXCommand = 0xFF; /* none */
1754 pSMB->Fid = smb_file_id; /* netfid stays le */
1755
Steve French790fe572007-07-07 19:25:05 +00001756 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1758 /* BB where to store pid high? */
1759 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1760 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1761 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1762 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1763 count = sizeof(LOCKING_ANDX_RANGE);
1764 } else {
1765 /* oplock break */
1766 count = 0;
1767 }
1768 pSMB->hdr.smb_buf_length += count;
1769 pSMB->ByteCount = cpu_to_le16(count);
1770
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001771 if (waitFlag) {
1772 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001773 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001774 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001775 } else {
Steve French133672e2007-11-13 22:41:37 +00001776 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1777 timeout);
1778 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001779 }
Steve Frencha4544342005-08-24 13:59:35 -07001780 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001781 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
Steve French50c2f752007-07-13 00:33:32 +00001784 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 since file handle passed in no longer valid */
1786 return rc;
1787}
1788
1789int
Steve French08547b02006-02-28 22:39:25 +00001790CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1791 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001792 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001793 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001794{
1795 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1796 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001797 struct cifs_posix_lock *parm_data;
1798 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001799 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001800 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001801 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001802 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001803 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001804
1805 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001806
Steve French790fe572007-07-07 19:25:05 +00001807 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001808 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001809
Steve French08547b02006-02-28 22:39:25 +00001810 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1811
1812 if (rc)
1813 return rc;
1814
1815 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1816
Steve French50c2f752007-07-13 00:33:32 +00001817 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001818 pSMB->MaxSetupCount = 0;
1819 pSMB->Reserved = 0;
1820 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001821 pSMB->Reserved2 = 0;
1822 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1823 offset = param_offset + params;
1824
Steve French08547b02006-02-28 22:39:25 +00001825 count = sizeof(struct cifs_posix_lock);
1826 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001827 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001828 pSMB->SetupCount = 1;
1829 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001830 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001831 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1832 else
1833 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1834 byte_count = 3 /* pad */ + params + count;
1835 pSMB->DataCount = cpu_to_le16(count);
1836 pSMB->ParameterCount = cpu_to_le16(params);
1837 pSMB->TotalDataCount = pSMB->DataCount;
1838 pSMB->TotalParameterCount = pSMB->ParameterCount;
1839 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001840 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001841 (((char *) &pSMB->hdr.Protocol) + offset);
1842
1843 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001844 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001845 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001846 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001847 pSMB->Timeout = cpu_to_le32(-1);
1848 } else
1849 pSMB->Timeout = 0;
1850
Steve French08547b02006-02-28 22:39:25 +00001851 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001852 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001853 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001854
1855 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001856 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001857 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1858 pSMB->Reserved4 = 0;
1859 pSMB->hdr.smb_buf_length += byte_count;
1860 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001861 if (waitFlag) {
1862 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1863 (struct smb_hdr *) pSMBr, &bytes_returned);
1864 } else {
Steve French133672e2007-11-13 22:41:37 +00001865 iov[0].iov_base = (char *)pSMB;
1866 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1867 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1868 &resp_buf_type, timeout);
1869 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1870 not try to free it twice below on exit */
1871 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001872 }
1873
Steve French08547b02006-02-28 22:39:25 +00001874 if (rc) {
1875 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001876 } else if (get_flag) {
1877 /* lock structure can be returned on get */
1878 __u16 data_offset;
1879 __u16 data_count;
1880 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001881
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001882 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1883 rc = -EIO; /* bad smb */
1884 goto plk_err_exit;
1885 }
Steve French790fe572007-07-07 19:25:05 +00001886 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001887 rc = -EINVAL;
1888 goto plk_err_exit;
1889 }
1890 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1891 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001892 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001893 rc = -EIO;
1894 goto plk_err_exit;
1895 }
1896 parm_data = (struct cifs_posix_lock *)
1897 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001898 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001899 pLockData->fl_type = F_UNLCK;
1900 }
Steve French50c2f752007-07-13 00:33:32 +00001901
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001902plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001903 if (pSMB)
1904 cifs_small_buf_release(pSMB);
1905
Steve French133672e2007-11-13 22:41:37 +00001906 if (resp_buf_type == CIFS_SMALL_BUFFER)
1907 cifs_small_buf_release(iov[0].iov_base);
1908 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1909 cifs_buf_release(iov[0].iov_base);
1910
Steve French08547b02006-02-28 22:39:25 +00001911 /* Note: On -EAGAIN error only caller can retry on handle based calls
1912 since file handle passed in no longer valid */
1913
1914 return rc;
1915}
1916
1917
1918int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1920{
1921 int rc = 0;
1922 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 cFYI(1, ("In CIFSSMBClose"));
1924
1925/* do not retry on dead session on close */
1926 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001927 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 return 0;
1929 if (rc)
1930 return rc;
1931
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001933 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001935 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001936 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001938 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 /* EINTR is expected when user ctl-c to kill app */
1940 cERROR(1, ("Send error in Close = %d", rc));
1941 }
1942 }
1943
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001945 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 rc = 0;
1947
1948 return rc;
1949}
1950
1951int
1952CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1953 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001954 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955{
1956 int rc = 0;
1957 RENAME_REQ *pSMB = NULL;
1958 RENAME_RSP *pSMBr = NULL;
1959 int bytes_returned;
1960 int name_len, name_len2;
1961 __u16 count;
1962
1963 cFYI(1, ("In CIFSSMBRename"));
1964renameRetry:
1965 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1966 (void **) &pSMBr);
1967 if (rc)
1968 return rc;
1969
1970 pSMB->BufferFormat = 0x04;
1971 pSMB->SearchAttributes =
1972 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1973 ATTR_DIRECTORY);
1974
1975 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1976 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001977 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001978 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 name_len++; /* trailing null */
1980 name_len *= 2;
1981 pSMB->OldFileName[name_len] = 0x04; /* pad */
1982 /* protocol requires ASCII signature byte on Unicode string */
1983 pSMB->OldFileName[name_len + 1] = 0x00;
1984 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001985 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001986 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1988 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001989 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 name_len = strnlen(fromName, PATH_MAX);
1991 name_len++; /* trailing null */
1992 strncpy(pSMB->OldFileName, fromName, name_len);
1993 name_len2 = strnlen(toName, PATH_MAX);
1994 name_len2++; /* trailing null */
1995 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1996 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1997 name_len2++; /* trailing null */
1998 name_len2++; /* signature byte */
1999 }
2000
2001 count = 1 /* 1st signature byte */ + name_len + name_len2;
2002 pSMB->hdr.smb_buf_length += count;
2003 pSMB->ByteCount = cpu_to_le16(count);
2004
2005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002007 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002008 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 cifs_buf_release(pSMB);
2012
2013 if (rc == -EAGAIN)
2014 goto renameRetry;
2015
2016 return rc;
2017}
2018
Steve French50c2f752007-07-13 00:33:32 +00002019int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002020 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002021 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022{
2023 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2024 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002025 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 char *data_offset;
2027 char dummy_string[30];
2028 int rc = 0;
2029 int bytes_returned = 0;
2030 int len_of_str;
2031 __u16 params, param_offset, offset, count, byte_count;
2032
2033 cFYI(1, ("Rename to File by handle"));
2034 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2035 (void **) &pSMBr);
2036 if (rc)
2037 return rc;
2038
2039 params = 6;
2040 pSMB->MaxSetupCount = 0;
2041 pSMB->Reserved = 0;
2042 pSMB->Flags = 0;
2043 pSMB->Timeout = 0;
2044 pSMB->Reserved2 = 0;
2045 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2046 offset = param_offset + params;
2047
2048 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2049 rename_info = (struct set_file_rename *) data_offset;
2050 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002051 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 pSMB->SetupCount = 1;
2053 pSMB->Reserved3 = 0;
2054 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2055 byte_count = 3 /* pad */ + params;
2056 pSMB->ParameterCount = cpu_to_le16(params);
2057 pSMB->TotalParameterCount = pSMB->ParameterCount;
2058 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2059 pSMB->DataOffset = cpu_to_le16(offset);
2060 /* construct random name ".cifs_tmp<inodenum><mid>" */
2061 rename_info->overwrite = cpu_to_le32(1);
2062 rename_info->root_fid = 0;
2063 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002064 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002065 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2066 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002067 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002069 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002070 target_name, PATH_MAX, nls_codepage,
2071 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 }
2073 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002074 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 byte_count += count;
2076 pSMB->DataCount = cpu_to_le16(count);
2077 pSMB->TotalDataCount = pSMB->DataCount;
2078 pSMB->Fid = netfid;
2079 pSMB->InformationLevel =
2080 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2081 pSMB->Reserved4 = 0;
2082 pSMB->hdr.smb_buf_length += byte_count;
2083 pSMB->ByteCount = cpu_to_le16(byte_count);
2084 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002086 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002087 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002088 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002089
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 cifs_buf_release(pSMB);
2091
2092 /* Note: On -EAGAIN error only caller can retry on handle based calls
2093 since file handle passed in no longer valid */
2094
2095 return rc;
2096}
2097
2098int
Steve French50c2f752007-07-13 00:33:32 +00002099CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2100 const __u16 target_tid, const char *toName, const int flags,
2101 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102{
2103 int rc = 0;
2104 COPY_REQ *pSMB = NULL;
2105 COPY_RSP *pSMBr = NULL;
2106 int bytes_returned;
2107 int name_len, name_len2;
2108 __u16 count;
2109
2110 cFYI(1, ("In CIFSSMBCopy"));
2111copyRetry:
2112 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2113 (void **) &pSMBr);
2114 if (rc)
2115 return rc;
2116
2117 pSMB->BufferFormat = 0x04;
2118 pSMB->Tid2 = target_tid;
2119
2120 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2121
2122 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002123 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002124 fromName, PATH_MAX, nls_codepage,
2125 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 name_len++; /* trailing null */
2127 name_len *= 2;
2128 pSMB->OldFileName[name_len] = 0x04; /* pad */
2129 /* protocol requires ASCII signature byte on Unicode string */
2130 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002131 name_len2 =
2132 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002133 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2135 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002136 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 name_len = strnlen(fromName, PATH_MAX);
2138 name_len++; /* trailing null */
2139 strncpy(pSMB->OldFileName, fromName, name_len);
2140 name_len2 = strnlen(toName, PATH_MAX);
2141 name_len2++; /* trailing null */
2142 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2143 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2144 name_len2++; /* trailing null */
2145 name_len2++; /* signature byte */
2146 }
2147
2148 count = 1 /* 1st signature byte */ + name_len + name_len2;
2149 pSMB->hdr.smb_buf_length += count;
2150 pSMB->ByteCount = cpu_to_le16(count);
2151
2152 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2153 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2154 if (rc) {
2155 cFYI(1, ("Send error in copy = %d with %d files copied",
2156 rc, le16_to_cpu(pSMBr->CopyCount)));
2157 }
Steve French0d817bc2008-05-22 02:02:03 +00002158 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
2160 if (rc == -EAGAIN)
2161 goto copyRetry;
2162
2163 return rc;
2164}
2165
2166int
2167CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2168 const char *fromName, const char *toName,
2169 const struct nls_table *nls_codepage)
2170{
2171 TRANSACTION2_SPI_REQ *pSMB = NULL;
2172 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2173 char *data_offset;
2174 int name_len;
2175 int name_len_target;
2176 int rc = 0;
2177 int bytes_returned = 0;
2178 __u16 params, param_offset, offset, byte_count;
2179
2180 cFYI(1, ("In Symlink Unix style"));
2181createSymLinkRetry:
2182 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2183 (void **) &pSMBr);
2184 if (rc)
2185 return rc;
2186
2187 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2188 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002189 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 /* find define for this maxpathcomponent */
2191 , nls_codepage);
2192 name_len++; /* trailing null */
2193 name_len *= 2;
2194
Steve French50c2f752007-07-13 00:33:32 +00002195 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 name_len = strnlen(fromName, PATH_MAX);
2197 name_len++; /* trailing null */
2198 strncpy(pSMB->FileName, fromName, name_len);
2199 }
2200 params = 6 + name_len;
2201 pSMB->MaxSetupCount = 0;
2202 pSMB->Reserved = 0;
2203 pSMB->Flags = 0;
2204 pSMB->Timeout = 0;
2205 pSMB->Reserved2 = 0;
2206 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002207 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 offset = param_offset + params;
2209
2210 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2211 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2212 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002213 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 /* find define for this maxpathcomponent */
2215 , nls_codepage);
2216 name_len_target++; /* trailing null */
2217 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002218 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 name_len_target = strnlen(toName, PATH_MAX);
2220 name_len_target++; /* trailing null */
2221 strncpy(data_offset, toName, name_len_target);
2222 }
2223
2224 pSMB->MaxParameterCount = cpu_to_le16(2);
2225 /* BB find exact max on data count below from sess */
2226 pSMB->MaxDataCount = cpu_to_le16(1000);
2227 pSMB->SetupCount = 1;
2228 pSMB->Reserved3 = 0;
2229 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2230 byte_count = 3 /* pad */ + params + name_len_target;
2231 pSMB->DataCount = cpu_to_le16(name_len_target);
2232 pSMB->ParameterCount = cpu_to_le16(params);
2233 pSMB->TotalDataCount = pSMB->DataCount;
2234 pSMB->TotalParameterCount = pSMB->ParameterCount;
2235 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2236 pSMB->DataOffset = cpu_to_le16(offset);
2237 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2238 pSMB->Reserved4 = 0;
2239 pSMB->hdr.smb_buf_length += byte_count;
2240 pSMB->ByteCount = cpu_to_le16(byte_count);
2241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2242 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002243 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002244 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002245 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Steve French0d817bc2008-05-22 02:02:03 +00002247 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
2249 if (rc == -EAGAIN)
2250 goto createSymLinkRetry;
2251
2252 return rc;
2253}
2254
2255int
2256CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2257 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002258 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259{
2260 TRANSACTION2_SPI_REQ *pSMB = NULL;
2261 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2262 char *data_offset;
2263 int name_len;
2264 int name_len_target;
2265 int rc = 0;
2266 int bytes_returned = 0;
2267 __u16 params, param_offset, offset, byte_count;
2268
2269 cFYI(1, ("In Create Hard link Unix style"));
2270createHardLinkRetry:
2271 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2272 (void **) &pSMBr);
2273 if (rc)
2274 return rc;
2275
2276 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002277 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002278 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 name_len++; /* trailing null */
2280 name_len *= 2;
2281
Steve French50c2f752007-07-13 00:33:32 +00002282 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 name_len = strnlen(toName, PATH_MAX);
2284 name_len++; /* trailing null */
2285 strncpy(pSMB->FileName, toName, name_len);
2286 }
2287 params = 6 + name_len;
2288 pSMB->MaxSetupCount = 0;
2289 pSMB->Reserved = 0;
2290 pSMB->Flags = 0;
2291 pSMB->Timeout = 0;
2292 pSMB->Reserved2 = 0;
2293 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002294 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 offset = param_offset + params;
2296
2297 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2299 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002300 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002301 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 name_len_target++; /* trailing null */
2303 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002304 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 name_len_target = strnlen(fromName, PATH_MAX);
2306 name_len_target++; /* trailing null */
2307 strncpy(data_offset, fromName, name_len_target);
2308 }
2309
2310 pSMB->MaxParameterCount = cpu_to_le16(2);
2311 /* BB find exact max on data count below from sess*/
2312 pSMB->MaxDataCount = cpu_to_le16(1000);
2313 pSMB->SetupCount = 1;
2314 pSMB->Reserved3 = 0;
2315 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2316 byte_count = 3 /* pad */ + params + name_len_target;
2317 pSMB->ParameterCount = cpu_to_le16(params);
2318 pSMB->TotalParameterCount = pSMB->ParameterCount;
2319 pSMB->DataCount = cpu_to_le16(name_len_target);
2320 pSMB->TotalDataCount = pSMB->DataCount;
2321 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2322 pSMB->DataOffset = cpu_to_le16(offset);
2323 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2324 pSMB->Reserved4 = 0;
2325 pSMB->hdr.smb_buf_length += byte_count;
2326 pSMB->ByteCount = cpu_to_le16(byte_count);
2327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002329 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002330 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332
2333 cifs_buf_release(pSMB);
2334 if (rc == -EAGAIN)
2335 goto createHardLinkRetry;
2336
2337 return rc;
2338}
2339
2340int
2341CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2342 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002343 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344{
2345 int rc = 0;
2346 NT_RENAME_REQ *pSMB = NULL;
2347 RENAME_RSP *pSMBr = NULL;
2348 int bytes_returned;
2349 int name_len, name_len2;
2350 __u16 count;
2351
2352 cFYI(1, ("In CIFSCreateHardLink"));
2353winCreateHardLinkRetry:
2354
2355 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2356 (void **) &pSMBr);
2357 if (rc)
2358 return rc;
2359
2360 pSMB->SearchAttributes =
2361 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2362 ATTR_DIRECTORY);
2363 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2364 pSMB->ClusterCount = 0;
2365
2366 pSMB->BufferFormat = 0x04;
2367
2368 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2369 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002370 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002371 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 name_len++; /* trailing null */
2373 name_len *= 2;
2374 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002375 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002377 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002378 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2380 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002381 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 name_len = strnlen(fromName, PATH_MAX);
2383 name_len++; /* trailing null */
2384 strncpy(pSMB->OldFileName, fromName, name_len);
2385 name_len2 = strnlen(toName, PATH_MAX);
2386 name_len2++; /* trailing null */
2387 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2388 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2389 name_len2++; /* trailing null */
2390 name_len2++; /* signature byte */
2391 }
2392
2393 count = 1 /* string type byte */ + name_len + name_len2;
2394 pSMB->hdr.smb_buf_length += count;
2395 pSMB->ByteCount = cpu_to_le16(count);
2396
2397 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2398 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002399 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002400 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002402
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 cifs_buf_release(pSMB);
2404 if (rc == -EAGAIN)
2405 goto winCreateHardLinkRetry;
2406
2407 return rc;
2408}
2409
2410int
2411CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2412 const unsigned char *searchName,
2413 char *symlinkinfo, const int buflen,
2414 const struct nls_table *nls_codepage)
2415{
2416/* SMB_QUERY_FILE_UNIX_LINK */
2417 TRANSACTION2_QPI_REQ *pSMB = NULL;
2418 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2419 int rc = 0;
2420 int bytes_returned;
2421 int name_len;
2422 __u16 params, byte_count;
2423
2424 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2425
2426querySymLinkRetry:
2427 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2428 (void **) &pSMBr);
2429 if (rc)
2430 return rc;
2431
2432 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2433 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002434 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2435 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 name_len++; /* trailing null */
2437 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002438 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 name_len = strnlen(searchName, PATH_MAX);
2440 name_len++; /* trailing null */
2441 strncpy(pSMB->FileName, searchName, name_len);
2442 }
2443
2444 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2445 pSMB->TotalDataCount = 0;
2446 pSMB->MaxParameterCount = cpu_to_le16(2);
2447 /* BB find exact max data count below from sess structure BB */
2448 pSMB->MaxDataCount = cpu_to_le16(4000);
2449 pSMB->MaxSetupCount = 0;
2450 pSMB->Reserved = 0;
2451 pSMB->Flags = 0;
2452 pSMB->Timeout = 0;
2453 pSMB->Reserved2 = 0;
2454 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002455 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 pSMB->DataCount = 0;
2457 pSMB->DataOffset = 0;
2458 pSMB->SetupCount = 1;
2459 pSMB->Reserved3 = 0;
2460 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2461 byte_count = params + 1 /* pad */ ;
2462 pSMB->TotalParameterCount = cpu_to_le16(params);
2463 pSMB->ParameterCount = pSMB->TotalParameterCount;
2464 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2465 pSMB->Reserved4 = 0;
2466 pSMB->hdr.smb_buf_length += byte_count;
2467 pSMB->ByteCount = cpu_to_le16(byte_count);
2468
2469 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2470 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2471 if (rc) {
2472 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2473 } else {
2474 /* decode response */
2475
2476 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2477 if (rc || (pSMBr->ByteCount < 2))
2478 /* BB also check enough total bytes returned */
2479 rc = -EIO; /* bad smb */
2480 else {
2481 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2482 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2483
2484 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2485 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002486 &pSMBr->hdr.Protocol + data_offset),
2487 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002488 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002490 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2491 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 name_len, nls_codepage);
2493 } else {
2494 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002495 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 data_offset,
2497 min_t(const int, buflen, count));
2498 }
2499 symlinkinfo[buflen] = 0;
2500 /* just in case so calling code does not go off the end of buffer */
2501 }
2502 }
2503 cifs_buf_release(pSMB);
2504 if (rc == -EAGAIN)
2505 goto querySymLinkRetry;
2506 return rc;
2507}
2508
Parag Warudkarc9489772007-10-23 18:09:48 +00002509#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002510/* Initialize NT TRANSACT SMB into small smb request buffer.
2511 This assumes that all NT TRANSACTS that we init here have
2512 total parm and data under about 400 bytes (to fit in small cifs
2513 buffer size), which is the case so far, it easily fits. NB:
2514 Setup words themselves and ByteCount
2515 MaxSetupCount (size of returned setup area) and
2516 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002517static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002518smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002519 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002520 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002521{
2522 int rc;
2523 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002524 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002525
2526 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2527 (void **)&pSMB);
2528 if (rc)
2529 return rc;
2530 *ret_buf = (void *)pSMB;
2531 pSMB->Reserved = 0;
2532 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2533 pSMB->TotalDataCount = 0;
2534 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2535 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2536 pSMB->ParameterCount = pSMB->TotalParameterCount;
2537 pSMB->DataCount = pSMB->TotalDataCount;
2538 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2539 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2540 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2541 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2542 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2543 pSMB->SubCommand = cpu_to_le16(sub_command);
2544 return 0;
2545}
2546
2547static int
Steve French50c2f752007-07-13 00:33:32 +00002548validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002549 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002550{
Steve French50c2f752007-07-13 00:33:32 +00002551 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002552 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002553 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002554
Steve French630f3f0c2007-10-25 21:17:17 +00002555 *pdatalen = 0;
2556 *pparmlen = 0;
2557
Steve French790fe572007-07-07 19:25:05 +00002558 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002559 return -EINVAL;
2560
2561 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2562
2563 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002564 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002565 (char *)&pSMBr->ByteCount;
2566
Steve French0a4b92c2006-01-12 15:44:21 -08002567 data_offset = le32_to_cpu(pSMBr->DataOffset);
2568 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002569 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002570 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2571
2572 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2573 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2574
2575 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002576 if (*ppparm > end_of_smb) {
2577 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002578 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002579 } else if (parm_count + *ppparm > end_of_smb) {
2580 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002581 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002582 } else if (*ppdata > end_of_smb) {
2583 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002584 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002585 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002586 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002587 *ppdata, data_count, (data_count + *ppdata),
2588 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002589 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002590 } else if (parm_count + data_count > pSMBr->ByteCount) {
2591 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002592 return -EINVAL;
2593 }
Steve French630f3f0c2007-10-25 21:17:17 +00002594 *pdatalen = data_count;
2595 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002596 return 0;
2597}
Parag Warudkarc9489772007-10-23 18:09:48 +00002598#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002599
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600int
2601CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2602 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002603 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 const struct nls_table *nls_codepage)
2605{
2606 int rc = 0;
2607 int bytes_returned;
2608 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002609 struct smb_com_transaction_ioctl_req *pSMB;
2610 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
2612 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2613 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2614 (void **) &pSMBr);
2615 if (rc)
2616 return rc;
2617
2618 pSMB->TotalParameterCount = 0 ;
2619 pSMB->TotalDataCount = 0;
2620 pSMB->MaxParameterCount = cpu_to_le32(2);
2621 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002622 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2623 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 pSMB->MaxSetupCount = 4;
2625 pSMB->Reserved = 0;
2626 pSMB->ParameterOffset = 0;
2627 pSMB->DataCount = 0;
2628 pSMB->DataOffset = 0;
2629 pSMB->SetupCount = 4;
2630 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2631 pSMB->ParameterCount = pSMB->TotalParameterCount;
2632 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2633 pSMB->IsFsctl = 1; /* FSCTL */
2634 pSMB->IsRootFlag = 0;
2635 pSMB->Fid = fid; /* file handle always le */
2636 pSMB->ByteCount = 0;
2637
2638 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2639 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2640 if (rc) {
2641 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2642 } else { /* decode response */
2643 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2644 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2645 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2646 /* BB also check enough total bytes returned */
2647 rc = -EIO; /* bad smb */
2648 else {
Steve French790fe572007-07-07 19:25:05 +00002649 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002650 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002651 pSMBr->ByteCount +
2652 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
Steve French50c2f752007-07-13 00:33:32 +00002654 struct reparse_data *reparse_buf =
2655 (struct reparse_data *)
2656 ((char *)&pSMBr->hdr.Protocol
2657 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002658 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 rc = -EIO;
2660 goto qreparse_out;
2661 }
Steve French790fe572007-07-07 19:25:05 +00002662 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 reparse_buf->TargetNameOffset +
2664 reparse_buf->TargetNameLen) >
2665 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002666 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 rc = -EIO;
2668 goto qreparse_out;
2669 }
Steve French50c2f752007-07-13 00:33:32 +00002670
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2672 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002673 (reparse_buf->LinkNamesBuf +
2674 reparse_buf->TargetNameOffset),
2675 min(buflen/2,
2676 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002678 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 reparse_buf->TargetNameOffset),
2680 name_len, nls_codepage);
2681 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002682 strncpy(symlinkinfo,
2683 reparse_buf->LinkNamesBuf +
2684 reparse_buf->TargetNameOffset,
2685 min_t(const int, buflen,
2686 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 }
2688 } else {
2689 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002690 cFYI(1, ("Invalid return data count on "
2691 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 }
2693 symlinkinfo[buflen] = 0; /* just in case so the caller
2694 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002695 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 }
2697 }
2698qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002699 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
2701 /* Note: On -EAGAIN error only caller can retry on handle based calls
2702 since file handle passed in no longer valid */
2703
2704 return rc;
2705}
2706
2707#ifdef CONFIG_CIFS_POSIX
2708
2709/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002710static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2711 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712{
2713 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002714 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2715 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2716 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2718
2719 return;
2720}
2721
2722/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002723static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2724 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725{
2726 int size = 0;
2727 int i;
2728 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002729 struct cifs_posix_ace *pACE;
2730 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2731 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732
2733 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2734 return -EOPNOTSUPP;
2735
Steve French790fe572007-07-07 19:25:05 +00002736 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 count = le16_to_cpu(cifs_acl->access_entry_count);
2738 pACE = &cifs_acl->ace_array[0];
2739 size = sizeof(struct cifs_posix_acl);
2740 size += sizeof(struct cifs_posix_ace) * count;
2741 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002742 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002743 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2744 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 return -EINVAL;
2746 }
Steve French790fe572007-07-07 19:25:05 +00002747 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 count = le16_to_cpu(cifs_acl->access_entry_count);
2749 size = sizeof(struct cifs_posix_acl);
2750 size += sizeof(struct cifs_posix_ace) * count;
2751/* skip past access ACEs to get to default ACEs */
2752 pACE = &cifs_acl->ace_array[count];
2753 count = le16_to_cpu(cifs_acl->default_entry_count);
2754 size += sizeof(struct cifs_posix_ace) * count;
2755 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002756 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return -EINVAL;
2758 } else {
2759 /* illegal type */
2760 return -EINVAL;
2761 }
2762
2763 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002764 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002765 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002766 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 return -ERANGE;
2768 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002769 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002770 for (i = 0; i < count ; i++) {
2771 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2772 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 }
2774 }
2775 return size;
2776}
2777
Steve French50c2f752007-07-13 00:33:32 +00002778static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2779 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780{
2781 __u16 rc = 0; /* 0 = ACL converted ok */
2782
Steve Frenchff7feac2005-11-15 16:45:16 -08002783 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2784 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002786 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 /* Probably no need to le convert -1 on any arch but can not hurt */
2788 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002789 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002790 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002791 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 return rc;
2793}
2794
2795/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002796static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2797 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798{
2799 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002800 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2801 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 int count;
2803 int i;
2804
Steve French790fe572007-07-07 19:25:05 +00002805 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 return 0;
2807
2808 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002809 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002810 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002811 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002812 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002813 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002814 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 return 0;
2816 }
2817 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002818 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002819 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002820 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002821 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 else {
Steve French50c2f752007-07-13 00:33:32 +00002823 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 return 0;
2825 }
Steve French50c2f752007-07-13 00:33:32 +00002826 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2828 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002829 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 /* ACE not converted */
2831 break;
2832 }
2833 }
Steve French790fe572007-07-07 19:25:05 +00002834 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2836 rc += sizeof(struct cifs_posix_acl);
2837 /* BB add check to make sure ACL does not overflow SMB */
2838 }
2839 return rc;
2840}
2841
2842int
2843CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002844 const unsigned char *searchName,
2845 char *acl_inf, const int buflen, const int acl_type,
2846 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847{
2848/* SMB_QUERY_POSIX_ACL */
2849 TRANSACTION2_QPI_REQ *pSMB = NULL;
2850 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2851 int rc = 0;
2852 int bytes_returned;
2853 int name_len;
2854 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002855
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2857
2858queryAclRetry:
2859 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2860 (void **) &pSMBr);
2861 if (rc)
2862 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002863
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2865 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002866 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002867 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 name_len++; /* trailing null */
2869 name_len *= 2;
2870 pSMB->FileName[name_len] = 0;
2871 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002872 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 name_len = strnlen(searchName, PATH_MAX);
2874 name_len++; /* trailing null */
2875 strncpy(pSMB->FileName, searchName, name_len);
2876 }
2877
2878 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2879 pSMB->TotalDataCount = 0;
2880 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002881 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 pSMB->MaxDataCount = cpu_to_le16(4000);
2883 pSMB->MaxSetupCount = 0;
2884 pSMB->Reserved = 0;
2885 pSMB->Flags = 0;
2886 pSMB->Timeout = 0;
2887 pSMB->Reserved2 = 0;
2888 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002889 offsetof(struct smb_com_transaction2_qpi_req,
2890 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 pSMB->DataCount = 0;
2892 pSMB->DataOffset = 0;
2893 pSMB->SetupCount = 1;
2894 pSMB->Reserved3 = 0;
2895 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2896 byte_count = params + 1 /* pad */ ;
2897 pSMB->TotalParameterCount = cpu_to_le16(params);
2898 pSMB->ParameterCount = pSMB->TotalParameterCount;
2899 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2900 pSMB->Reserved4 = 0;
2901 pSMB->hdr.smb_buf_length += byte_count;
2902 pSMB->ByteCount = cpu_to_le16(byte_count);
2903
2904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002906 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 if (rc) {
2908 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2909 } else {
2910 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002911
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2913 if (rc || (pSMBr->ByteCount < 2))
2914 /* BB also check enough total bytes returned */
2915 rc = -EIO; /* bad smb */
2916 else {
2917 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2918 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2919 rc = cifs_copy_posix_acl(acl_inf,
2920 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002921 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 }
2923 }
2924 cifs_buf_release(pSMB);
2925 if (rc == -EAGAIN)
2926 goto queryAclRetry;
2927 return rc;
2928}
2929
2930int
2931CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002932 const unsigned char *fileName,
2933 const char *local_acl, const int buflen,
2934 const int acl_type,
2935 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936{
2937 struct smb_com_transaction2_spi_req *pSMB = NULL;
2938 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2939 char *parm_data;
2940 int name_len;
2941 int rc = 0;
2942 int bytes_returned = 0;
2943 __u16 params, byte_count, data_count, param_offset, offset;
2944
2945 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2946setAclRetry:
2947 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002948 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 if (rc)
2950 return rc;
2951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2952 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002953 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002954 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 name_len++; /* trailing null */
2956 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002957 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 name_len = strnlen(fileName, PATH_MAX);
2959 name_len++; /* trailing null */
2960 strncpy(pSMB->FileName, fileName, name_len);
2961 }
2962 params = 6 + name_len;
2963 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002964 /* BB find max SMB size from sess */
2965 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 pSMB->MaxSetupCount = 0;
2967 pSMB->Reserved = 0;
2968 pSMB->Flags = 0;
2969 pSMB->Timeout = 0;
2970 pSMB->Reserved2 = 0;
2971 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002972 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 offset = param_offset + params;
2974 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2975 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2976
2977 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002978 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979
Steve French790fe572007-07-07 19:25:05 +00002980 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 rc = -EOPNOTSUPP;
2982 goto setACLerrorExit;
2983 }
2984 pSMB->DataOffset = cpu_to_le16(offset);
2985 pSMB->SetupCount = 1;
2986 pSMB->Reserved3 = 0;
2987 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2988 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2989 byte_count = 3 /* pad */ + params + data_count;
2990 pSMB->DataCount = cpu_to_le16(data_count);
2991 pSMB->TotalDataCount = pSMB->DataCount;
2992 pSMB->ParameterCount = cpu_to_le16(params);
2993 pSMB->TotalParameterCount = pSMB->ParameterCount;
2994 pSMB->Reserved4 = 0;
2995 pSMB->hdr.smb_buf_length += byte_count;
2996 pSMB->ByteCount = cpu_to_le16(byte_count);
2997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002999 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
3002setACLerrorExit:
3003 cifs_buf_release(pSMB);
3004 if (rc == -EAGAIN)
3005 goto setAclRetry;
3006 return rc;
3007}
3008
Steve Frenchf654bac2005-04-28 22:41:04 -07003009/* BB fix tabs in this function FIXME BB */
3010int
3011CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003012 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003013{
Steve French50c2f752007-07-13 00:33:32 +00003014 int rc = 0;
3015 struct smb_t2_qfi_req *pSMB = NULL;
3016 struct smb_t2_qfi_rsp *pSMBr = NULL;
3017 int bytes_returned;
3018 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003019
Steve French790fe572007-07-07 19:25:05 +00003020 cFYI(1, ("In GetExtAttr"));
3021 if (tcon == NULL)
3022 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003023
3024GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003025 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3026 (void **) &pSMBr);
3027 if (rc)
3028 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003029
Steve Frenchad7a2922008-02-07 23:25:02 +00003030 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003031 pSMB->t2.TotalDataCount = 0;
3032 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3033 /* BB find exact max data count below from sess structure BB */
3034 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3035 pSMB->t2.MaxSetupCount = 0;
3036 pSMB->t2.Reserved = 0;
3037 pSMB->t2.Flags = 0;
3038 pSMB->t2.Timeout = 0;
3039 pSMB->t2.Reserved2 = 0;
3040 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3041 Fid) - 4);
3042 pSMB->t2.DataCount = 0;
3043 pSMB->t2.DataOffset = 0;
3044 pSMB->t2.SetupCount = 1;
3045 pSMB->t2.Reserved3 = 0;
3046 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3047 byte_count = params + 1 /* pad */ ;
3048 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3049 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3050 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3051 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003052 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003053 pSMB->hdr.smb_buf_length += byte_count;
3054 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003055
Steve French790fe572007-07-07 19:25:05 +00003056 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3057 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3058 if (rc) {
3059 cFYI(1, ("error %d in GetExtAttr", rc));
3060 } else {
3061 /* decode response */
3062 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3063 if (rc || (pSMBr->ByteCount < 2))
3064 /* BB also check enough total bytes returned */
3065 /* If rc should we check for EOPNOSUPP and
3066 disable the srvino flag? or in caller? */
3067 rc = -EIO; /* bad smb */
3068 else {
3069 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3070 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3071 struct file_chattr_info *pfinfo;
3072 /* BB Do we need a cast or hash here ? */
3073 if (count != 16) {
3074 cFYI(1, ("Illegal size ret in GetExtAttr"));
3075 rc = -EIO;
3076 goto GetExtAttrOut;
3077 }
3078 pfinfo = (struct file_chattr_info *)
3079 (data_offset + (char *) &pSMBr->hdr.Protocol);
3080 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003081 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003082 }
3083 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003084GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003085 cifs_buf_release(pSMB);
3086 if (rc == -EAGAIN)
3087 goto GetExtAttrRetry;
3088 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003089}
3090
Steve Frenchf654bac2005-04-28 22:41:04 -07003091#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
Steve French297647c2007-10-12 04:11:59 +00003093#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003094/* Get Security Descriptor (by handle) from remote server for a file or dir */
3095int
3096CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003097 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003098{
3099 int rc = 0;
3100 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003101 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003102 struct kvec iov[1];
3103
3104 cFYI(1, ("GetCifsACL"));
3105
Steve French630f3f0c2007-10-25 21:17:17 +00003106 *pbuflen = 0;
3107 *acl_inf = NULL;
3108
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003109 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003110 8 /* parm len */, tcon, (void **) &pSMB);
3111 if (rc)
3112 return rc;
3113
3114 pSMB->MaxParameterCount = cpu_to_le32(4);
3115 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3116 pSMB->MaxSetupCount = 0;
3117 pSMB->Fid = fid; /* file handle always le */
3118 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3119 CIFS_ACL_DACL);
3120 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3121 pSMB->hdr.smb_buf_length += 11;
3122 iov[0].iov_base = (char *)pSMB;
3123 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3124
Steve Frencha761ac52007-10-18 21:45:27 +00003125 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003126 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003127 cifs_stats_inc(&tcon->num_acl_get);
3128 if (rc) {
3129 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3130 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003131 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003132 __u32 parm_len;
3133 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003134 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003135 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003136
3137/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003138 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003139 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003140 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003141 goto qsec_out;
3142 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3143
Steve French630f3f0c2007-10-25 21:17:17 +00003144 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003145
3146 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3147 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003148 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003149 goto qsec_out;
3150 }
3151
3152/* BB check that data area is minimum length and as big as acl_len */
3153
Steve Frenchaf6f4612007-10-16 18:40:37 +00003154 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003155 if (acl_len != *pbuflen) {
3156 cERROR(1, ("acl length %d does not match %d",
3157 acl_len, *pbuflen));
3158 if (*pbuflen > acl_len)
3159 *pbuflen = acl_len;
3160 }
Steve French0a4b92c2006-01-12 15:44:21 -08003161
Steve French630f3f0c2007-10-25 21:17:17 +00003162 /* check if buffer is big enough for the acl
3163 header followed by the smallest SID */
3164 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3165 (*pbuflen >= 64 * 1024)) {
3166 cERROR(1, ("bad acl length %d", *pbuflen));
3167 rc = -EINVAL;
3168 *pbuflen = 0;
3169 } else {
3170 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3171 if (*acl_inf == NULL) {
3172 *pbuflen = 0;
3173 rc = -ENOMEM;
3174 }
3175 memcpy(*acl_inf, pdata, *pbuflen);
3176 }
Steve French0a4b92c2006-01-12 15:44:21 -08003177 }
3178qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003179 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003180 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003181 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003182 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003183/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003184 return rc;
3185}
Steve French97837582007-12-31 07:47:21 +00003186
3187int
3188CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3189 struct cifs_ntsd *pntsd, __u32 acllen)
3190{
3191 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3192 int rc = 0;
3193 int bytes_returned = 0;
3194 SET_SEC_DESC_REQ *pSMB = NULL;
3195 NTRANSACT_RSP *pSMBr = NULL;
3196
3197setCifsAclRetry:
3198 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3199 (void **) &pSMBr);
3200 if (rc)
3201 return (rc);
3202
3203 pSMB->MaxSetupCount = 0;
3204 pSMB->Reserved = 0;
3205
3206 param_count = 8;
3207 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3208 data_count = acllen;
3209 data_offset = param_offset + param_count;
3210 byte_count = 3 /* pad */ + param_count;
3211
3212 pSMB->DataCount = cpu_to_le32(data_count);
3213 pSMB->TotalDataCount = pSMB->DataCount;
3214 pSMB->MaxParameterCount = cpu_to_le32(4);
3215 pSMB->MaxDataCount = cpu_to_le32(16384);
3216 pSMB->ParameterCount = cpu_to_le32(param_count);
3217 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3218 pSMB->TotalParameterCount = pSMB->ParameterCount;
3219 pSMB->DataOffset = cpu_to_le32(data_offset);
3220 pSMB->SetupCount = 0;
3221 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3222 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3223
3224 pSMB->Fid = fid; /* file handle always le */
3225 pSMB->Reserved2 = 0;
3226 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3227
3228 if (pntsd && acllen) {
3229 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3230 (char *) pntsd,
3231 acllen);
3232 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3233
3234 } else
3235 pSMB->hdr.smb_buf_length += byte_count;
3236
3237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3238 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3239
3240 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3241 if (rc)
3242 cFYI(1, ("Set CIFS ACL returned %d", rc));
3243 cifs_buf_release(pSMB);
3244
3245 if (rc == -EAGAIN)
3246 goto setCifsAclRetry;
3247
3248 return (rc);
3249}
3250
Steve French297647c2007-10-12 04:11:59 +00003251#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003252
Steve French6b8edfe2005-08-23 20:26:03 -07003253/* Legacy Query Path Information call for lookup to old servers such
3254 as Win9x/WinME */
3255int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003256 const unsigned char *searchName,
3257 FILE_ALL_INFO *pFinfo,
3258 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003259{
Steve Frenchad7a2922008-02-07 23:25:02 +00003260 QUERY_INFORMATION_REQ *pSMB;
3261 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003262 int rc = 0;
3263 int bytes_returned;
3264 int name_len;
3265
Steve French50c2f752007-07-13 00:33:32 +00003266 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003267QInfRetry:
3268 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003269 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003270 if (rc)
3271 return rc;
3272
3273 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3274 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003275 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3276 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003277 name_len++; /* trailing null */
3278 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003279 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003280 name_len = strnlen(searchName, PATH_MAX);
3281 name_len++; /* trailing null */
3282 strncpy(pSMB->FileName, searchName, name_len);
3283 }
3284 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003285 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003286 pSMB->hdr.smb_buf_length += (__u16) name_len;
3287 pSMB->ByteCount = cpu_to_le16(name_len);
3288
3289 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003290 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003291 if (rc) {
3292 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003293 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003294 struct timespec ts;
3295 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003296
3297 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003298 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003299 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003300 ts.tv_nsec = 0;
3301 ts.tv_sec = time;
3302 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003303 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003304 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3305 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003306 pFinfo->AllocationSize =
3307 cpu_to_le64(le32_to_cpu(pSMBr->size));
3308 pFinfo->EndOfFile = pFinfo->AllocationSize;
3309 pFinfo->Attributes =
3310 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003311 } else
3312 rc = -EIO; /* bad buffer passed in */
3313
3314 cifs_buf_release(pSMB);
3315
3316 if (rc == -EAGAIN)
3317 goto QInfRetry;
3318
3319 return rc;
3320}
3321
3322
3323
3324
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325int
3326CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3327 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003328 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003329 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003330 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331{
3332/* level 263 SMB_QUERY_FILE_ALL_INFO */
3333 TRANSACTION2_QPI_REQ *pSMB = NULL;
3334 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3335 int rc = 0;
3336 int bytes_returned;
3337 int name_len;
3338 __u16 params, byte_count;
3339
3340/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3341QPathInfoRetry:
3342 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3343 (void **) &pSMBr);
3344 if (rc)
3345 return rc;
3346
3347 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3348 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003349 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003350 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 name_len++; /* trailing null */
3352 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003353 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 name_len = strnlen(searchName, PATH_MAX);
3355 name_len++; /* trailing null */
3356 strncpy(pSMB->FileName, searchName, name_len);
3357 }
3358
Steve French50c2f752007-07-13 00:33:32 +00003359 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 pSMB->TotalDataCount = 0;
3361 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003362 /* BB find exact max SMB PDU from sess structure BB */
3363 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 pSMB->MaxSetupCount = 0;
3365 pSMB->Reserved = 0;
3366 pSMB->Flags = 0;
3367 pSMB->Timeout = 0;
3368 pSMB->Reserved2 = 0;
3369 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003370 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 pSMB->DataCount = 0;
3372 pSMB->DataOffset = 0;
3373 pSMB->SetupCount = 1;
3374 pSMB->Reserved3 = 0;
3375 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3376 byte_count = params + 1 /* pad */ ;
3377 pSMB->TotalParameterCount = cpu_to_le16(params);
3378 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003379 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003380 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3381 else
3382 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 pSMB->Reserved4 = 0;
3384 pSMB->hdr.smb_buf_length += byte_count;
3385 pSMB->ByteCount = cpu_to_le16(byte_count);
3386
3387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3388 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3389 if (rc) {
3390 cFYI(1, ("Send error in QPathInfo = %d", rc));
3391 } else { /* decode response */
3392 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3393
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003394 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3395 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003396 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003398 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003399 rc = -EIO; /* 24 or 26 expected but we do not read
3400 last field */
3401 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003402 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003404
3405 /* On legacy responses we do not read the last field,
3406 EAsize, fortunately since it varies by subdialect and
3407 also note it differs on Set vs. Get, ie two bytes or 4
3408 bytes depending but we don't care here */
3409 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003410 size = sizeof(FILE_INFO_STANDARD);
3411 else
3412 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 memcpy((char *) pFindData,
3414 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003415 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 } else
3417 rc = -ENOMEM;
3418 }
3419 cifs_buf_release(pSMB);
3420 if (rc == -EAGAIN)
3421 goto QPathInfoRetry;
3422
3423 return rc;
3424}
3425
3426int
3427CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3428 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003429 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003430 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431{
3432/* SMB_QUERY_FILE_UNIX_BASIC */
3433 TRANSACTION2_QPI_REQ *pSMB = NULL;
3434 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3435 int rc = 0;
3436 int bytes_returned = 0;
3437 int name_len;
3438 __u16 params, byte_count;
3439
3440 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3441UnixQPathInfoRetry:
3442 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3443 (void **) &pSMBr);
3444 if (rc)
3445 return rc;
3446
3447 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3448 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003449 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003450 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 name_len++; /* trailing null */
3452 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003453 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 name_len = strnlen(searchName, PATH_MAX);
3455 name_len++; /* trailing null */
3456 strncpy(pSMB->FileName, searchName, name_len);
3457 }
3458
Steve French50c2f752007-07-13 00:33:32 +00003459 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 pSMB->TotalDataCount = 0;
3461 pSMB->MaxParameterCount = cpu_to_le16(2);
3462 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003463 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 pSMB->MaxSetupCount = 0;
3465 pSMB->Reserved = 0;
3466 pSMB->Flags = 0;
3467 pSMB->Timeout = 0;
3468 pSMB->Reserved2 = 0;
3469 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003470 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 pSMB->DataCount = 0;
3472 pSMB->DataOffset = 0;
3473 pSMB->SetupCount = 1;
3474 pSMB->Reserved3 = 0;
3475 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3476 byte_count = params + 1 /* pad */ ;
3477 pSMB->TotalParameterCount = cpu_to_le16(params);
3478 pSMB->ParameterCount = pSMB->TotalParameterCount;
3479 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3480 pSMB->Reserved4 = 0;
3481 pSMB->hdr.smb_buf_length += byte_count;
3482 pSMB->ByteCount = cpu_to_le16(byte_count);
3483
3484 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3485 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3486 if (rc) {
3487 cFYI(1, ("Send error in QPathInfo = %d", rc));
3488 } else { /* decode response */
3489 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3490
3491 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003492 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3493 "Unix Extensions can be disabled on mount "
3494 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 rc = -EIO; /* bad smb */
3496 } else {
3497 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3498 memcpy((char *) pFindData,
3499 (char *) &pSMBr->hdr.Protocol +
3500 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003501 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 }
3503 }
3504 cifs_buf_release(pSMB);
3505 if (rc == -EAGAIN)
3506 goto UnixQPathInfoRetry;
3507
3508 return rc;
3509}
3510
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511/* xid, tcon, searchName and codepage are input parms, rest are returned */
3512int
3513CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003514 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003516 __u16 *pnetfid,
3517 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518{
3519/* level 257 SMB_ */
3520 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3521 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003522 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 int rc = 0;
3524 int bytes_returned = 0;
3525 int name_len;
3526 __u16 params, byte_count;
3527
Steve French50c2f752007-07-13 00:33:32 +00003528 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529
3530findFirstRetry:
3531 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3532 (void **) &pSMBr);
3533 if (rc)
3534 return rc;
3535
3536 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3537 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003538 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003539 PATH_MAX, nls_codepage, remap);
3540 /* We can not add the asterik earlier in case
3541 it got remapped to 0xF03A as if it were part of the
3542 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003544 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003545 pSMB->FileName[name_len+1] = 0;
3546 pSMB->FileName[name_len+2] = '*';
3547 pSMB->FileName[name_len+3] = 0;
3548 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3550 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003551 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 } else { /* BB add check for overrun of SMB buf BB */
3553 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003555 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 free buffer exit; BB */
3557 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003558 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003559 pSMB->FileName[name_len+1] = '*';
3560 pSMB->FileName[name_len+2] = 0;
3561 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 }
3563
3564 params = 12 + name_len /* includes null */ ;
3565 pSMB->TotalDataCount = 0; /* no EAs */
3566 pSMB->MaxParameterCount = cpu_to_le16(10);
3567 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3568 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3569 pSMB->MaxSetupCount = 0;
3570 pSMB->Reserved = 0;
3571 pSMB->Flags = 0;
3572 pSMB->Timeout = 0;
3573 pSMB->Reserved2 = 0;
3574 byte_count = params + 1 /* pad */ ;
3575 pSMB->TotalParameterCount = cpu_to_le16(params);
3576 pSMB->ParameterCount = pSMB->TotalParameterCount;
3577 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003578 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3579 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 pSMB->DataCount = 0;
3581 pSMB->DataOffset = 0;
3582 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3583 pSMB->Reserved3 = 0;
3584 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3585 pSMB->SearchAttributes =
3586 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3587 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003588 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3589 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 CIFS_SEARCH_RETURN_RESUME);
3591 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3592
3593 /* BB what should we set StorageType to? Does it matter? BB */
3594 pSMB->SearchStorageType = 0;
3595 pSMB->hdr.smb_buf_length += byte_count;
3596 pSMB->ByteCount = cpu_to_le16(byte_count);
3597
3598 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3599 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003600 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601
Steve French88274812006-03-09 22:21:45 +00003602 if (rc) {/* BB add logic to retry regular search if Unix search
3603 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 /* BB Add code to handle unsupported level rc */
3605 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003606
Steve French88274812006-03-09 22:21:45 +00003607 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
3609 /* BB eventually could optimize out free and realloc of buf */
3610 /* for this case */
3611 if (rc == -EAGAIN)
3612 goto findFirstRetry;
3613 } else { /* decode response */
3614 /* BB remember to free buffer if error BB */
3615 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003616 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003617 unsigned int lnoff;
3618
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003620 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 else
Steve French4b18f2a2008-04-29 00:06:05 +00003622 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623
3624 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003625 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003626 psrch_inf->srch_entries_start =
3627 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3630 le16_to_cpu(pSMBr->t2.ParameterOffset));
3631
Steve French790fe572007-07-07 19:25:05 +00003632 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003633 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 else
Steve French4b18f2a2008-04-29 00:06:05 +00003635 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636
Steve French50c2f752007-07-13 00:33:32 +00003637 psrch_inf->entries_in_buffer =
3638 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003639 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003641 lnoff = le16_to_cpu(parms->LastNameOffset);
3642 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3643 lnoff) {
3644 cERROR(1, ("ignoring corrupt resume name"));
3645 psrch_inf->last_entry = NULL;
3646 return rc;
3647 }
3648
Steve French0752f152008-10-07 20:03:33 +00003649 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003650 lnoff;
3651
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 *pnetfid = parms->SearchHandle;
3653 } else {
3654 cifs_buf_release(pSMB);
3655 }
3656 }
3657
3658 return rc;
3659}
3660
3661int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003662 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663{
3664 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3665 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003666 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 char *response_data;
3668 int rc = 0;
3669 int bytes_returned, name_len;
3670 __u16 params, byte_count;
3671
3672 cFYI(1, ("In FindNext"));
3673
Steve French4b18f2a2008-04-29 00:06:05 +00003674 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 return -ENOENT;
3676
3677 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3678 (void **) &pSMBr);
3679 if (rc)
3680 return rc;
3681
Steve French50c2f752007-07-13 00:33:32 +00003682 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 byte_count = 0;
3684 pSMB->TotalDataCount = 0; /* no EAs */
3685 pSMB->MaxParameterCount = cpu_to_le16(8);
3686 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003687 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3688 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 pSMB->MaxSetupCount = 0;
3690 pSMB->Reserved = 0;
3691 pSMB->Flags = 0;
3692 pSMB->Timeout = 0;
3693 pSMB->Reserved2 = 0;
3694 pSMB->ParameterOffset = cpu_to_le16(
3695 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3696 pSMB->DataCount = 0;
3697 pSMB->DataOffset = 0;
3698 pSMB->SetupCount = 1;
3699 pSMB->Reserved3 = 0;
3700 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3701 pSMB->SearchHandle = searchHandle; /* always kept as le */
3702 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003703 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3705 pSMB->ResumeKey = psrch_inf->resume_key;
3706 pSMB->SearchFlags =
3707 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3708
3709 name_len = psrch_inf->resume_name_len;
3710 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003711 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3713 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003714 /* 14 byte parm len above enough for 2 byte null terminator */
3715 pSMB->ResumeFileName[name_len] = 0;
3716 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 } else {
3718 rc = -EINVAL;
3719 goto FNext2_err_exit;
3720 }
3721 byte_count = params + 1 /* pad */ ;
3722 pSMB->TotalParameterCount = cpu_to_le16(params);
3723 pSMB->ParameterCount = pSMB->TotalParameterCount;
3724 pSMB->hdr.smb_buf_length += byte_count;
3725 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003726
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3728 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003729 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 if (rc) {
3731 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003732 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003733 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003734 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 } else
3736 cFYI(1, ("FindNext returned = %d", rc));
3737 } else { /* decode response */
3738 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003739
Steve French790fe572007-07-07 19:25:05 +00003740 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003741 unsigned int lnoff;
3742
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 /* BB fixme add lock for file (srch_info) struct here */
3744 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003745 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 else
Steve French4b18f2a2008-04-29 00:06:05 +00003747 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 response_data = (char *) &pSMBr->hdr.Protocol +
3749 le16_to_cpu(pSMBr->t2.ParameterOffset);
3750 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3751 response_data = (char *)&pSMBr->hdr.Protocol +
3752 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003753 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003754 cifs_small_buf_release(
3755 psrch_inf->ntwrk_buf_start);
3756 else
3757 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 psrch_inf->srch_entries_start = response_data;
3759 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003760 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003761 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003762 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 else
Steve French4b18f2a2008-04-29 00:06:05 +00003764 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003765 psrch_inf->entries_in_buffer =
3766 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 psrch_inf->index_of_last_entry +=
3768 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003769 lnoff = le16_to_cpu(parms->LastNameOffset);
3770 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3771 lnoff) {
3772 cERROR(1, ("ignoring corrupt resume name"));
3773 psrch_inf->last_entry = NULL;
3774 return rc;
3775 } else
3776 psrch_inf->last_entry =
3777 psrch_inf->srch_entries_start + lnoff;
3778
Steve French50c2f752007-07-13 00:33:32 +00003779/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3780 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781
3782 /* BB fixme add unlock here */
3783 }
3784
3785 }
3786
3787 /* BB On error, should we leave previous search buf (and count and
3788 last entry fields) intact or free the previous one? */
3789
3790 /* Note: On -EAGAIN error only caller can retry on handle based calls
3791 since file handle passed in no longer valid */
3792FNext2_err_exit:
3793 if (rc != 0)
3794 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 return rc;
3796}
3797
3798int
Steve French50c2f752007-07-13 00:33:32 +00003799CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3800 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801{
3802 int rc = 0;
3803 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804
3805 cFYI(1, ("In CIFSSMBFindClose"));
3806 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3807
3808 /* no sense returning error if session restarted
3809 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003810 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 return 0;
3812 if (rc)
3813 return rc;
3814
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 pSMB->FileID = searchHandle;
3816 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003817 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003818 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003820
Steve Frencha4544342005-08-24 13:59:35 -07003821 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822
3823 /* Since session is dead, search handle closed on server already */
3824 if (rc == -EAGAIN)
3825 rc = 0;
3826
3827 return rc;
3828}
3829
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830int
3831CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003832 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003833 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003834 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835{
3836 int rc = 0;
3837 TRANSACTION2_QPI_REQ *pSMB = NULL;
3838 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3839 int name_len, bytes_returned;
3840 __u16 params, byte_count;
3841
Steve French50c2f752007-07-13 00:33:32 +00003842 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003843 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003844 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845
3846GetInodeNumberRetry:
3847 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003848 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 if (rc)
3850 return rc;
3851
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3853 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003854 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003855 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 name_len++; /* trailing null */
3857 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003858 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 name_len = strnlen(searchName, PATH_MAX);
3860 name_len++; /* trailing null */
3861 strncpy(pSMB->FileName, searchName, name_len);
3862 }
3863
3864 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3865 pSMB->TotalDataCount = 0;
3866 pSMB->MaxParameterCount = cpu_to_le16(2);
3867 /* BB find exact max data count below from sess structure BB */
3868 pSMB->MaxDataCount = cpu_to_le16(4000);
3869 pSMB->MaxSetupCount = 0;
3870 pSMB->Reserved = 0;
3871 pSMB->Flags = 0;
3872 pSMB->Timeout = 0;
3873 pSMB->Reserved2 = 0;
3874 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003875 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 pSMB->DataCount = 0;
3877 pSMB->DataOffset = 0;
3878 pSMB->SetupCount = 1;
3879 pSMB->Reserved3 = 0;
3880 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3881 byte_count = params + 1 /* pad */ ;
3882 pSMB->TotalParameterCount = cpu_to_le16(params);
3883 pSMB->ParameterCount = pSMB->TotalParameterCount;
3884 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3885 pSMB->Reserved4 = 0;
3886 pSMB->hdr.smb_buf_length += byte_count;
3887 pSMB->ByteCount = cpu_to_le16(byte_count);
3888
3889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3890 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3891 if (rc) {
3892 cFYI(1, ("error %d in QueryInternalInfo", rc));
3893 } else {
3894 /* decode response */
3895 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3896 if (rc || (pSMBr->ByteCount < 2))
3897 /* BB also check enough total bytes returned */
3898 /* If rc should we check for EOPNOSUPP and
3899 disable the srvino flag? or in caller? */
3900 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003901 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3903 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003904 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003906 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3908 rc = -EIO;
3909 goto GetInodeNumOut;
3910 }
3911 pfinfo = (struct file_internal_info *)
3912 (data_offset + (char *) &pSMBr->hdr.Protocol);
3913 *inode_number = pfinfo->UniqueId;
3914 }
3915 }
3916GetInodeNumOut:
3917 cifs_buf_release(pSMB);
3918 if (rc == -EAGAIN)
3919 goto GetInodeNumberRetry;
3920 return rc;
3921}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
Igor Mammedovfec45852008-05-16 13:06:30 +04003923/* parses DFS refferal V3 structure
3924 * caller is responsible for freeing target_nodes
3925 * returns:
3926 * on success - 0
3927 * on failure - errno
3928 */
3929static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003930parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003931 unsigned int *num_of_nodes,
3932 struct dfs_info3_param **target_nodes,
3933 const struct nls_table *nls_codepage)
3934{
3935 int i, rc = 0;
3936 char *data_end;
3937 bool is_unicode;
3938 struct dfs_referral_level_3 *ref;
3939
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003940 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3941 is_unicode = true;
3942 else
3943 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003944 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3945
3946 if (*num_of_nodes < 1) {
3947 cERROR(1, ("num_referrals: must be at least > 0,"
3948 "but we get num_referrals = %d\n", *num_of_nodes));
3949 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003950 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003951 }
3952
3953 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003954 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003955 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003956 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003957 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003958 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003959 }
3960
3961 /* get the upper boundary of the resp buffer */
3962 data_end = (char *)(&(pSMBr->PathConsumed)) +
3963 le16_to_cpu(pSMBr->t2.DataCount);
3964
3965 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3966 *num_of_nodes,
3967 le16_to_cpu(pSMBr->DFSFlags)));
3968
3969 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3970 *num_of_nodes, GFP_KERNEL);
3971 if (*target_nodes == NULL) {
3972 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3973 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003974 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003975 }
3976
3977 /* collect neccessary data from referrals */
3978 for (i = 0; i < *num_of_nodes; i++) {
3979 char *temp;
3980 int max_len;
3981 struct dfs_info3_param *node = (*target_nodes)+i;
3982
3983 node->flags = le16_to_cpu(pSMBr->DFSFlags);
3984 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3985 node->server_type = le16_to_cpu(ref->ServerType);
3986 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3987
3988 /* copy DfsPath */
3989 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3990 max_len = data_end - temp;
3991 rc = cifs_strncpy_to_host(&(node->path_name), temp,
3992 max_len, is_unicode, nls_codepage);
3993 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00003994 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003995
3996 /* copy link target UNC */
3997 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3998 max_len = data_end - temp;
3999 rc = cifs_strncpy_to_host(&(node->node_name), temp,
4000 max_len, is_unicode, nls_codepage);
4001 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00004002 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004003
Al Viro1d92cfd2008-06-02 10:59:02 +01004004 ref += le16_to_cpu(ref->Size);
Igor Mammedovfec45852008-05-16 13:06:30 +04004005 }
4006
Steve Frencha1fe78f2008-05-16 18:48:38 +00004007parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004008 if (rc) {
4009 free_dfs_info_array(*target_nodes, *num_of_nodes);
4010 *target_nodes = NULL;
4011 *num_of_nodes = 0;
4012 }
4013 return rc;
4014}
4015
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016int
4017CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4018 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004019 struct dfs_info3_param **target_nodes,
4020 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004021 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022{
4023/* TRANS2_GET_DFS_REFERRAL */
4024 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4025 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 int rc = 0;
4027 int bytes_returned;
4028 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004030 *num_of_nodes = 0;
4031 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032
4033 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4034 if (ses == NULL)
4035 return -ENODEV;
4036getDFSRetry:
4037 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4038 (void **) &pSMBr);
4039 if (rc)
4040 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004041
4042 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004043 but should never be null here anyway */
4044 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 pSMB->hdr.Tid = ses->ipc_tid;
4046 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004047 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004049 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051
4052 if (ses->capabilities & CAP_UNICODE) {
4053 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4054 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004055 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004056 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 name_len++; /* trailing null */
4058 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004059 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 name_len = strnlen(searchName, PATH_MAX);
4061 name_len++; /* trailing null */
4062 strncpy(pSMB->RequestFileName, searchName, name_len);
4063 }
4064
Steve French790fe572007-07-07 19:25:05 +00004065 if (ses->server) {
4066 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004067 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4068 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4069 }
4070
Steve French50c2f752007-07-13 00:33:32 +00004071 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004072
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 params = 2 /* level */ + name_len /*includes null */ ;
4074 pSMB->TotalDataCount = 0;
4075 pSMB->DataCount = 0;
4076 pSMB->DataOffset = 0;
4077 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004078 /* BB find exact max SMB PDU from sess structure BB */
4079 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 pSMB->MaxSetupCount = 0;
4081 pSMB->Reserved = 0;
4082 pSMB->Flags = 0;
4083 pSMB->Timeout = 0;
4084 pSMB->Reserved2 = 0;
4085 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004086 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 pSMB->SetupCount = 1;
4088 pSMB->Reserved3 = 0;
4089 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4090 byte_count = params + 3 /* pad */ ;
4091 pSMB->ParameterCount = cpu_to_le16(params);
4092 pSMB->TotalParameterCount = pSMB->ParameterCount;
4093 pSMB->MaxReferralLevel = cpu_to_le16(3);
4094 pSMB->hdr.smb_buf_length += byte_count;
4095 pSMB->ByteCount = cpu_to_le16(byte_count);
4096
4097 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4099 if (rc) {
4100 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004101 goto GetDFSRefExit;
4102 }
4103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004105 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004106 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004107 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004108 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004110
4111 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4112 pSMBr->ByteCount,
4113 le16_to_cpu(pSMBr->t2.DataOffset)));
4114
4115 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004116 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedovfec45852008-05-16 13:06:30 +04004117 target_nodes, nls_codepage);
4118
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004120 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
4122 if (rc == -EAGAIN)
4123 goto getDFSRetry;
4124
4125 return rc;
4126}
4127
Steve French20962432005-09-21 22:05:57 -07004128/* Query File System Info such as free space to old servers such as Win 9x */
4129int
4130SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4131{
4132/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4133 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4134 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4135 FILE_SYSTEM_ALLOC_INFO *response_data;
4136 int rc = 0;
4137 int bytes_returned = 0;
4138 __u16 params, byte_count;
4139
4140 cFYI(1, ("OldQFSInfo"));
4141oldQFSInfoRetry:
4142 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4143 (void **) &pSMBr);
4144 if (rc)
4145 return rc;
Steve French20962432005-09-21 22:05:57 -07004146
4147 params = 2; /* level */
4148 pSMB->TotalDataCount = 0;
4149 pSMB->MaxParameterCount = cpu_to_le16(2);
4150 pSMB->MaxDataCount = cpu_to_le16(1000);
4151 pSMB->MaxSetupCount = 0;
4152 pSMB->Reserved = 0;
4153 pSMB->Flags = 0;
4154 pSMB->Timeout = 0;
4155 pSMB->Reserved2 = 0;
4156 byte_count = params + 1 /* pad */ ;
4157 pSMB->TotalParameterCount = cpu_to_le16(params);
4158 pSMB->ParameterCount = pSMB->TotalParameterCount;
4159 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4160 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4161 pSMB->DataCount = 0;
4162 pSMB->DataOffset = 0;
4163 pSMB->SetupCount = 1;
4164 pSMB->Reserved3 = 0;
4165 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4166 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4167 pSMB->hdr.smb_buf_length += byte_count;
4168 pSMB->ByteCount = cpu_to_le16(byte_count);
4169
4170 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4171 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4172 if (rc) {
4173 cFYI(1, ("Send error in QFSInfo = %d", rc));
4174 } else { /* decode response */
4175 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4176
4177 if (rc || (pSMBr->ByteCount < 18))
4178 rc = -EIO; /* bad smb */
4179 else {
4180 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004181 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004182 pSMBr->ByteCount, data_offset));
4183
Steve French50c2f752007-07-13 00:33:32 +00004184 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004185 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4186 FSData->f_bsize =
4187 le16_to_cpu(response_data->BytesPerSector) *
4188 le32_to_cpu(response_data->
4189 SectorsPerAllocationUnit);
4190 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004191 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004192 FSData->f_bfree = FSData->f_bavail =
4193 le32_to_cpu(response_data->FreeAllocationUnits);
4194 cFYI(1,
4195 ("Blocks: %lld Free: %lld Block size %ld",
4196 (unsigned long long)FSData->f_blocks,
4197 (unsigned long long)FSData->f_bfree,
4198 FSData->f_bsize));
4199 }
4200 }
4201 cifs_buf_release(pSMB);
4202
4203 if (rc == -EAGAIN)
4204 goto oldQFSInfoRetry;
4205
4206 return rc;
4207}
4208
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209int
Steve French737b7582005-04-28 22:41:06 -07004210CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211{
4212/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4213 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4214 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4215 FILE_SYSTEM_INFO *response_data;
4216 int rc = 0;
4217 int bytes_returned = 0;
4218 __u16 params, byte_count;
4219
4220 cFYI(1, ("In QFSInfo"));
4221QFSInfoRetry:
4222 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4223 (void **) &pSMBr);
4224 if (rc)
4225 return rc;
4226
4227 params = 2; /* level */
4228 pSMB->TotalDataCount = 0;
4229 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004230 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 pSMB->MaxSetupCount = 0;
4232 pSMB->Reserved = 0;
4233 pSMB->Flags = 0;
4234 pSMB->Timeout = 0;
4235 pSMB->Reserved2 = 0;
4236 byte_count = params + 1 /* pad */ ;
4237 pSMB->TotalParameterCount = cpu_to_le16(params);
4238 pSMB->ParameterCount = pSMB->TotalParameterCount;
4239 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004240 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 pSMB->DataCount = 0;
4242 pSMB->DataOffset = 0;
4243 pSMB->SetupCount = 1;
4244 pSMB->Reserved3 = 0;
4245 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4246 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4247 pSMB->hdr.smb_buf_length += byte_count;
4248 pSMB->ByteCount = cpu_to_le16(byte_count);
4249
4250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4251 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4252 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004253 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004255 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256
Steve French20962432005-09-21 22:05:57 -07004257 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 rc = -EIO; /* bad smb */
4259 else {
4260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261
4262 response_data =
4263 (FILE_SYSTEM_INFO
4264 *) (((char *) &pSMBr->hdr.Protocol) +
4265 data_offset);
4266 FSData->f_bsize =
4267 le32_to_cpu(response_data->BytesPerSector) *
4268 le32_to_cpu(response_data->
4269 SectorsPerAllocationUnit);
4270 FSData->f_blocks =
4271 le64_to_cpu(response_data->TotalAllocationUnits);
4272 FSData->f_bfree = FSData->f_bavail =
4273 le64_to_cpu(response_data->FreeAllocationUnits);
4274 cFYI(1,
4275 ("Blocks: %lld Free: %lld Block size %ld",
4276 (unsigned long long)FSData->f_blocks,
4277 (unsigned long long)FSData->f_bfree,
4278 FSData->f_bsize));
4279 }
4280 }
4281 cifs_buf_release(pSMB);
4282
4283 if (rc == -EAGAIN)
4284 goto QFSInfoRetry;
4285
4286 return rc;
4287}
4288
4289int
Steve French737b7582005-04-28 22:41:06 -07004290CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291{
4292/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4293 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4294 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4295 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4296 int rc = 0;
4297 int bytes_returned = 0;
4298 __u16 params, byte_count;
4299
4300 cFYI(1, ("In QFSAttributeInfo"));
4301QFSAttributeRetry:
4302 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4303 (void **) &pSMBr);
4304 if (rc)
4305 return rc;
4306
4307 params = 2; /* level */
4308 pSMB->TotalDataCount = 0;
4309 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004310 /* BB find exact max SMB PDU from sess structure BB */
4311 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 pSMB->MaxSetupCount = 0;
4313 pSMB->Reserved = 0;
4314 pSMB->Flags = 0;
4315 pSMB->Timeout = 0;
4316 pSMB->Reserved2 = 0;
4317 byte_count = params + 1 /* pad */ ;
4318 pSMB->TotalParameterCount = cpu_to_le16(params);
4319 pSMB->ParameterCount = pSMB->TotalParameterCount;
4320 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004321 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 pSMB->DataCount = 0;
4323 pSMB->DataOffset = 0;
4324 pSMB->SetupCount = 1;
4325 pSMB->Reserved3 = 0;
4326 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4327 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4328 pSMB->hdr.smb_buf_length += byte_count;
4329 pSMB->ByteCount = cpu_to_le16(byte_count);
4330
4331 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4332 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4333 if (rc) {
4334 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4335 } else { /* decode response */
4336 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4337
Steve French50c2f752007-07-13 00:33:32 +00004338 if (rc || (pSMBr->ByteCount < 13)) {
4339 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 rc = -EIO; /* bad smb */
4341 } else {
4342 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4343 response_data =
4344 (FILE_SYSTEM_ATTRIBUTE_INFO
4345 *) (((char *) &pSMBr->hdr.Protocol) +
4346 data_offset);
4347 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004348 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 }
4350 }
4351 cifs_buf_release(pSMB);
4352
4353 if (rc == -EAGAIN)
4354 goto QFSAttributeRetry;
4355
4356 return rc;
4357}
4358
4359int
Steve French737b7582005-04-28 22:41:06 -07004360CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361{
4362/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4363 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4364 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4365 FILE_SYSTEM_DEVICE_INFO *response_data;
4366 int rc = 0;
4367 int bytes_returned = 0;
4368 __u16 params, byte_count;
4369
4370 cFYI(1, ("In QFSDeviceInfo"));
4371QFSDeviceRetry:
4372 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4373 (void **) &pSMBr);
4374 if (rc)
4375 return rc;
4376
4377 params = 2; /* level */
4378 pSMB->TotalDataCount = 0;
4379 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004380 /* BB find exact max SMB PDU from sess structure BB */
4381 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 pSMB->MaxSetupCount = 0;
4383 pSMB->Reserved = 0;
4384 pSMB->Flags = 0;
4385 pSMB->Timeout = 0;
4386 pSMB->Reserved2 = 0;
4387 byte_count = params + 1 /* pad */ ;
4388 pSMB->TotalParameterCount = cpu_to_le16(params);
4389 pSMB->ParameterCount = pSMB->TotalParameterCount;
4390 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004391 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392
4393 pSMB->DataCount = 0;
4394 pSMB->DataOffset = 0;
4395 pSMB->SetupCount = 1;
4396 pSMB->Reserved3 = 0;
4397 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4398 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4399 pSMB->hdr.smb_buf_length += byte_count;
4400 pSMB->ByteCount = cpu_to_le16(byte_count);
4401
4402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4404 if (rc) {
4405 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4406 } else { /* decode response */
4407 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4408
Steve French630f3f0c2007-10-25 21:17:17 +00004409 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 rc = -EIO; /* bad smb */
4411 else {
4412 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4413 response_data =
Steve French737b7582005-04-28 22:41:06 -07004414 (FILE_SYSTEM_DEVICE_INFO *)
4415 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 data_offset);
4417 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004418 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 }
4420 }
4421 cifs_buf_release(pSMB);
4422
4423 if (rc == -EAGAIN)
4424 goto QFSDeviceRetry;
4425
4426 return rc;
4427}
4428
4429int
Steve French737b7582005-04-28 22:41:06 -07004430CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431{
4432/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4433 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4434 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4435 FILE_SYSTEM_UNIX_INFO *response_data;
4436 int rc = 0;
4437 int bytes_returned = 0;
4438 __u16 params, byte_count;
4439
4440 cFYI(1, ("In QFSUnixInfo"));
4441QFSUnixRetry:
4442 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4443 (void **) &pSMBr);
4444 if (rc)
4445 return rc;
4446
4447 params = 2; /* level */
4448 pSMB->TotalDataCount = 0;
4449 pSMB->DataCount = 0;
4450 pSMB->DataOffset = 0;
4451 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004452 /* BB find exact max SMB PDU from sess structure BB */
4453 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 pSMB->MaxSetupCount = 0;
4455 pSMB->Reserved = 0;
4456 pSMB->Flags = 0;
4457 pSMB->Timeout = 0;
4458 pSMB->Reserved2 = 0;
4459 byte_count = params + 1 /* pad */ ;
4460 pSMB->ParameterCount = cpu_to_le16(params);
4461 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004462 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4463 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 pSMB->SetupCount = 1;
4465 pSMB->Reserved3 = 0;
4466 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4467 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4468 pSMB->hdr.smb_buf_length += byte_count;
4469 pSMB->ByteCount = cpu_to_le16(byte_count);
4470
4471 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4472 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4473 if (rc) {
4474 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4475 } else { /* decode response */
4476 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4477
4478 if (rc || (pSMBr->ByteCount < 13)) {
4479 rc = -EIO; /* bad smb */
4480 } else {
4481 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4482 response_data =
4483 (FILE_SYSTEM_UNIX_INFO
4484 *) (((char *) &pSMBr->hdr.Protocol) +
4485 data_offset);
4486 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004487 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 }
4489 }
4490 cifs_buf_release(pSMB);
4491
4492 if (rc == -EAGAIN)
4493 goto QFSUnixRetry;
4494
4495
4496 return rc;
4497}
4498
Jeremy Allisonac670552005-06-22 17:26:35 -07004499int
Steve French45abc6e2005-06-23 13:42:03 -05004500CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004501{
4502/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4503 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4504 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4505 int rc = 0;
4506 int bytes_returned = 0;
4507 __u16 params, param_offset, offset, byte_count;
4508
4509 cFYI(1, ("In SETFSUnixInfo"));
4510SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004511 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004512 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4513 (void **) &pSMBr);
4514 if (rc)
4515 return rc;
4516
4517 params = 4; /* 2 bytes zero followed by info level. */
4518 pSMB->MaxSetupCount = 0;
4519 pSMB->Reserved = 0;
4520 pSMB->Flags = 0;
4521 pSMB->Timeout = 0;
4522 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004523 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4524 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004525 offset = param_offset + params;
4526
4527 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004528 /* BB find exact max SMB PDU from sess structure BB */
4529 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004530 pSMB->SetupCount = 1;
4531 pSMB->Reserved3 = 0;
4532 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4533 byte_count = 1 /* pad */ + params + 12;
4534
4535 pSMB->DataCount = cpu_to_le16(12);
4536 pSMB->ParameterCount = cpu_to_le16(params);
4537 pSMB->TotalDataCount = pSMB->DataCount;
4538 pSMB->TotalParameterCount = pSMB->ParameterCount;
4539 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4540 pSMB->DataOffset = cpu_to_le16(offset);
4541
4542 /* Params. */
4543 pSMB->FileNum = 0;
4544 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4545
4546 /* Data. */
4547 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4548 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4549 pSMB->ClientUnixCap = cpu_to_le64(cap);
4550
4551 pSMB->hdr.smb_buf_length += byte_count;
4552 pSMB->ByteCount = cpu_to_le16(byte_count);
4553
4554 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4555 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4556 if (rc) {
4557 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4558 } else { /* decode response */
4559 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004560 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004561 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004562 }
4563 cifs_buf_release(pSMB);
4564
4565 if (rc == -EAGAIN)
4566 goto SETFSUnixRetry;
4567
4568 return rc;
4569}
4570
4571
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572
4573int
4574CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004575 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576{
4577/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4578 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4579 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4580 FILE_SYSTEM_POSIX_INFO *response_data;
4581 int rc = 0;
4582 int bytes_returned = 0;
4583 __u16 params, byte_count;
4584
4585 cFYI(1, ("In QFSPosixInfo"));
4586QFSPosixRetry:
4587 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4588 (void **) &pSMBr);
4589 if (rc)
4590 return rc;
4591
4592 params = 2; /* level */
4593 pSMB->TotalDataCount = 0;
4594 pSMB->DataCount = 0;
4595 pSMB->DataOffset = 0;
4596 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004597 /* BB find exact max SMB PDU from sess structure BB */
4598 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 pSMB->MaxSetupCount = 0;
4600 pSMB->Reserved = 0;
4601 pSMB->Flags = 0;
4602 pSMB->Timeout = 0;
4603 pSMB->Reserved2 = 0;
4604 byte_count = params + 1 /* pad */ ;
4605 pSMB->ParameterCount = cpu_to_le16(params);
4606 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004607 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4608 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 pSMB->SetupCount = 1;
4610 pSMB->Reserved3 = 0;
4611 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4612 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4613 pSMB->hdr.smb_buf_length += byte_count;
4614 pSMB->ByteCount = cpu_to_le16(byte_count);
4615
4616 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4617 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4618 if (rc) {
4619 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4620 } else { /* decode response */
4621 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4622
4623 if (rc || (pSMBr->ByteCount < 13)) {
4624 rc = -EIO; /* bad smb */
4625 } else {
4626 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4627 response_data =
4628 (FILE_SYSTEM_POSIX_INFO
4629 *) (((char *) &pSMBr->hdr.Protocol) +
4630 data_offset);
4631 FSData->f_bsize =
4632 le32_to_cpu(response_data->BlockSize);
4633 FSData->f_blocks =
4634 le64_to_cpu(response_data->TotalBlocks);
4635 FSData->f_bfree =
4636 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004637 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 FSData->f_bavail = FSData->f_bfree;
4639 } else {
4640 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004641 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 }
Steve French790fe572007-07-07 19:25:05 +00004643 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004645 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004646 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004648 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 }
4650 }
4651 cifs_buf_release(pSMB);
4652
4653 if (rc == -EAGAIN)
4654 goto QFSPosixRetry;
4655
4656 return rc;
4657}
4658
4659
Steve French50c2f752007-07-13 00:33:32 +00004660/* We can not use write of zero bytes trick to
4661 set file size due to need for large file support. Also note that
4662 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 routine which is only needed to work around a sharing violation bug
4664 in Samba which this routine can run into */
4665
4666int
4667CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004668 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004669 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670{
4671 struct smb_com_transaction2_spi_req *pSMB = NULL;
4672 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4673 struct file_end_of_file_info *parm_data;
4674 int name_len;
4675 int rc = 0;
4676 int bytes_returned = 0;
4677 __u16 params, byte_count, data_count, param_offset, offset;
4678
4679 cFYI(1, ("In SetEOF"));
4680SetEOFRetry:
4681 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4682 (void **) &pSMBr);
4683 if (rc)
4684 return rc;
4685
4686 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4687 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004688 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004689 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 name_len++; /* trailing null */
4691 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004692 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 name_len = strnlen(fileName, PATH_MAX);
4694 name_len++; /* trailing null */
4695 strncpy(pSMB->FileName, fileName, name_len);
4696 }
4697 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004698 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004700 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 pSMB->MaxSetupCount = 0;
4702 pSMB->Reserved = 0;
4703 pSMB->Flags = 0;
4704 pSMB->Timeout = 0;
4705 pSMB->Reserved2 = 0;
4706 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004707 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004709 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004710 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4711 pSMB->InformationLevel =
4712 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4713 else
4714 pSMB->InformationLevel =
4715 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4716 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4718 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004719 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 else
4721 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004722 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 }
4724
4725 parm_data =
4726 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4727 offset);
4728 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4729 pSMB->DataOffset = cpu_to_le16(offset);
4730 pSMB->SetupCount = 1;
4731 pSMB->Reserved3 = 0;
4732 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4733 byte_count = 3 /* pad */ + params + data_count;
4734 pSMB->DataCount = cpu_to_le16(data_count);
4735 pSMB->TotalDataCount = pSMB->DataCount;
4736 pSMB->ParameterCount = cpu_to_le16(params);
4737 pSMB->TotalParameterCount = pSMB->ParameterCount;
4738 pSMB->Reserved4 = 0;
4739 pSMB->hdr.smb_buf_length += byte_count;
4740 parm_data->FileSize = cpu_to_le64(size);
4741 pSMB->ByteCount = cpu_to_le16(byte_count);
4742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004744 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746
4747 cifs_buf_release(pSMB);
4748
4749 if (rc == -EAGAIN)
4750 goto SetEOFRetry;
4751
4752 return rc;
4753}
4754
4755int
Steve French50c2f752007-07-13 00:33:32 +00004756CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004757 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758{
4759 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 char *data_offset;
4761 struct file_end_of_file_info *parm_data;
4762 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 __u16 params, param_offset, offset, byte_count, count;
4764
4765 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4766 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004767 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4768
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 if (rc)
4770 return rc;
4771
4772 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4773 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004774
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 params = 6;
4776 pSMB->MaxSetupCount = 0;
4777 pSMB->Reserved = 0;
4778 pSMB->Flags = 0;
4779 pSMB->Timeout = 0;
4780 pSMB->Reserved2 = 0;
4781 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4782 offset = param_offset + params;
4783
Steve French50c2f752007-07-13 00:33:32 +00004784 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785
4786 count = sizeof(struct file_end_of_file_info);
4787 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004788 /* BB find exact max SMB PDU from sess structure BB */
4789 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 pSMB->SetupCount = 1;
4791 pSMB->Reserved3 = 0;
4792 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4793 byte_count = 3 /* pad */ + params + count;
4794 pSMB->DataCount = cpu_to_le16(count);
4795 pSMB->ParameterCount = cpu_to_le16(params);
4796 pSMB->TotalDataCount = pSMB->DataCount;
4797 pSMB->TotalParameterCount = pSMB->ParameterCount;
4798 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4799 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004800 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4801 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 pSMB->DataOffset = cpu_to_le16(offset);
4803 parm_data->FileSize = cpu_to_le64(size);
4804 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004805 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4807 pSMB->InformationLevel =
4808 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4809 else
4810 pSMB->InformationLevel =
4811 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004812 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4814 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004815 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 else
4817 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004818 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 }
4820 pSMB->Reserved4 = 0;
4821 pSMB->hdr.smb_buf_length += byte_count;
4822 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004823 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 if (rc) {
4825 cFYI(1,
4826 ("Send error in SetFileInfo (SetFileSize) = %d",
4827 rc));
4828 }
4829
Steve French50c2f752007-07-13 00:33:32 +00004830 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 since file handle passed in no longer valid */
4832
4833 return rc;
4834}
4835
Steve French50c2f752007-07-13 00:33:32 +00004836/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 an open handle, rather than by pathname - this is awkward due to
4838 potential access conflicts on the open, but it is unavoidable for these
4839 old servers since the only other choice is to go from 100 nanosecond DCE
4840 time and resort to the original setpathinfo level which takes the ancient
4841 DOS time format with 2 second granularity */
4842int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004843CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4844 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845{
4846 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 char *data_offset;
4848 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 __u16 params, param_offset, offset, byte_count, count;
4850
4851 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004852 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4853
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 if (rc)
4855 return rc;
4856
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004857 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4858 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004859
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 params = 6;
4861 pSMB->MaxSetupCount = 0;
4862 pSMB->Reserved = 0;
4863 pSMB->Flags = 0;
4864 pSMB->Timeout = 0;
4865 pSMB->Reserved2 = 0;
4866 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4867 offset = param_offset + params;
4868
Steve French50c2f752007-07-13 00:33:32 +00004869 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870
Steve French26f57362007-08-30 22:09:15 +00004871 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004873 /* BB find max SMB PDU from sess */
4874 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 pSMB->SetupCount = 1;
4876 pSMB->Reserved3 = 0;
4877 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4878 byte_count = 3 /* pad */ + params + count;
4879 pSMB->DataCount = cpu_to_le16(count);
4880 pSMB->ParameterCount = cpu_to_le16(params);
4881 pSMB->TotalDataCount = pSMB->DataCount;
4882 pSMB->TotalParameterCount = pSMB->ParameterCount;
4883 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4884 pSMB->DataOffset = cpu_to_le16(offset);
4885 pSMB->Fid = fid;
4886 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4887 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4888 else
4889 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4890 pSMB->Reserved4 = 0;
4891 pSMB->hdr.smb_buf_length += byte_count;
4892 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004893 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004894 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004895 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004896 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897
Steve French50c2f752007-07-13 00:33:32 +00004898 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 since file handle passed in no longer valid */
4900
4901 return rc;
4902}
4903
Jeff Layton6d22f092008-09-23 11:48:35 -04004904int
4905CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4906 bool delete_file, __u16 fid, __u32 pid_of_opener)
4907{
4908 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4909 char *data_offset;
4910 int rc = 0;
4911 __u16 params, param_offset, offset, byte_count, count;
4912
4913 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4914 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4915
4916 if (rc)
4917 return rc;
4918
4919 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4920 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4921
4922 params = 6;
4923 pSMB->MaxSetupCount = 0;
4924 pSMB->Reserved = 0;
4925 pSMB->Flags = 0;
4926 pSMB->Timeout = 0;
4927 pSMB->Reserved2 = 0;
4928 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4929 offset = param_offset + params;
4930
4931 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4932
4933 count = 1;
4934 pSMB->MaxParameterCount = cpu_to_le16(2);
4935 /* BB find max SMB PDU from sess */
4936 pSMB->MaxDataCount = cpu_to_le16(1000);
4937 pSMB->SetupCount = 1;
4938 pSMB->Reserved3 = 0;
4939 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4940 byte_count = 3 /* pad */ + params + count;
4941 pSMB->DataCount = cpu_to_le16(count);
4942 pSMB->ParameterCount = cpu_to_le16(params);
4943 pSMB->TotalDataCount = pSMB->DataCount;
4944 pSMB->TotalParameterCount = pSMB->ParameterCount;
4945 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4946 pSMB->DataOffset = cpu_to_le16(offset);
4947 pSMB->Fid = fid;
4948 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4949 pSMB->Reserved4 = 0;
4950 pSMB->hdr.smb_buf_length += byte_count;
4951 pSMB->ByteCount = cpu_to_le16(byte_count);
4952 *data_offset = delete_file ? 1 : 0;
4953 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4954 if (rc)
4955 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4956
4957 return rc;
4958}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959
4960int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004961CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4962 const char *fileName, const FILE_BASIC_INFO *data,
4963 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964{
4965 TRANSACTION2_SPI_REQ *pSMB = NULL;
4966 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4967 int name_len;
4968 int rc = 0;
4969 int bytes_returned = 0;
4970 char *data_offset;
4971 __u16 params, param_offset, offset, byte_count, count;
4972
4973 cFYI(1, ("In SetTimes"));
4974
4975SetTimesRetry:
4976 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4977 (void **) &pSMBr);
4978 if (rc)
4979 return rc;
4980
4981 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4982 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004983 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004984 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 name_len++; /* trailing null */
4986 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004987 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 name_len = strnlen(fileName, PATH_MAX);
4989 name_len++; /* trailing null */
4990 strncpy(pSMB->FileName, fileName, name_len);
4991 }
4992
4993 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004994 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004996 /* BB find max SMB PDU from sess structure BB */
4997 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 pSMB->MaxSetupCount = 0;
4999 pSMB->Reserved = 0;
5000 pSMB->Flags = 0;
5001 pSMB->Timeout = 0;
5002 pSMB->Reserved2 = 0;
5003 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005004 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005 offset = param_offset + params;
5006 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5007 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5008 pSMB->DataOffset = cpu_to_le16(offset);
5009 pSMB->SetupCount = 1;
5010 pSMB->Reserved3 = 0;
5011 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5012 byte_count = 3 /* pad */ + params + count;
5013
5014 pSMB->DataCount = cpu_to_le16(count);
5015 pSMB->ParameterCount = cpu_to_le16(params);
5016 pSMB->TotalDataCount = pSMB->DataCount;
5017 pSMB->TotalParameterCount = pSMB->ParameterCount;
5018 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5019 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5020 else
5021 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5022 pSMB->Reserved4 = 0;
5023 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005024 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 pSMB->ByteCount = cpu_to_le16(byte_count);
5026 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5027 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005028 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030
5031 cifs_buf_release(pSMB);
5032
5033 if (rc == -EAGAIN)
5034 goto SetTimesRetry;
5035
5036 return rc;
5037}
5038
5039/* Can not be used to set time stamps yet (due to old DOS time format) */
5040/* Can be used to set attributes */
5041#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5042 handling it anyway and NT4 was what we thought it would be needed for
5043 Do not delete it until we prove whether needed for Win9x though */
5044int
5045CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5046 __u16 dos_attrs, const struct nls_table *nls_codepage)
5047{
5048 SETATTR_REQ *pSMB = NULL;
5049 SETATTR_RSP *pSMBr = NULL;
5050 int rc = 0;
5051 int bytes_returned;
5052 int name_len;
5053
5054 cFYI(1, ("In SetAttrLegacy"));
5055
5056SetAttrLgcyRetry:
5057 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5058 (void **) &pSMBr);
5059 if (rc)
5060 return rc;
5061
5062 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5063 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005064 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 PATH_MAX, nls_codepage);
5066 name_len++; /* trailing null */
5067 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005068 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 name_len = strnlen(fileName, PATH_MAX);
5070 name_len++; /* trailing null */
5071 strncpy(pSMB->fileName, fileName, name_len);
5072 }
5073 pSMB->attr = cpu_to_le16(dos_attrs);
5074 pSMB->BufferFormat = 0x04;
5075 pSMB->hdr.smb_buf_length += name_len + 1;
5076 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5077 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5078 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005079 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081
5082 cifs_buf_release(pSMB);
5083
5084 if (rc == -EAGAIN)
5085 goto SetAttrLgcyRetry;
5086
5087 return rc;
5088}
5089#endif /* temporarily unneeded SetAttr legacy function */
5090
5091int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005092CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005093 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005094 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095{
5096 TRANSACTION2_SPI_REQ *pSMB = NULL;
5097 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5098 int name_len;
5099 int rc = 0;
5100 int bytes_returned = 0;
5101 FILE_UNIX_BASIC_INFO *data_offset;
5102 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005103 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104
5105 cFYI(1, ("In SetUID/GID/Mode"));
5106setPermsRetry:
5107 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5108 (void **) &pSMBr);
5109 if (rc)
5110 return rc;
5111
5112 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5113 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005114 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005115 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 name_len++; /* trailing null */
5117 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005118 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 name_len = strnlen(fileName, PATH_MAX);
5120 name_len++; /* trailing null */
5121 strncpy(pSMB->FileName, fileName, name_len);
5122 }
5123
5124 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005125 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005127 /* BB find max SMB PDU from sess structure BB */
5128 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 pSMB->MaxSetupCount = 0;
5130 pSMB->Reserved = 0;
5131 pSMB->Flags = 0;
5132 pSMB->Timeout = 0;
5133 pSMB->Reserved2 = 0;
5134 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005135 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 offset = param_offset + params;
5137 data_offset =
5138 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5139 offset);
5140 memset(data_offset, 0, count);
5141 pSMB->DataOffset = cpu_to_le16(offset);
5142 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5143 pSMB->SetupCount = 1;
5144 pSMB->Reserved3 = 0;
5145 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5146 byte_count = 3 /* pad */ + params + count;
5147 pSMB->ParameterCount = cpu_to_le16(params);
5148 pSMB->DataCount = cpu_to_le16(count);
5149 pSMB->TotalParameterCount = pSMB->ParameterCount;
5150 pSMB->TotalDataCount = pSMB->DataCount;
5151 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5152 pSMB->Reserved4 = 0;
5153 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005154 /* Samba server ignores set of file size to zero due to bugs in some
5155 older clients, but we should be precise - we use SetFileSize to
5156 set file size and do not want to truncate file size to zero
5157 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005158 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005159 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5160 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5161 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5162 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5163 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5164 data_offset->Uid = cpu_to_le64(args->uid);
5165 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005167 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5168 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005170
Steve French790fe572007-07-07 19:25:05 +00005171 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005173 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005175 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005177 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005179 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005181 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005183 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5185
5186
5187 pSMB->ByteCount = cpu_to_le16(byte_count);
5188 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5189 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005190 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192
Steve French0d817bc2008-05-22 02:02:03 +00005193 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 if (rc == -EAGAIN)
5195 goto setPermsRetry;
5196 return rc;
5197}
5198
Steve French50c2f752007-07-13 00:33:32 +00005199int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005200 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005201 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005202 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203{
5204 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005205 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5206 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005207 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 int bytes_returned;
5209
Steve French50c2f752007-07-13 00:33:32 +00005210 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005212 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 if (rc)
5214 return rc;
5215
5216 pSMB->TotalParameterCount = 0 ;
5217 pSMB->TotalDataCount = 0;
5218 pSMB->MaxParameterCount = cpu_to_le32(2);
5219 /* BB find exact data count max from sess structure BB */
5220 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005221/* BB VERIFY verify which is correct for above BB */
5222 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5223 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5224
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 pSMB->MaxSetupCount = 4;
5226 pSMB->Reserved = 0;
5227 pSMB->ParameterOffset = 0;
5228 pSMB->DataCount = 0;
5229 pSMB->DataOffset = 0;
5230 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5231 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5232 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005233 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5235 pSMB->Reserved2 = 0;
5236 pSMB->CompletionFilter = cpu_to_le32(filter);
5237 pSMB->Fid = netfid; /* file handle always le */
5238 pSMB->ByteCount = 0;
5239
5240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005241 (struct smb_hdr *)pSMBr, &bytes_returned,
5242 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 if (rc) {
5244 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005245 } else {
5246 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005247 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005248 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005249 sizeof(struct dir_notify_req),
5250 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005251 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005252 dnotify_req->Pid = pSMB->hdr.Pid;
5253 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5254 dnotify_req->Mid = pSMB->hdr.Mid;
5255 dnotify_req->Tid = pSMB->hdr.Tid;
5256 dnotify_req->Uid = pSMB->hdr.Uid;
5257 dnotify_req->netfid = netfid;
5258 dnotify_req->pfile = pfile;
5259 dnotify_req->filter = filter;
5260 dnotify_req->multishot = multishot;
5261 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005262 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005263 &GlobalDnotifyReqList);
5264 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005265 } else
Steve French47c786e2005-10-11 20:03:18 -07005266 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 }
5268 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005269 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270}
5271#ifdef CONFIG_CIFS_XATTR
5272ssize_t
5273CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5274 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005275 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005276 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277{
5278 /* BB assumes one setup word */
5279 TRANSACTION2_QPI_REQ *pSMB = NULL;
5280 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5281 int rc = 0;
5282 int bytes_returned;
5283 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005284 struct fea *temp_fea;
5285 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 __u16 params, byte_count;
5287
5288 cFYI(1, ("In Query All EAs path %s", searchName));
5289QAllEAsRetry:
5290 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5291 (void **) &pSMBr);
5292 if (rc)
5293 return rc;
5294
5295 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5296 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005297 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005298 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 name_len++; /* trailing null */
5300 name_len *= 2;
5301 } else { /* BB improve the check for buffer overruns BB */
5302 name_len = strnlen(searchName, PATH_MAX);
5303 name_len++; /* trailing null */
5304 strncpy(pSMB->FileName, searchName, name_len);
5305 }
5306
Steve French50c2f752007-07-13 00:33:32 +00005307 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 pSMB->TotalDataCount = 0;
5309 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005310 /* BB find exact max SMB PDU from sess structure BB */
5311 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 pSMB->MaxSetupCount = 0;
5313 pSMB->Reserved = 0;
5314 pSMB->Flags = 0;
5315 pSMB->Timeout = 0;
5316 pSMB->Reserved2 = 0;
5317 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005318 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 pSMB->DataCount = 0;
5320 pSMB->DataOffset = 0;
5321 pSMB->SetupCount = 1;
5322 pSMB->Reserved3 = 0;
5323 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5324 byte_count = params + 1 /* pad */ ;
5325 pSMB->TotalParameterCount = cpu_to_le16(params);
5326 pSMB->ParameterCount = pSMB->TotalParameterCount;
5327 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5328 pSMB->Reserved4 = 0;
5329 pSMB->hdr.smb_buf_length += byte_count;
5330 pSMB->ByteCount = cpu_to_le16(byte_count);
5331
5332 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5333 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5334 if (rc) {
5335 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5336 } else { /* decode response */
5337 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5338
5339 /* BB also check enough total bytes returned */
5340 /* BB we need to improve the validity checking
5341 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005342 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 rc = -EIO; /* bad smb */
5344 /* else if (pFindData){
5345 memcpy((char *) pFindData,
5346 (char *) &pSMBr->hdr.Protocol +
5347 data_offset, kl);
5348 }*/ else {
5349 /* check that length of list is not more than bcc */
5350 /* check that each entry does not go beyond length
5351 of list */
5352 /* check that each element of each entry does not
5353 go beyond end of list */
5354 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005355 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 rc = 0;
5357 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005358 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 ea_response_data = (struct fealist *)
5360 (((char *) &pSMBr->hdr.Protocol) +
5361 data_offset);
5362 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005363 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005364 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005366 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 } else {
5368 /* account for ea list len */
5369 name_len -= 4;
5370 temp_fea = ea_response_data->list;
5371 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005372 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 __u16 value_len;
5374 name_len -= 4;
5375 temp_ptr += 4;
5376 rc += temp_fea->name_len;
5377 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005378 rc = rc + 5 + 1;
5379 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005380 memcpy(EAData, "user.", 5);
5381 EAData += 5;
5382 memcpy(EAData, temp_ptr,
5383 temp_fea->name_len);
5384 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 /* null terminate name */
5386 *EAData = 0;
5387 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005388 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 /* skip copy - calc size only */
5390 } else {
5391 /* stop before overrun buffer */
5392 rc = -ERANGE;
5393 break;
5394 }
5395 name_len -= temp_fea->name_len;
5396 temp_ptr += temp_fea->name_len;
5397 /* account for trailing null */
5398 name_len--;
5399 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005400 value_len =
5401 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 name_len -= value_len;
5403 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005404 /* BB check that temp_ptr is still
5405 within the SMB BB*/
5406
5407 /* no trailing null to account for
5408 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 /* go on to next EA */
5410 temp_fea = (struct fea *)temp_ptr;
5411 }
5412 }
5413 }
5414 }
Steve French0d817bc2008-05-22 02:02:03 +00005415 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 if (rc == -EAGAIN)
5417 goto QAllEAsRetry;
5418
5419 return (ssize_t)rc;
5420}
5421
Steve French50c2f752007-07-13 00:33:32 +00005422ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5423 const unsigned char *searchName, const unsigned char *ea_name,
5424 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005425 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426{
5427 TRANSACTION2_QPI_REQ *pSMB = NULL;
5428 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5429 int rc = 0;
5430 int bytes_returned;
5431 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005432 struct fea *temp_fea;
5433 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 __u16 params, byte_count;
5435
5436 cFYI(1, ("In Query EA path %s", searchName));
5437QEARetry:
5438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5439 (void **) &pSMBr);
5440 if (rc)
5441 return rc;
5442
5443 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5444 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005445 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005446 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 name_len++; /* trailing null */
5448 name_len *= 2;
5449 } else { /* BB improve the check for buffer overruns BB */
5450 name_len = strnlen(searchName, PATH_MAX);
5451 name_len++; /* trailing null */
5452 strncpy(pSMB->FileName, searchName, name_len);
5453 }
5454
Steve French50c2f752007-07-13 00:33:32 +00005455 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 pSMB->TotalDataCount = 0;
5457 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005458 /* BB find exact max SMB PDU from sess structure BB */
5459 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 pSMB->MaxSetupCount = 0;
5461 pSMB->Reserved = 0;
5462 pSMB->Flags = 0;
5463 pSMB->Timeout = 0;
5464 pSMB->Reserved2 = 0;
5465 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005466 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 pSMB->DataCount = 0;
5468 pSMB->DataOffset = 0;
5469 pSMB->SetupCount = 1;
5470 pSMB->Reserved3 = 0;
5471 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5472 byte_count = params + 1 /* pad */ ;
5473 pSMB->TotalParameterCount = cpu_to_le16(params);
5474 pSMB->ParameterCount = pSMB->TotalParameterCount;
5475 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5476 pSMB->Reserved4 = 0;
5477 pSMB->hdr.smb_buf_length += byte_count;
5478 pSMB->ByteCount = cpu_to_le16(byte_count);
5479
5480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5482 if (rc) {
5483 cFYI(1, ("Send error in Query EA = %d", rc));
5484 } else { /* decode response */
5485 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5486
5487 /* BB also check enough total bytes returned */
5488 /* BB we need to improve the validity checking
5489 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005490 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 rc = -EIO; /* bad smb */
5492 /* else if (pFindData){
5493 memcpy((char *) pFindData,
5494 (char *) &pSMBr->hdr.Protocol +
5495 data_offset, kl);
5496 }*/ else {
5497 /* check that length of list is not more than bcc */
5498 /* check that each entry does not go beyond length
5499 of list */
5500 /* check that each element of each entry does not
5501 go beyond end of list */
5502 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005503 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 rc = -ENODATA;
5505 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005506 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 ea_response_data = (struct fealist *)
5508 (((char *) &pSMBr->hdr.Protocol) +
5509 data_offset);
5510 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005511 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005512 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005514 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 } else {
5516 /* account for ea list len */
5517 name_len -= 4;
5518 temp_fea = ea_response_data->list;
5519 temp_ptr = (char *)temp_fea;
5520 /* loop through checking if we have a matching
5521 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005522 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 __u16 value_len;
5524 name_len -= 4;
5525 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005526 value_len =
5527 le16_to_cpu(temp_fea->value_len);
5528 /* BB validate that value_len falls within SMB,
5529 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005530 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 temp_fea->name_len) == 0) {
5532 /* found a match */
5533 rc = value_len;
5534 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005535 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 memcpy(ea_value,
5537 temp_fea->name+temp_fea->name_len+1,
5538 rc);
Steve French50c2f752007-07-13 00:33:32 +00005539 /* ea values, unlike ea
5540 names, are not null
5541 terminated */
Steve French790fe572007-07-07 19:25:05 +00005542 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 /* skip copy - calc size only */
5544 } else {
Steve French50c2f752007-07-13 00:33:32 +00005545 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 rc = -ERANGE;
5547 }
5548 break;
5549 }
5550 name_len -= temp_fea->name_len;
5551 temp_ptr += temp_fea->name_len;
5552 /* account for trailing null */
5553 name_len--;
5554 temp_ptr++;
5555 name_len -= value_len;
5556 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005557 /* No trailing null to account for in
5558 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 temp_fea = (struct fea *)temp_ptr;
5560 }
Steve French50c2f752007-07-13 00:33:32 +00005561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 }
5563 }
Steve French0d817bc2008-05-22 02:02:03 +00005564 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 if (rc == -EAGAIN)
5566 goto QEARetry;
5567
5568 return (ssize_t)rc;
5569}
5570
5571int
5572CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005573 const char *ea_name, const void *ea_value,
5574 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5575 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576{
5577 struct smb_com_transaction2_spi_req *pSMB = NULL;
5578 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5579 struct fealist *parm_data;
5580 int name_len;
5581 int rc = 0;
5582 int bytes_returned = 0;
5583 __u16 params, param_offset, byte_count, offset, count;
5584
5585 cFYI(1, ("In SetEA"));
5586SetEARetry:
5587 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5588 (void **) &pSMBr);
5589 if (rc)
5590 return rc;
5591
5592 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5593 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005594 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005595 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 name_len++; /* trailing null */
5597 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005598 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 name_len = strnlen(fileName, PATH_MAX);
5600 name_len++; /* trailing null */
5601 strncpy(pSMB->FileName, fileName, name_len);
5602 }
5603
5604 params = 6 + name_len;
5605
5606 /* done calculating parms using name_len of file name,
5607 now use name_len to calculate length of ea name
5608 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005609 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 name_len = 0;
5611 else
Steve French50c2f752007-07-13 00:33:32 +00005612 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00005614 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005616 /* BB find max SMB PDU from sess */
5617 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 pSMB->MaxSetupCount = 0;
5619 pSMB->Reserved = 0;
5620 pSMB->Flags = 0;
5621 pSMB->Timeout = 0;
5622 pSMB->Reserved2 = 0;
5623 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005624 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 offset = param_offset + params;
5626 pSMB->InformationLevel =
5627 cpu_to_le16(SMB_SET_FILE_EA);
5628
5629 parm_data =
5630 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5631 offset);
5632 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5633 pSMB->DataOffset = cpu_to_le16(offset);
5634 pSMB->SetupCount = 1;
5635 pSMB->Reserved3 = 0;
5636 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5637 byte_count = 3 /* pad */ + params + count;
5638 pSMB->DataCount = cpu_to_le16(count);
5639 parm_data->list_len = cpu_to_le32(count);
5640 parm_data->list[0].EA_flags = 0;
5641 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005642 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005644 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005645 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 parm_data->list[0].name[name_len] = 0;
5647 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5648 /* caller ensures that ea_value_len is less than 64K but
5649 we need to ensure that it fits within the smb */
5650
Steve French50c2f752007-07-13 00:33:32 +00005651 /*BB add length check to see if it would fit in
5652 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005653 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5654 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005655 memcpy(parm_data->list[0].name+name_len+1,
5656 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657
5658 pSMB->TotalDataCount = pSMB->DataCount;
5659 pSMB->ParameterCount = cpu_to_le16(params);
5660 pSMB->TotalParameterCount = pSMB->ParameterCount;
5661 pSMB->Reserved4 = 0;
5662 pSMB->hdr.smb_buf_length += byte_count;
5663 pSMB->ByteCount = cpu_to_le16(byte_count);
5664 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5665 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005666 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668
5669 cifs_buf_release(pSMB);
5670
5671 if (rc == -EAGAIN)
5672 goto SetEARetry;
5673
5674 return rc;
5675}
5676
5677#endif